Sử dụng Vectorization - Một sự thay thế siêu nhanh cho các vòng lặp trong Python
Giới thiệu
Loops đến với chúng ta một cách tự nhiên, chúng ta tìm hiểu về Loops trong hầu hết các ngôn ngữ lập trình. Vì vậy, theo mặc định, chúng tôi bắt đầu thực hiện các vòng lặp bất cứ khi nào có một hoạt động lặp đi lặp lại. Nhưng khi chúng ta làm việc với một số lượng lớn các lần lặp lại (hàng triệu/ hàng tỷ hàng), sử dụng các vòng lặp là một tội ác. Bạn có thể bị mắc kẹt trong nhiều giờ, để sau đó nhận ra rằng nó sẽ không hoạt động. Đây là nơi mà việc triển khai Vectorisation trong python trở nên siêu quan trọng.
Vectorization là gì?
Vectorization là kỹ thuật thực hiện các phép toán mảng (NumPy) trên tập dữ liệu. Trong nền, nó áp dụng các phép toán cho tất cả các phần tử của một mảng hoặc chuỗi trong một lần (không giống như vòng lặp 'for' thao tác một hàng tại một thời điểm).
Trong bài viết này, chúng ta sẽ xem xét một số trường hợp sử dụng mà chúng ta có thể dễ dàng thay thế các vòng lặp python bằng Vectorization. Điều này sẽ giúp bạn tiết kiệm thời gian và trở nên 'pro' hơn trong coding.
Vấn đề 1: Tìm tổng số số
Đầu tiên, chúng ta sẽ xem xét một ví dụ cơ bản về việc tìm tổng các số bằng cách sử dụng các vòng lặp và Vectorization trong python.
Dùng vòng lặp
import time start = time.time() # iterative sum
total = 0
# iterating through 1.5 Million numbers
for item in range(0, 1500000): total = total + item print('sum is:' + str(total))
end = time.time() print(end - start) #1124999250000
#0.14 Seconds
Dùng Vectorization
import numpy as np start = time.time() # vectorized sum - using numpy for vectorization
# np.arange create the sequence of numbers from 0 to 1499999
print(np.sum(np.arange(1500000))) end = time.time()
print(end - start) ##1124999250000
##0.008 Seconds
Vectorization mất ít thời gian hơn ~ 18 lần để thực hiện so với lần lặp lại bằng cách sử dụng hàm phạm vi. Sự khác biệt này sẽ trở nên đáng kể hơn khi làm việc với Pandas DataFrame.
Vấn đề 2: Hoạt động tính toán (trên DataFrame)
trong khi làm việc với Pandas DataFrame, các nhà phát triển sử dụng các vòng lặp để tạo các cột dẫn xuất mới bằng cách sử dụng các phép toán. Trong ví dụ sau, chúng ta có thể thấy các vòng lặp có thể được thay thế dễ dàng như thế nào bằng Vectorization cho các trường hợp sử dụng như vậy.
Tạo DataFrame
DataFrame là dữ liệu dạng bảng dưới dạng hàng và cột. Chúng ta sẽ tạo một pandas DataFrame có 5 triệu hàng và 4 cột chứa đầy các giá trị ngẫu nhiên từ 0 đến 50.
import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.randint(0, 50, size=(5000000, 4)), columns=('a','b','c','d'))
df.shape
# (5000000, 5)
df.head()
Chúng ta sẽ tạo một cột mới 'tỷ lệ' để tìm tỷ lệ của cột 'd' và 'c'.
Dùng vòng lặp
import time start = time.time() # Iterating through DataFrame using iterrows
for idx, row in df.iterrows(): # creating a new column df.at[idx,'ratio'] = 100 * (row["d"] / row["c"]) end = time.time()
print(end - start)
### 109 Seconds
Dùng Vectorization
start = time.time()
df["ratio"] = 100 * (df["d"] / df["c"]) end = time.time()
print(end - start)
### 0.12 seconds
Chúng ta có thể thấy một sự cải thiện đáng kể với DataFrame, thời gian được thực hiện bởi hoạt động vectơ hóa nhanh hơn gần 1000 lần so với các vòng lặp trong Python.
Vấn đề 3: Các câu lệnh IF-Else (trên DataFrame)
Chúng ta thực hiện rất nhiều hoạt động yêu cầu sử dụng loại logic ‘if-else '. Chúng ta có thể dễ dàng thay thế các logic này bằng các hoạt động vector hóa trong Python. Chúng ta hãy xem xét ví dụ sau để hiểu nó tốt hơn (chúng ta sẽ sử dụng DataFrame mà chúng ta đã tạo trong vấn đề 2): Hãy tưởng tượng chúng ta muốn tạo một cột mới ‘e 'dựa trên một số điều kiện trên cột cũ 'a'. Dùng vòng lặp
import time start = time.time() # Iterating through DataFrame using iterrows
for idx, row in df.iterrows(): if row.a == 0: df.at[idx,'e'] = row.d elif (row.a <= 25) & (row.a > 0): df.at[idx,'e'] = (row.b)-(row.c) else: df.at[idx,'e'] = row.b + row.c end = time.time() print(end - start)
### Time taken: 177 seconds
Dùng Vectorization
start = time.time()
df['e'] = df['b'] + df['c']
df.loc[df['a'] <= 25, 'e'] = df['b'] -df['c']
df.loc[df['a']==0, 'e'] = df['d']end = time.time()
print(end - start)
## 0.28007707595825195 sec
Thời gian thực hiện bởi phép toán Vectorization nhanh hơn 600 lần so với các vòng lặp python với các câu lệnh if-else.
Vân đề 4 (nâng cao): Dùng trong Machine Learning/Deep Learning Networks
Deep Learning đòi hỏi chúng ta phải giải nhiều phương trình phức tạp và điều đó cũng cho hàng triệu, hàng tỷ hàng. Chạy các vòng lặp trong Python để giải các phương trình này rất chậm và Vectorization là giải pháp tối ưu.
Ví dụ: để tính giá trị của y cho hàng triệu hàng trong phương trình hồi quy đa tuyến tính sau đây:
chúng ta có thể thay thế các vòng lặp bằng Vectorization. Các giá trị của m1, m2, m3... được xác định bằng cách giải phương trình trên bằng cách sử dụng hàng triệu giá trị tương ứng với x1,x2,x3... (để đơn giản, chúng ta sẽ chỉ xem xét một bước nhân đơn giản)
Tạo data
import numpy as np
# setting initial values of m
m = np.random.rand(1,5) # input values for 5 million rows
x = np.random.rand(5000000,5)
Dùng vòng lặp
import numpy as np
m = np.random.rand(1,5)
x = np.random.rand(5000000,5) total = 0
tic = time.process_time() for i in range(0,5000000): total = 0 for j in range(0,5): total = total + x[i][j]*m[0][j] zer[i] = total toc = time.process_time()
print ("Computation time = " + str((toc - tic)) + "seconds") ####Computation time = 28.228 seconds
Dùng Vectorization
tic = time.process_time() #dot product
np.dot(x,m.T) toc = time.process_time()
print ("Computation time = " + str((toc - tic)) + "seconds") ####Computation time = 0.107 seconds
np.dot thực hiện phép nhân ma trận Vectorized trong phần phụ trợ. Nó nhanh hơn 165 lần so với các vòng lặp trong python.
Kết luận
Vectorization trong Python là siêu nhanh và nên được ưu tiên hơn các vòng lặp, bất cứ khi nào chúng tôi làm việc với các bộ dữ liệu rất lớn. Bắt đầu thực hiện nó theo thời gian và bạn sẽ trở nên thoải mái với suy nghĩ dọc theo dòng với code của bạn.
Kham khảo
https://medium.com/codex/say-goodbye-to-loops-in-python-and-welcome-vectorization-e4df66615a52
https://towardsdatascience.com/how-to-speedup-data-processing-with-numpy-vectorization-12acac71cfca