【问题标题】:Iterating a Pandas dataframe over 'n' next rows在“n”下一行上迭代 Pandas 数据框
【发布时间】:2015-02-12 19:00:04
【问题描述】:

我有这个 Pandas 数据框df

station a_d direction
   a     0      0
   a     0      0
   a     1      0
   a     0      0
   a     1      0
   b     0      0
   b     1      0
   c     0      0
   c     1      0
   c     0      1
   c     1      1
   b     0      1
   b     1      1
   b     0      1
   b     1      1
   a     0      1
   a     1      1
   a     0      0
   a     1      0

我会分配一个 value_id,当方向值改变时它会增加,并且只引用最后一对站值,首先它会随着不同的 [0,1] a_d 值改变。我可以忽略最后一个(在本例中为最后两个)数据框行。换句话说:

station a_d direction id_value
   a     0      0
   a     0      0
   a     1      0
   a     0      0        0
   a     1      0        0
   b     0      0        0
   b     1      0        0
   c     0      0        0
   c     1      0        0
   c     0      1        1
   c     1      1        1
   b     0      1         
   b     1      1        
   b     0      1        1
   b     1      1        1
   a     0      1        1
   a     1      1        1
   a     0      0
   a     1      0

使用df.iterrows()我写这个脚本:

df['value_id'] = ""
value_id = 0
row_iterator = df.iterrows()
for i, row in row_iterator:
    if i == 0:
        continue
    elif (df.loc[i-1,'direction'] != df.loc [i,'direction']):
        value_id += 1
    for z in range(1,11):
        if i+z >= len(df)-1:
            break
        elif (df.loc[i+1,'a_d'] == df.loc [i,'a_d']):
            break
        elif (df.loc[i+1,'a_d'] != df.loc [i,'a_d']) and (df.loc [i+2,'station'] == df.loc [i,'station'] and (df.loc [i+2,'direction'] == df.loc [i,'direction'])):
            break
        else:
            df.loc[i,'value_id'] = value_id

它可以工作,但速度很慢。使用10*10^6 rows 数据框,我需要一种更快的方法。有什么想法吗?

@user5402 代码运行良好,但我注意到最后一个 else 之后的 break 也会减少计算时间:

df['value_id'] = ""
value_id = 0
row_iterator = df.iterrows()
for i, row in row_iterator:
    if i == 0:
        continue
    elif (df.loc[i-1,'direction'] != df.loc [i,'direction']):
        value_id += 1
    for z in range(1,11):
        if i+z >= len(df)-1:
            break
        elif (df.loc[i+1,'a_d'] == df.loc [i,'a_d']):
            break
        elif (df.loc[i+1,'a_d'] != df.loc [i,'a_d']) and (df.loc [i+2,'station'] == df.loc [i,'station'] and (df.loc [i+2,'direction'] == df.loc [i,'direction'])):
            break
        else:
            df.loc[i,'value_id'] = value_id
            break

【问题讨论】:

  • 您发布的代码似乎没有产生该输出。
  • 我的意思是我得到['', '', '', 0, 0, 0, 0, '', '', 1, 1, '', '', 1, 1, '', ''] 作为value_id 列,它与您输出的id_value 列不匹配。
  • 您没有在内部 for 循环中有效地使用 z - 事实上,它可以完全消除。你不想在那个循环的某个地方使用df.loc[i+z,... 吗?
  • @DSM 我更正了代码
  • @user5402 我使用z。当 i+z 行不满足if 条件时,它会递增

标签: python loops pandas iterator


【解决方案1】:

您没有在内部 for 循环中有效地使用 z。您永远不会访问i+z-th 行。您可以访问第 i 行、i+1-th 行和i+2-th 行,但不能访问i+z-th 行。

您可以将内部 for 循环替换为:

  if i+1 > len(df)-1:
    pass
  elif (df.loc[i+1,'a_d'] == df.loc [i,'a_d']):
    pass
  elif (df.loc [i+2,'station'] == df.loc [i,'station'] and (df.loc [i+2,'direction'] == df.loc [i,'direction'])):
    pass
  else:
    df.loc[i,'value_id'] = value_id

请注意,我还略微优化了第二个 elif,因为此时您已经知道 df.loc[i+1,'a_d'] 不等于 df.loc [i,'a_d']

不必循环 z 将节省大量时间。

【讨论】:

  • 是的,它有效,但我意识到内部 for 循环中最后一个 else 之后的 break 使脚本与没有 for 循环的脚本一样快
  • 您的代码中根本不需要 for z in range(1,11) 行。我打赌您需要添加 break 语句,因为您的代码中仍然有 for z ... 行。只需摆脱它并将循环体重新缩进左侧一级。
  • 也许你不明白我的评论。我说在最后一个else 之后,您提出的解决方案与break 的时间相同。我只是编辑我的帖子。你同意吗?
  • 好的 - 我明白你现在在说什么了。
猜你喜欢
  • 2020-10-29
  • 1970-01-01
  • 1970-01-01
  • 2022-09-22
  • 2017-01-04
  • 2019-01-14
  • 1970-01-01
  • 2017-06-15
  • 2020-07-09
相关资源
最近更新 更多