python pandas 试图减少对循环的依赖

python pandas trying to reduce reliance on loops

这是一个关于矢量化的一般问题,但我会用一个例子来帮助提问。我有一个数据框 dfdf[col_1] bool (True/False)。 在 df[col_2] 中,我想 return 另一个 True/False 基于第 1 列 df[col_1][i-6:i-1] 的前五行是否包含 df[col_1][i] 的匹配项。

这是我现在使用的循环,但它只是众多循环之一,所以我认为随着数据变大,它们一定会放慢速度:

for i in df.index:
  if i < 6:
    df[col_2][i] = 0.
  else:
    df[col_2][i] = df[col_1][i] not in tuple(df[col_1].ix[i-6:i-1,col_1)

...输出如下所示:

.   col_1   col_2
0   TRUE    
1   TRUE    
2   TRUE    
3   TRUE    
4   FALSE   
5   FALSE   FALSE
6   FALSE   FALSE
7   FALSE   FALSE
8   FALSE   FALSE
9   TRUE    TRUE
10  FALSE   FALSE
11  FALSE   FALSE
12  FALSE   FALSE
13  FALSE   FALSE
14  TRUE    FALSE
15  TRUE    FALSE
16  TRUE    FALSE
17  TRUE    FALSE
18  TRUE    FALSE
19  TRUE    FALSE
20  FALSE   TRUE

我如何在 pandas 中使用矢量化执行此操作 - 也许使用 shift() 或偏移函数?

这是一个简单的矢量化解决方案,应该非常快,尽管可能有更优雅的编写方式。如果愿意,您可以忽略前 5 行或将它们覆盖为 NaN。

df = pd.DataFrame({ 'col_1':[True,True,True,True,False,False,False,False,
                             False,True,False,False,False,False,True,True,
                             True,True,True,True,False] })

df['col_2'] = ((df!=df.shift(1)) & (df!=df.shift(2)) & (df!=df.shift(3)) & 
               (df!=df.shift(4)) & (df!=df.shift(5)))

如果速度真的很重要,您可以执行以下操作。它比上面的速度快 3 倍以上,并且可能与您在此处执行的操作一样高效。这只是利用 rolling_sum() 将布尔值解释为 0/1 的事实,您只需要知道总和是 0 还是 5。

df['rollsum'] = pd.rolling_sum(df.col_1,6) - df.col_1
df['col_3'] = ( ((df.col_1==True ) & (df.rollsum==0)) 
              | ((df.col_1==False) & (df.rollsum==5)) )

    col_1  col_2  rollsum  col_3
0    True   True      NaN  False
1    True  False      NaN  False
2    True  False      NaN  False
3    True  False      NaN  False
4   False   True      NaN  False
5   False  False        4  False
6   False  False        3  False
7   False  False        2  False
8   False  False        1  False
9    True   True        0   True
10  False  False        1  False
11  False  False        1  False
12  False  False        1  False
13  False  False        1  False
14   True  False        1  False
15   True  False        1  False
16   True  False        2  False
17   True  False        3  False
18   True  False        4  False
19   True  False        5  False
20  False   True        5   True