【问题标题】:Pandas - replace for loop for efficiencyPandas - 替换 for 循环以提高效率
【发布时间】:2019-03-07 20:21:05
【问题描述】:

我有一个数据框 (df)

df = pd.DataFrame({'No': [123,234,345,456,567,678], 'text': ['60 ABC','1nHG','KL HG','21ABC','K 200','1g HG'], 'reference':['ABC','HG','FL','','200',''], 'result':['','','','','','']}, columns=['No', 'text', 'reference', 'result'])

    No    text reference result
0  123  60 ABC       ABC       
1  234    1nHG        HG       
2  345   KL HG        FL       
3  456   21ABC                 
4  567   K 200       200       
5  678   1g HG                 

和一个包含元素的列表

list
['ABC','HG','FL','200','CP1']

现在我有以下编码:

for idx, row in df.iterrows(): 

    for item in list:

        if row['text'].strip().endswith(item):

            if pd.isnull(row['reference']):
                df.at[idx, 'result'] = item

            elif pd.notnull(row['reference']) and row['reference'] != item:                
                df.at[idx, 'result'] = 'wrong item'

            if pd.isnull(row['result']):
                break

我遍历 df 和列表并检查匹配项。

输出:

    No    text reference      result
0  123  60 ABC       ABC            
1  234    1nHG        HG            
2  345   KL HG        FL  wrong item
3  456   21ABC                   ABC
4  567   K 200       200            
5  678   1g HG                    HG

break 指令很重要,否则会在列表中找到第二个元素,然后这个第二个元素会覆盖结果中的内容。

现在我需要另一个解决方案,因为数据框很大并且 for 循环效率低下。认为使用 apply 可以工作,但如何?

谢谢!

【问题讨论】:

  • 请不要对 DataFrame 使用 ascii 边框。相反,只需按照 shell 中的格式复制 DataFrame。
  • @Alex - 希望这是你的要求

标签: python pandas performance for-loop dataframe


【解决方案1】:

您可以迭代后缀,而不是迭代行,这可能是一个更小的可迭代对象。这样,您就可以利用基于系列的方法和布尔索引。

我还创建了一个额外的系列来识别行的更新时间。与按行迭代的成本相比,这种额外检查的成本应该很小。

L = ['ABC', 'HG', 'FL', '200', 'CP1']

df['text'] = df['text'].str.strip()
null = df['reference'].eq('')
df['updated'] = False

for item in L:
    ends = df['text'].str.endswith(item)
    diff = df['reference'].ne(item)

    m1 = ends & null & ~df['updated']
    m2 = ends & diff & ~null & ~df['updated']

    df.loc[m1, 'result'] = item
    df.loc[m2, 'result'] = 'wrong item'

    df.loc[m1 | m2, 'updated'] = True

结果:

    No    text reference      result updated
0  123  60 ABC       ABC               False
1  234    1nHG        HG               False
2  345   KL HG        FL  wrong item    True
3  456   21ABC                   ABC    True
4  567   K 200       200               False
5  678   1g HG                    HG    True

您可以删除最后一列,但您可能会发现它对其他用途很有用。

【讨论】:

  • 谢谢!这种方式要快得多。您看不到我不需要任何 for 循环的解决方案吗?因为在这一点上,我不能说我的列表将包含多少元素。到目前为止,已经有数百个,但肯定会有更多。
  • @MaMo,我看不到任何明显的东西。随意保持这个问题开放一段时间。其他人可能会想出更聪明的方法!
猜你喜欢
  • 2019-11-06
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
  • 2021-10-28
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 2018-04-18
相关资源
最近更新 更多