我想根据每行的排序值列表中的位置(不包括NaN)来分配每个值的位置。我只是无法弄清楚如何用pandas以优雅的方式做到这一点。
我认为在一个例子中解释更容易:
A B C D
Date
2002-02-28 -0.051272 -0.005851 -0.012669 NaN
2002-03-29 0.103416 0.050121 0.050203 0.5
2002-04-30 -0.090579 -0.042308 0.019293 0.03
2002-05-31 0.160239 -0.078983 0.047319 0.66
对于每一行,我想执行以下操作:
结果将是:
A B C D
Date
2002-02-28 1 3 2 NaN
2002-03-29 3 1 2 4
2002-04-30 1 2 3 4
2002-05-31 3 1 2 4
在第二步中,我想要每列制作一个3行“滚动”功能,检查当前行和一列之前的2行是否小于某个阈值X,如果是,然后显示这3个值的平均值,否则只需记下NaN。如果这3个值中的任何一个是NaN,那么只需记下NaN。只能从2002-04-30进行计算,因为需要至少3个值。对于列D,这将在行2002-04-30中产生“NaN”,因为事先只有两个数值。对于D列和2002-05-31行,它也会产生“NaN”,因为3个值是4,4和4,其中4大于阈值。
假设阈值X = 3。 (我遗漏了D栏,因为我的解释使数据变宽):
E.g:
A B C
Date
2002-02-28 NaN NaN NaN
2002-03-29 NaN NaN NaN
2002-04-30 Avg(1,3,1) Avg(3,1,2) Avg(2+2+3)
2002-05-31 Avg(3,1,3) Avg(1,2,1) Avg(2+3+2)
修改: 我想我自己也做了两个步骤。你能否评价这是否正确和明智?:
import numpy as np
import pandas as pd
df = pd.DataFrame(data={'X': [0.1, 0.2, 0.3, 0.4], 'Y': [0.5, -0.2, np.NaN, -1], 'Z': [np.NaN, -0.21, -5, 10]})
df.apply(lambda row: [sorted([y for y in row if not np.isnan(y)]).index(x)+1 if not np.isnan(x) else np.NaN for x in row], axis=1)
df:
X Y Z
0 0.1 0.5 NaN
1 0.2 -0.2 -0.21
2 0.3 NaN -5.00
3 0.4 -1.0 10.00
After .apply:
X Y Z
0 1.0 2.0 NaN
1 3.0 2.0 1.0
2 2.0 NaN 1.0
3 2.0 1.0 3.0
# Step 2 with new examplatory data and only one column
df = pd.DataFrame(data={'A': [1,2,3,np.NaN,3,1,3,4,3,np.NaN,2,2,1,2]})
threshold = 3
df['A_rolling'] = df['A'].rolling(window=3, min_periods=3).apply(lambda x: x.mean() if all([val <= threshold for val in x]) else np.NaN)
A A_rolling
0 1.0 NaN
1 2.0 NaN
2 3.0 2.000000
3 NaN NaN
4 3.0 NaN
5 1.0 NaN
6 3.0 2.333333
7 4.0 NaN
8 3.0 NaN
9 NaN NaN
10 2.0 NaN
11 2.0 NaN
12 1.0 1.666667
13 2.0 1.666667
所以现在只需要为所有列运行它:)
有什么想法吗? 感谢
答案 0 :(得分:2)
对于第一步,您可以使用rank
方法:
step1 = df.rank(axis=1)
A B C D Date 2002-02-28 1.0 3.0 2.0 NaN 2002-03-29 3.0 1.0 2.0 4.0 2002-04-30 1.0 2.0 3.0 4.0 2002-05-31 3.0 1.0 2.0 4.0
对于第二步,用NaN
替换大于阈值的所有值并运行滚动平均值可能不那么冗长:
threshold = 3
step1[step1 > threshold] = pd.np.NaN
step2 = step1.rolling(window=3, min_periods=3).mean()
A B C D Date 2002-02-28 NaN NaN NaN NaN 2002-03-29 NaN NaN NaN NaN 2002-04-30 1.666667 2.000000 2.333333 NaN 2002-05-31 2.333333 1.333333 2.333333 NaN