我有一个熊猫数据帧,df:
c1 c2
0 10 100
1 11 110
2 12 120
如何迭代此数据帧的行?对于每一行,我希望能够通过列的名称访问其元素(单元格中的值)。例如:
for row in df.rows:
print(row['c1'], row['c2'])
我发现了一个类似的问题,建议使用以下任一项:
for date, row in df.T.iteritems():
for row in df.iterrows():
但我不知道row对象是什么,以及如何使用它。
您还可以进行NumPy索引,以实现更高的速度。它不是真正的迭代,但对某些应用程序来说,它比迭代好得多。
subset = row['c1'][0:5]
all = row['c1'][:]
您可能还希望将其强制转换为数组。这些索引/选择本来应该像NumPy数组一样,但我遇到了一些问题,需要转换
np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) # Resize every image in an hdf5 file
免责声明:尽管这里有很多答案建议不要使用迭代(循环)方法(我基本同意),但我仍然认为这是一种适用于以下情况的合理方法:
使用API中的数据扩展数据帧
假设您有一个包含不完整用户数据的大型数据帧。现在,您必须使用其他列来扩展此数据,例如,用户的年龄和性别。
这两个值都必须从后端API获取。我假设API不提供“批处理”端点(一次接受多个用户ID)。否则,您应该只调用一次API。
网络请求的成本(等待时间)远远超过了数据帧的迭代。我们讨论的是数百毫秒的网络往返时间,相比之下,使用迭代的替代方法可以忽略不计的小增益。
每行一个昂贵的网络请求
所以在这种情况下,我绝对倾向于使用迭代方法。尽管网络请求很昂贵,但可以保证对数据帧中的每一行只触发一次。以下是使用DataFrame.iterrows的示例:
实例
for index, row in users_df.iterrows():
user_id = row['user_id']
# Trigger expensive network request once for each row
response_dict = backend_api.get(f'/api/user-data/{user_id}')
# Extend dataframe with multiple data from response
users_df.at[index, 'age'] = response_dict.get('age')
users_df.at[index, 'gender'] = response_dict.get('gender')
除了这篇文章中的好答案,我将提出“分而治之”的方法,我写这个答案并不是为了废除其他好答案,而是为了用另一种对我有效的方法来实现它们。它有两个步骤,即拆分和合并熊猫数据帧:
分裂与征服的证明:
您不需要使用矢量化或任何其他方法将数据帧的类型转换为另一种类型您不需要将代码循环化,这通常需要额外的时间在我的例子中,iterrows()和itertples()在整个数据帧上都具有相同的性能根据您对切片索引的选择,您将能够以指数方式加快迭代。索引越高,迭代过程越快。
分裂与征服的缺点:
您不应该依赖于同一数据帧和不同切片的迭代过程。这意味着,如果你想从其他切片读取或写入,那么可能很难做到这一点。
===============分而治之=================
步骤1:分割/切片
在这一步中,我们将在整个数据帧上划分迭代。假设你要将一个CSV文件读入panda df,然后对其进行迭代。在这种情况下,我有5000000条记录,我要将其拆分为100000条记录。
注意:我需要重申,正如本页其他解决方案中解释的其他运行时分析一样,在df上搜索时,“记录数”与“运行时”成指数比例。基于我的数据基准,以下是结果:
Number of records | Iteration rate [per second]
========================================
100,000 | 500
500,000 | 200
1,000,000 | 50
5,000,000 | 20
第2步:合并
这将是一个简单的步骤,只需将所有写入的CSV文件合并到一个数据帧中,然后将其写入一个更大的CSV文件。
以下是示例代码:
# Step 1 (Splitting/Slicing)
import pandas as pd
df_all = pd.read_csv('C:/KtV.csv')
df_index = 100000
df_len = len(df)
for i in range(df_len // df_index + 1):
lower_bound = i * df_index
higher_bound = min(lower_bound + df_index, df_len)
# Splitting/slicing df (make sure to copy() otherwise it will be a view
df = df_all[lower_bound:higher_bound].copy()
'''
Write your iteration over the sliced df here
using iterrows() or intertuples() or ...
'''
# Writing into CSV files
df.to_csv('C:/KtV_prep_' + str(i) + '.csv')
# Step 2 (Merging)
filename = 'C:/KtV_prep_'
df = (pd.read_csv(f) for f in [filename + str(i) + '.csv' for i in range(ktv_len // ktv_index + 1)])
df_prep_all = pd.concat(df)
df_prep_all.to_csv('C:/KtV_prep_all.csv')
参考:
数据流迭代的有效方法
将CSV文件连接到一个Pandas数据帧中
更新:cs95更新了他的答案,包括简单的numpy矢量化。你可以简单地参考他的答案。
cs95表明,Pandas矢量化在使用数据帧计算数据方面远远优于其他Pandas方法。
我想补充一点,如果您首先将数据帧转换为NumPy数组,然后使用矢量化,它甚至比Pandas数据帧矢量化更快(这包括将其转换回数据帧序列的时间)。
如果您将以下函数添加到cs95的基准代码中,这将变得非常明显:
def np_vectorization(df):
np_arr = df.to_numpy()
return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)
def just_np_vectorization(df):
np_arr = df.to_numpy()
return np_arr[:,0] + np_arr[:,1]