循环对我们来说是自然而然的,我们在几乎所有的编程语言中都会学习循环。所以,默认情况下,我们在遇到重复操作时就开始实现循环。但是,当我们处理大量的迭代(百万/十亿行)时,使用循环就成了一个罪行。你可能会陷入数小时的困境,后来才意识到它不会工作。这就是在Python中实现向量化变得非常重要的地方。

什么是向量化?

向量化是在数据集上实现(NumPy)数组操作的技术。在后台,它一次性对数组或系列的所有元素应用操作(与‘for’循环不同,‘for’循环一次处理一行)。

在这篇博客中,我们将查看一些可以轻松用向量化替换Python循环的用例。这将帮助你节省时间,提高编码技巧。

用例1:求和 首先,我们将查看一个基本的示例,了解如何使用循环和Python中的向量化求和。

使用循环:

import time
start = time.time()

# 迭代求和
total = 0
# 迭代150万个数字
for item in range(0, 1500000):
    total = total + item

print('sum is:' + str(total))
end = time.time()

print(end - start)

#1124999250000
#0.14 秒

使用向量化:

import numpy as np

start = time.time()

# 向量化求和 - 使用numpy进行向量化
# np.arange 创建从0到1499999的数字序列
print(np.sum(np.arange(1500000)))

end = time.time()

print(end - start)

##1124999250000
##0.008 秒

向量化的执行时间比使用range函数的迭代少了大约18倍。在使用Pandas DataFrame时,这种差异将变得更为明显。

用例2:对DataFrame执行数学运算
在数据科学中,开发人员在使用Pandas DataFrame时,常常使用循环来通过数学运算创建新的派生列。

在以下示例中,我们可以看到如何轻松地用向量化替换循环来实现这些用例。

创建DataFrame:

DataFrame是以行和列形式呈现的表格数据。

我们将创建一个包含500万行和4列的pandas DataFrame,其中填充了0到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()

我们将创建一个新列‘ratio’,以找到列‘d’和‘c’的比率。

使用循环:

import time 
start = time.time()

# 使用iterrows遍历DataFrame
for idx, row in df.iterrows():
    # 创建一个新列
    df.at[idx,'ratio'] = 100 * (row["d"] / row["c"])  
end = time.time()
print(end - start)
### 109 秒

使用向量化:

start = time.time()
df["ratio"] = 100 * (df["d"] / df["c"])

end = time.time()
print(end - start)
### 0.12 秒

我们可以看到DataFrame的显著改进,向量化操作的时间几乎比Python中的循环快了1000倍。

用例3:对DataFrame执行if-else语句
我们实现了很多需要使用‘If-else’逻辑的操作。我们可以轻松地用Python中的向量化操作替换这些逻辑。

让我们通过以下示例更好地理解它(我们将使用在用例2中创建的DataFrame):

假设我们想基于列‘a’上的一些条件创建一个新列‘e’。

使用循环:

import time 
start = time.time()

# 使用iterrows遍历DataFrame
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)
### 时间:177 秒

使用向量化:

# 使用向量化

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 秒

向量化操作的时间比Python中带有if-else语句的循环快了600倍。

用例4(高级):解决机器学习/深度学习网络
深度学习需要我们解决多个复杂的方程,而且是对数百万和数十亿行。在Python中运行循环以解决这些方程非常慢,向量化是最佳解决方案。

例如,为了计算上述多元线性回归方程中y的值,我们可以用向量化替换循环,该方程有数百万行。

创建数据:

import numpy as np
# 设置m的初始值
m = np.random.rand(1,5)

# 为500万行输入值
x = np.random.rand(5000000,5)

使用循环:

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]

toc = time.process_time()
print ("Computation time = " + str((toc - tic)) + "seconds")

####计算时间 = 28.228 秒

使用向量化:

tic = time.process_time()

# 点积
np.dot(x,m.T) 

toc = time.process_time()
print ("Computation time = " + str((toc - tic)) + "seconds")

####计算时间 = 0.107 秒

np.dot在后台实现了向量化的矩阵乘法。它比Python中的循环快了165倍。