Pandas: 应用滚动函数计算新的列值

Pandas: Apply rolling function to compute new column value

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

[编辑]

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

UPDATE 我使用了下面推荐的这个选项并且有效。虽然还有其他选择,但我觉得这样更干净

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

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

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

您可以在 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 函数以考虑传递的变量 window 大小。我相信这就是您要找的。

您的 X 数据类型似乎是对象而不是浮点数。尝试以下操作,看看它是否有效。

 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

您可以使用:

  • 首先通过 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