說(shuō)再見(jiàn)Python循環(huán),“向量化”讓我們代碼更高效
介紹
循環(huán)在我們身邊自然而然地出現(xiàn),我們幾乎在所有編程語(yǔ)言中都學(xué)過(guò)循環(huán)。因此,默認(rèn)情況下,每當(dāng)有重復(fù)操作時(shí),我們就開(kāi)始實(shí)現(xiàn)循環(huán)。但是當(dāng)我們處理大量迭代(數(shù)百萬(wàn)/數(shù)十億行)時(shí),使用循環(huán)就是一種罪行。我們可能會(huì)卡住好幾個(gè)小時(shí),最后意識(shí)到它行不通。這就是在Python中實(shí)現(xiàn)向量化變得非常關(guān)鍵的地方。
什么是向量化?
向量化是在數(shù)據(jù)集上實(shí)現(xiàn)(NumPy)數(shù)組操作的技術(shù)。在后臺(tái),它將操作應(yīng)用于數(shù)組或系列的所有元素,一次性完成(不像“for”循環(huán)一次操作一行)。在這篇文章中中,我們可以輕松地用向量化替代Python循環(huán)。這將幫助我們節(jié)省時(shí)間,并在編碼方面變得更加熟練。
用例1:找到數(shù)字的和
首先,我們將看一個(gè)使用循環(huán)和Python中的向量化找到數(shù)字和的基本示例。
使用循環(huán) :
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
使用向量化:
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
相比于使用range函數(shù)進(jìn)行迭代,向量化執(zhí)行時(shí)間約為循環(huán)的18倍。在使用Pandas DataFrame時(shí),這種差異將變得更為顯著。
用例2:數(shù)學(xué)運(yùn)算(在DataFrame上)
在數(shù)據(jù)科學(xué)中,開(kāi)發(fā)人員在使用Pandas DataFrame時(shí),使用循環(huán)進(jìn)行數(shù)學(xué)運(yùn)算以創(chuàng)建新的派生列。在以下示例中,我們可以看到如何輕松地將循環(huán)替換為這種情況下的向量化。
創(chuàng)建DataFrame:
DataFrame是以行和列形式的表格數(shù)據(jù)。我們創(chuàng)建一個(gè)具有500萬(wàn)行和4列,填充了0到50之間的隨機(jī)值的Pandas DataFrame。
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()
前5行
我們將創(chuàng)建一個(gè)新列'ratio',以找到列'd'和'c'的比率。
使用循環(huán):
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
使用向量化:
start = time.time()
df["ratio"] = 100 * (df["d"] / df["c"])
end = time.time()
print(end - start)
### 0.12 seconds
我們可以看到,在DataFrame中,與Python中的循環(huán)相比,向量化操作所需的時(shí)間幾乎快1000倍。
用例3:if-else語(yǔ)句(在DataFrame上)
我們實(shí)現(xiàn)了許多需要使用“If-else”類(lèi)型邏輯的操作。我們可以輕松地用Python中的向量化操作替換這些邏輯。讓我們看下面的例子以更好地理解它(我們將使用在用例2中創(chuàng)建的DataFrame):
假設(shè)我們想基于對(duì)現(xiàn)有列‘a(chǎn)’的某些條件創(chuàng)建一個(gè)新列‘e’。
使用循環(huán):
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
使用向量化:
# using 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
向量化操作所需的時(shí)間比帶有if-else語(yǔ)句的Python循環(huán)快600倍。
用例4(高級(jí)):解決機(jī)器學(xué)習(xí)/深度學(xué)習(xí)網(wǎng)絡(luò)
深度學(xué)習(xí)要求我們解決多個(gè)復(fù)雜的方程,而且還要為數(shù)百萬(wàn)甚至數(shù)十億行運(yùn)行。在Python中運(yùn)行循環(huán)來(lái)解決這些方程非常慢,而向量化是最優(yōu)解。例如,為了計(jì)算多元線性回歸方程中數(shù)百萬(wàn)行的y值:
多元線性回歸
我們可以用向量化替換循環(huán)。m1,m2,m3...的值是通過(guò)使用與x1,x2,x3...相對(duì)應(yīng)的數(shù)百萬(wàn)個(gè)值解上述方程得出的(為簡(jiǎn)單起見(jiàn),我們只看一個(gè)簡(jiǎn)單的乘法步驟)
創(chuàng)建數(shù)據(jù):
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)
m的輸出
x的輸出
使用循環(huán):
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
使用向量化:
兩個(gè)矩陣的點(diǎn)積
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在后臺(tái)實(shí)現(xiàn)了向量化矩陣乘法。與Python中的循環(huán)相比,它快165倍。
結(jié)論
在Python中,向量化非??欤瑧?yīng)該優(yōu)先使用,特別是在處理非常大的數(shù)據(jù)集時(shí)。
隨著時(shí)間的推移開(kāi)始實(shí)施它,我們將逐漸習(xí)慣以向量化代碼的方式思考。