Pandas:应用滚动功能来计算新的列值

时间:2017-07-09 03:58:22

标签: python pandas numpy dataframe artificial-intelligence

我试图通过检查列X的前9行和当前行值来计算每行的新列Y.基本上每行的新列Y值将告诉我们列X的值的百分比更大包括当前记录在内的前10个记录中的1个以上。下面是我正在使用的代码,但获得的结果与预期不同

[EDITED]

def count_pcnt(x):
 return ((np.sum(x > 1) / len(x)) * 100.0)

def run():
df = pd.DataFrame(
data={'X': ['8.12', '7.13', '-5.30', '3.21', '4.21', '3.14','8.65', 
            '7.33', '-5.10', '3.01']
      })


df['Y'] = df['X'].rolling(window=10, min_periods=1).apply(lambda x: 
          count_pcnt(x)).apply(int)

预期结果 [已编辑]

     X    Y(%)
0   8.12  100
1   7.13  100
2  -5.30  66.67
3   3.21  75
4   4.21  80
5   3.14  83.33
6   8.65  85.71
7   7.33  87.50
8  -5.10  77.77
9   3.01  80

实际

      X    Y
 0   8.12  100
 1   7.13  100
 2  -5.30  0
 3   3.21  0
 4   4.21  0
 5   3.14  0
 6   8.65  0
 7   7.33  0
 8  -5.10  0
 9   3.01  0

更新我使用了下面推荐的这个选项并且它有效。虽然还有其他选择,我觉得这更清洁

df['Y'] = df['X'].astype(float)
             .rolling(window=w, min_periods=1)
             .apply(lambda x: (x>1).mean()) * 100

如果你想根据接下来的10行计算列值而不是前10行 - 下面是解决方案(感谢 jezrae l提供了它)

df['Y'] = (df['X'].astype(float).iloc[::-1].rolling(window=10, min_periods=1).apply(lambda x: (x>1).mean()) * 100)[::-1]

3 个答案:

答案 0 :(得分:2)

您可以在df.rolling中设置min_periods=1属性:

In [927]: def count_pcnt(x):
     ...:     return ((np.sum(x > 1) / len(x)) * 100.0)
     ...: 

In [930]: df['Y'] = df['X'].astype(np.float64).rolling(window=10, min_periods=1).apply(lambda x: count_pcnt(x))

In [931]: df
Out[931]: 
       X           Y
0   8.12  100.000000
1   7.13  100.000000
2  -5.30   66.666667
3   3.21   75.000000
4   4.21   80.000000
5   3.14   83.333333
6   8.65   85.714286
7   7.33   87.500000
8  -5.10   77.777778
9   3.01   80.000000

我修改了您的count_pcnt功能,以考虑传递的可变窗口大小。我相信这就是你要找的东西。

答案 1 :(得分:1)

似乎X的数据类型是object而不是float。请尝试以下操作以查看它是否有效。

 df['Y'] = (
    df.assign(X2=(df.X.astype(float)>0)).X2.rolling(window=10,min_periods=1)
      .apply(lambda x: sum(x)*100.0/len(x))
    )

df
Out[92]: 
       X           Y
0   8.12  100.000000
1   7.13  100.000000
2  -5.30   66.666667
3   3.21   75.000000
4   4.21   80.000000
5   3.14   83.333333
6   8.65   85.714286
7   7.33   87.500000
8  -5.10   77.777778
9   3.01   80.000000

答案 2 :(得分:1)

您可以使用:

  • 首先按astype
  • 将列X转换为float
  • 将参数min_periods添加到Series.rolling
  • 而不是自定义函数使用lambda与(x>1).mean()具有相同的输出
df = pd.DataFrame(
data={'X': ['8.12', '7.13', '-5.30', '3.21', '4.21', '3.14','8.65', 
            '7.33', '-5.10', '3.01']
      })
w = 10
df['Y'] = df['X'].astype(float)
                 .rolling(window=w, min_periods=1)
                 .apply(lambda x: (x>1).mean()) * 100
print(df)

      X           Y
0  8.12  100.000000
1  7.13  100.000000
2 -5.30   66.666667
3  3.21   75.000000
4  4.21   80.000000
5  3.14   83.333333
6  8.65   85.714286
7  7.33   87.500000
8 -5.10   77.777778
9  3.01   80.000000

自定义功能解决方案:

def count_pcnt(x):
    return ((np.sum(x>1))/ len(x))*100.0

w = 10
df['Y'] = df['X'].astype(float).rolling(window=w, min_periods=1).apply(count_pcnt)
print(df)
       X           Y
0   8.12  100.000000
1   7.13  100.000000
2  -5.30   66.666667
3   3.21   75.000000
4   4.21   80.000000
5   3.14   83.333333
6   8.65   85.714286
7   7.33   87.500000
8  -5.10   77.777778
9   3.01   80.000000 

编辑:

可以通过以下方式更改功能:

def count_pcnt(x):
    return ((x>1).sum() / len(x))*100.0

或:

def count_pcnt(x):
    return (x>1).mean()*100.0