更快的 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 中处理数据的主要内容,如果未能解决你的问题,请参考以下文章

第五篇 pandas??

pandas小结

从两个 Pandas DataFrames 向数据帧添加一列,当前使用两个带有条件的循环:有更快的方法吗?

附加在 for 循环中生成的 pandas 数据帧

在 for 循环中显示 Pandas 数据框

如何将 for 循环中的 .pkl 文件附加到 for 循环中创建的 pandas 数据帧?