c

codeye

V1

2022/10/28阅读:31主题:默认主题

不要在Python中使用iterrows()循环

不要在Python中使用iterrows()循环,而是使用这些!

知道如何以31倍的速度迭代pandas DataFrame

你想在Python中快速运行31倍的循环吗?

简介:循环对我们来说是非常自然的。当我们学习任何编程语言时,循环都是重要概念的一个组成部分,而且循环也很容易解释。因此,在Python中,每当我们必须对数据集的行进行迭代时,凭直觉,我们就开始考虑实现循环。

但是,当数据集太大的时候,循环需要花费大量的时间来遍历DataFrame。那么,我们是完全不使用循环呢,还是可以通过一些小技巧来克服这一挑战呢?

幸运的是,有一些小窍门

在这篇博客中,我们将使用pandas中不同的循环方法来研究在一个大的pandas DataFrame中迭代的不同方式(以及相关的运行时间)。在这篇博客结束时,你会知道哪种循环技术对较大的数据集最有效。

创建我们的数据集

我们将使用一个DataFrame df有500万行和4列。每一列都被分配一个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()

有500万行和4列的数据框架

选项1:迭行

想象一下,我们想在数据框架df中添加一列'e',基于以下条件。

如果'a'等于0,那么'e'就等于'd'的值。

如果'a'小于或等于25且大于0,那么'e'等于'b'-'c'。

如果不满足上述条件,那么'e'就等于'b'+'c'。

为了实现上述条件,我们将使用pandas iterrows()函数来迭代数据框架df的行。

Iterrows()函数以(index, Series)对的形式遍历数据框架的行。

import time 
start = time.time()
# Iterating through DataFrame using iterro
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: 666 seconds 

所花费的时间666秒

iterrows()函数需要666秒(约11分钟)来实现对500万行的操作。

选项2:迭代数

Itertuples是另一种在pandas DataFrame中迭代的方法。它将DataFrame的行作为命名的图元进行迭代。

下面的代码显示了如何使用itertuples访问元素。该行对象有第一个字段作为索引,以下字段作为列。

for row in df[:1].itertuples():
    print(row)
    print(row.Index)
    print(row.a)

输出 使用下面的代码,我们可以在我们的DataFrame df上应用这个操作。

start = time.time()
# Iterating through namedtuples
for row in df.itertuples():
    if row.a == 0:
        df.at[row.Index,'e'] = row.d
    
    elif (row.a <= 25) & (row.a > 0):
        df.at[row.Index,'e'] = (row.b)-(row.c)
    else:
        df.at[row.Index,'e'] = row.b + row.c 
        
end = time.time()
print(end - start)
## Time taken: 81 seconds 

花费的时间:81秒 ** itertuples()函数在DataFrame上执行所需的操作需要~81秒,比iterrows()函数快8倍**。

选项3:字典

我们也可以通过将 DataFrame 转换为 dictionary(它是一个轻量级的内置数据类型)来迭代 DataFrame 的行,通过 dictionary 迭代来执行操作,然后将更新的 dictionary 转换回 DataFrame。

我们可以使用'to_dict()'函数将 DataFrame 转换为 dictionary


start = time.time()
# converting the DataFrame to a dictionary
df_dict = df.to_dict('records')  
# Iterating through the dictionary 
for row in df_dict[:]:
    if row['a'] == 0:
        row['e'] = row['d']
    
    elif row['a'] <= 25 & row['a'] > 0:
        row['e'] = row['b']-row['c']
    else:
        row['e'] = row['b'] + row['c']
# converting back to DataFrame
df4 = pd.DataFrame(df_dict)
end = time.time()
print(end - start)
## Time taken: 25 seconds

花费的时间:25秒

dictionary方法花费了~25秒,比itertuples()函数花费的时间快了~3倍。

选项4:数组/列表

这个方法类似于字典方法,我们将把DataFrame转换为数组,在数组中迭代操作每一行(保存在一个列表中),然后将列表转换为DataFrame。

start = time.time()
# 创建一个空的字典

list2 = []
# 初始化有0的列。
df['e'] = 0

# 遍历一个NumPy数组 
for row in df.values:
    if row[0] == 0:
        row[4] = row[3]
    
    elif row[0] <= 25 & row[0] > 0:
        row[4] = row[1]-row[2]
   
    else:
        row[4] = row[1] + row[2]
#将数值追加到一个列表中
    list2.append(row)
#将列表转换为一个数据框架 
df2 = pd.DataFrame(list2, columns=['a''b''c''d','e'])
end = time.time()
print(end - start)
#Time Taken: 21 seconds

所花费的时间:21秒

这个方法所花费的时间是~21秒(比iterrows快31倍),这与在字典中迭代所花费的时间非常接近。

执行时间的比较

字典和数组是内置的轻型数据结构,因此在DataFrame中迭代花费的时间最少。

每当处理大型数据集时,最好的做法是将你的python代码矢量化。它将以闪电般的速度运行。对上述代码进行矢量化后,执行时间减少到0.29秒(比在数组中迭代快72倍)。我们将在接下来的文章中学习矢量化的知识。

总结 我们看了使用循环遍历DataFrame的4种不同方式。

Iterrows函数花费了最大的时间来迭代DataFrame。 使用itertuples函数,我们可以以8倍于iterrows函数的速度遍历DataFrame。 遍历Dictionary和Array需要的时间最少,是使用循环来操作数据的最佳方法。

分类:

后端

标签:

后端

作者介绍

c
codeye
V1