【问题标题】:Pandas: Apply rolling function to compute new column valuePandas:应用滚动函数来计算新列值
【发布时间】:2017-07-09 03:58:21
【问题描述】:

我正在尝试通过检查 X 列的前 9 行和当前行值来计算每行的新 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

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

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]

【问题讨论】:

  • 对于前 9 条记录,它没有大小为 9 的窗口,这就是您看到 NaN 的原因。我想要么手动设置它们,要么逐渐增加窗口大小直到达到 9。
  • 另外,您的预期结果看起来不对。为什么第一条记录的值应该是 80%?它之前没有任何记录。为什么第二条记录的值是 77%?它之前的所有记录的X值都大于1,所以不应该是100%吗?
  • @HavanAgrawal 我相信 OP 的价值观是颠倒的,除了这里和那里的计算错误。
  • @HavanAgrawal 更正了值

标签: python pandas numpy dataframe artificial-intelligence


【解决方案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 函数以考虑传递的可变窗口大小。我相信这就是你要找的。

【讨论】:

  • @COLDSPEED 我试过跑步,但我没有得到正确的 Y 值,正如你指出的那样
  • 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) print(df)
  • 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
  • @COLDSPEED 当它达到负值时,逻辑似乎正在中断
  • @user845405 你有什么不一样的吗?还是说我的回答不正确?
【解决方案2】:

你可以使用:

  • 首先将列X 转换为float by astype
  • 将参数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

【讨论】:

  • 这不起作用 df['Y'] = df['X'].astype(float).rolling(window=10, min_periods=1).apply(count_pcnt)
  • 功能是否正确?也许有些() 有问题 - 你能检查一下吗?
  • 是函数是正确的,但输出与问题中的相同。不过,您的第一个选项有效!
  • 我添加了 2 个具有相同输出的功能替代品,你能检查一下它是如何工作的吗?
  • 具有均值的函数可以正常工作,但另一个则不行
【解决方案3】:

您的 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

【讨论】:

    猜你喜欢
    • 2021-12-08
    • 2014-05-10
    • 2018-05-23
    • 2017-06-27
    • 2019-09-09
    • 1970-01-01
    • 2012-12-27
    • 2017-02-03
    相关资源
    最近更新 更多