优化python数据帧迭代循环

时间:2021-06-22 14:32:14

标签: python pandas loops

我有两个数据框,df 和 ct

dfUNIT, START, END, CHECK 是相关列。 CHECK 值均默认为“n”。我的代码测试它们,如果它们通过,则将此值更改为 'y'

df.shape = 59155, 5
<头>
单位 DTours 开始 END 检查
0 A7000 0.1097 43100.0321 43382.1417 n
1 A7000 0.0125 43105.6621 43382.6736 n
2 A7000 0.2042 43200.1214 43388.3465 n
3 A7000 0.1521 43389.2979 43854.4500 n
4 A7002 0.1455 44198.5049 44199.0009 n

ctUNIT, START, END 是唯一的组合,但每个 UNIT 可以有多个条目(这些实际上是开始/结束日期)。平均每个 UNIT 行重复约 5 次

ct.shape = 6219, 3
<头>
单位 开始 END
0 A7000 43101 43156
1 A7000 43101 43173
2 A7000 43172 43616
3 A7000 43172 43712
4 A7002 43172 44196

我正在测试 df['START'] 和 df['END '] 值是否在 ct 中该 UNIT 的任何实例之间。然而,代码花费的时间特别长。它在 12 小时内迭代了约 12000 行。我做错了什么?

伪代码:

 for loop iterating through all rows of df
      create list of all cf[START] values for current df[UNIT]
      create list of all cf[END] values for current df[UNIT]

      test if the df[CHECK] value is 'n' viz default value
           for loop iterating over length of cf[START] (len = cf[END]), index
                test if (df[START]>= cf[START][index]) AND (df[END]>= cf[END][index])
                     change df[CHECK] to 'y'
                     break for loop iterating over cf[START] for this row in df

实际代码:

for index, row in df.iterrows():
    display.clear_output(wait=True)
    display.display(plt.gcf())
    
    df_unit = row['UNIT']
    ct_start = ct.loc[ct['UNIT'] == df_unit]['START'].values
    ct_end = ct.loc[ct['UNIT'] == df_unit]['END'].values
    
    if (row['UNIT'] != 'y'):
        for ct_index in range(len(ct_start)):
            if ((row['START'] >= ct_start[ct_index]) & (row['END'] <= 
ct_end[ct_index])):
                row['CHECK'] == 'y'
                aaa += 1
                break
        
    plt.scatter(index,aaa, c='r')

上述数据帧的预期输出

<头>
单位 DTours 开始 END 检查
0 A7000 0.1097 43100.0321 43382.1417 n
1 A7000 0.0125 43105.6621 43382.6736 n
2 A7000 0.2042 43200.1214 43388.3465 y
3 A7000 0.1521 43389.2979 43854.4500 n
4 A7002 0.1455 44198.5049 44199.0009 n

2 个答案:

答案 0 :(得分:1)

根据经验:90% 的情况下,如果您在数据帧上使用循环,那么您做错了

就你而言:

  • 与其做 for ... if,不如过滤数据框:df[df["CHECK"] == "y"]
  • 您不断为每一行过滤 ct 数据框。您最好将此数据框分组一次并将其转换为您可以按单元访问的字典:
    • units = dict(list(ct.groupby("UNIT")))
    • for index in units[df_unit]: do_something()

这应该已经大大提高了性能

答案 1 :(得分:0)

我们可以使用以下步骤来解决这个问题

  • df上用merge重置ctUNIT的索引
  • 查询生成的合并数据框以查找 STARTEND 中的对应值满足包含条件的索引
  • 使用带有 loc 的布尔索引,使用在上一步中获得的索引将 CHECK 列中的值更新为 y
s  = df.reset_index().merge(ct, on='UNIT', suffixes=['', '_r'])
ix = s.query("START >= START_r and END <= END_r")['index']
df.loc[df.index.isin(ix), 'CHECK'] = 'y'

    UNIT  DTHours       START         END CHECK
0  A7000   0.1097  43100.0321  43382.1417     n
1  A7000   0.0125  43105.6621  43382.6736     n
2  A7000   0.2042  43200.1214  43388.3465     y
3  A7000   0.1521  43389.2979  43854.4500     n
4  A7002   0.1455  44198.5049  44199.0009     n
相关问题