寻找一种有效的迭代方式

时间:2017-05-04 14:40:42

标签: python-3.x performance pandas numpy pandas-groupby

我可以请求更高效(更快)迭代的建议吗? 这是问题,我正在寻找一种方法在确定的窗口大小内在pandas DataFrame中传播零:

<input type="button" id="createPassSubmit" value="Create">

现在我们想要通过增加每行3行的窗口来填充 顶部的值。 每行3行的窗口从window_start开始,定义为:

import numpy as np
import pandas as pd

A = np.matrix([[ 0.,  1.,  1.,  1.,  1.],
           [ 1.,  0.,  1.,  1.,  1.],
           [ 1.,  1.,  0.,  1.,  1.],
           [ 1.,  1.,  1.,  0.,  1.],
           [ 1.,  1.,  1.,  1.,  0.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  0.],
           [ 1.,  1.,  0.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  0.,  1.],
           [ 1.,  1.,  1.,  1.,  1.],
           [ 1.,  1.,  0.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  0.],
           [ 1.,  0.,  1.,  1.,  1.],
           [ 1.,  1.,  1.,  1.,  1.]])

df = pd.DataFrame(A)

现在将DataFrame从零传播到零 在该窗口内的上面一行:

window_size = 3
window_start = [i for i in range(0, df.shape[0]) 
                if i % window_size == 0]
print(df)
gf = df.copy()
print('\n')

对于非常大的数据集来说,这最后一点非常低效且耗时,是否有更好的方法呢?

2 个答案:

答案 0 :(得分:8)

您应该能够使用groupby内的累积产品完成此任务。

df.groupby(np.arange(len(df)) // 3).cumprod()

      0    1    2    3    4
0   0.0  1.0  1.0  1.0  1.0
1   0.0  0.0  1.0  1.0  1.0
2   0.0  0.0  0.0  1.0  1.0
3   1.0  1.0  1.0  0.0  1.0
4   1.0  1.0  1.0  0.0  0.0
5   1.0  1.0  1.0  0.0  0.0
6   1.0  1.0  1.0  1.0  1.0
7   1.0  1.0  1.0  1.0  1.0
8   1.0  1.0  1.0  1.0  0.0
9   1.0  1.0  0.0  1.0  1.0
10  1.0  1.0  0.0  1.0  1.0
11  1.0  1.0  0.0  1.0  1.0
12  1.0  1.0  1.0  1.0  1.0
13  1.0  1.0  1.0  1.0  1.0
14  1.0  1.0  1.0  0.0  1.0
15  1.0  1.0  1.0  1.0  1.0
16  1.0  1.0  0.0  1.0  1.0
17  1.0  1.0  0.0  1.0  0.0
18  1.0  0.0  1.0  1.0  1.0
19  1.0  0.0  1.0  1.0  1.0

我们可以更好地了解一下,使用concat查看它是否正在执行我们想要的操作。

pd.concat([df.iloc[:6, :2], d1.iloc[:6, :2]], axis=1, keys=['Before', 'After'])

  Before      After     
       0    1     0    1
0    0.0  1.0   0.0  1.0
1    1.0  0.0   0.0  0.0
2    1.0  1.0   0.0  0.0
3    1.0  1.0   1.0  1.0
4    1.0  1.0   1.0  1.0
5    1.0  1.0   1.0  1.0

我采用numpy方法
请参阅@Divakar的解决方案,因为我借用了其功能的一些元素

def prop_zero(df, window_size=3):
    a = df.values
    W = window_size
    m, n = a.shape

    pad = np.zeros((W - m % W, n))
    b = np.vstack([a, pad])

    return pd.DataFrame(
        b.reshape(-1, W, n).cumprod(1).reshape(-1, n)[:m],
        df.index, df.columns
    )

prop_zero(df)

答案 1 :(得分:5)

您可以使用groupby执行cummin

In [46]: out = df.groupby(np.arange(len(df))//3).cummin()

In [47]: df.head(6)
Out[47]: 
     0    1    2    3    4
0  0.0  1.0  1.0  1.0  1.0
1  1.0  0.0  1.0  1.0  1.0
2  1.0  1.0  0.0  1.0  1.0
3  1.0  1.0  1.0  0.0  1.0
4  1.0  1.0  1.0  1.0  0.0
5  1.0  1.0  1.0  1.0  1.0

In [48]: out.head(6)
Out[48]: 
     0    1    2    3    4
0  0.0  1.0  1.0  1.0  1.0
1  0.0  0.0  1.0  1.0  1.0
2  0.0  0.0  0.0  1.0  1.0
3  1.0  1.0  1.0  0.0  1.0
4  1.0  1.0  1.0  0.0  0.0
5  1.0  1.0  1.0  0.0  0.0

这假设所有值都是0和1.如果你有非1值,但你仍然想要零之后的行为,你可以做类似的事情

df.where(~(df == 0).groupby(np.arange(len(df))//3).cummax(), 0)

这不是很漂亮,但不会被像0.5这样的值(直接将cummin直接应用于值)或潜在溢出(将cumprod直接应用于值)所迷惑一样)。