更快的 For 循环在 Pandas 中处理数据
Posted
技术标签:
【中文标题】更快的 For 循环在 Pandas 中处理数据【英文标题】:Faster For Loop to Manipulate Data in Pandas 【发布时间】:2017-01-19 23:55:03 【问题描述】:我正在使用形状为 ~(100000, 50)
的 pandas 数据框,虽然我可以实现所需的数据格式和操作,但我发现我的代码运行时间比预期的要长(3-10 分钟),具体取决于具体任务,包括:
-
组合不同列中的字符串
将函数应用于数据框系列中的每个实例
检查值是否包含在单独的列表或 numpy 数组中
我将来会有更大的数据帧,并希望确保我使用适当的编码方法来避免很长的处理时间。我发现我的 for
循环耗时最长。我尽量避免使用列表推导和系列运算符(例如df.loc[:,'C'] = df.A + df.B
)的for
循环,但在某些情况下,我需要使用嵌套的for
循环执行更复杂/涉及的操作。例如,下面遍历数据框的系列history
(一系列列表),然后遍历每个list
中的每个项目:
for row in DF.iterrows():
removelist = []
for i in xrange(0, len(row[1]['history'])-1):
if ((row[1]['history'][i]['title'] == row[1]['history'][i+1]['title']) &
(row[1]['history'][i]['dept'] == row[1]['history'][i+1]['dept']) &
(row[1]['history'][i]['office'] == row[1]['history'][i+1]['office']) &
(row[1]['history'][i]['employment'] == row[1]['history'][i+1]['employment'])):
removelist.append(i)
newlist = [v for i, v in enumerate(row[1]['history']) if i not in removelist]
我知道列表推导可以容纳嵌套的 for
循环,但上面的内容在列表推导中看起来确实很麻烦。
我的问题:我可以使用哪些其他技术来实现与 for
循环相同的功能,并且处理时间更短?在遍历包含列表的系列时,我应该使用嵌套 for
循环以外的其他技术吗?
【问题讨论】:
【参考方案1】:那么您在这里似乎有一个数据框,其中每行的历史条目都包含一个字典列表?喜欢:
import pandas as pd
john_history = ['title': 'a', 'dept': 'cs', 'title': 'cj', 'dept': 'sales']
john_history
jill_history = ['title': 'boss', 'dept': 'cs', 'title': 'boss', 'dept': 'cs', 'title': 'junior', 'dept': 'cs']
jill_history
df = pd.DataFrame('history': [john_history, jill_history],
'firstname': ['john', 'jill'])
我会重组您的数据,以便您在结构的底层使用 pandas 结构,例如DataFrames 的字典,其中每个 DataFrame 都是历史记录(我不认为 Panel 在这里工作,因为 DataFrames 可能有不同的长度):
john_history = pd.DataFrame('title': ['a', 'cj'], 'dept': ['cs', 'sales'])
john_history['name'] = 'john'
jill_history = pd.DataFrame('title': ['boss', 'boss', 'junior'], 'dept': ['cs', 'cs', 'cs'])
jill_history['name'] = 'jill'
people = pd.concat([john_history, jill_history])
然后您可以使用 groupby 处理它们,例如:
people.groupby('name').apply(pd.DataFrame.drop_duplicates)
一般来说,如果您在 pandas/numpy 中找不到您想要的功能,您应该会发现使用 pandas 原语创建它而不是迭代数据帧会更快。例如,要重新创建上面的逻辑,首先创建一个新的数据框,它是第一个移动的数据框:
df2 = df.shift()
现在您可以通过比较数据框的内容来创建选择,只保留不同的内容并使用它来过滤数据框:
selection_array = (df.history == df2.history) & (df.title == df2.title)
unduplicated_consecutive = df[~selection_array]
print(unduplicated_consecutive)
history id title
0 a 1 x
1 b 2 y
# or in one line:
df[~((df.history == df2.history) & (df.title == df2.title))]
# or:
df[(df.history != df2.history) | (df.title != df2.title)]
所以把这个放到groupby中:
def drop_consecutive_duplicates(df):
df2 = df.shift()
return df.drop(df[(df.dept == df2.dept) & (df.title == df2.title)].index)
people.groupby('name').apply(drop_consecutive_duplicates)
【讨论】:
不一定要删除重复项 - 但是,是的,根据某些逻辑删除。任何关于快速迭代包含列表项的数据框系列的 cmets?感谢之前的cmets。 所以你想要一个框架的行并且每一行在每一列中都包含一个列表?我已经修改了我的答案,以展示如何使用 pandas 数据结构来做到这一点。以上是关于更快的 For 循环在 Pandas 中处理数据的主要内容,如果未能解决你的问题,请参考以下文章