Pandas 每组中前 N% 的值,同时忽略缺失值
Pandas Top N% of values within each group while ignoring missing values
我有一个 df,我想为每一行(对应一个月)列出该行中“B”最高值的 50%。
month
A
B
1994-07
A
50
1994-07
B
60
1994-07
C
70
1994-07
D
80
1994-07
E
NAN
1994-07
F
NAN
1994-08
A
90
1994-08
B
60
1994-08
C
70
1994-08
D
95
1994-08
E
100
1994-08
F
110
1994-08
G
NAN
对于July/1994,我只有 4 列“B”填充了值,因此 50% 将是 2 个最高的 MV。之后的一个月,我有 6 只股票,这给了我 3 个最高值:
month
A
B
1994-07
C
70
1994-07
D
80
1994-08
D
95
1994-08
E
100
1994-08
F
110
我试过:
df = df.groupby(pd.Grouper(freq="M")).apply(lambda g: g.nsmallest(len(g)//2, 'B'))
但是,它不会忽略“NAN”并将其计为一个数字。例如,对于 July/1994,它计算 6 个值,因此它 return 是当月最高值的 3 个(6 个的 50%)。相反,它应该算作有 4 个值,return 我是最高的 2 个。
IIUC,你想使用 g['B'].count()
因为 count
忽略 NaNs:
(df
.groupby('month')
.apply(lambda g: g.nlargest(g['B'].count()//2, columns='B'))
.droplevel(0).sort_index()
)
或者,dropna
首先:
(df
.dropna(subset='B')
.groupby('month')
.apply(lambda g: g.nlargest(len(g)//2, 'B'))
.droplevel(0).sort_index()
)
输出:
month A B
2 1994-07 C 70.0
3 1994-07 D 80.0
9 1994-08 D 95.0
10 1994-08 E 100.0
11 1994-08 F 110.0
或者,您可以将 median
传递给 groupby.transform
,然后过滤掉大于中位数(即前 50%)的值。由于 median
方法默认跳过 NaN,因此没有问题。
out = df[df['B'] > df.groupby('month')['B'].transform('median')]
输出:
month A B
2 1994-07 C 70.0
3 1994-07 D 80.0
9 1994-08 D 95.0
10 1994-08 E 100.0
11 1994-08 F 110.0
我有一个 df,我想为每一行(对应一个月)列出该行中“B”最高值的 50%。
month | A | B |
---|---|---|
1994-07 | A | 50 |
1994-07 | B | 60 |
1994-07 | C | 70 |
1994-07 | D | 80 |
1994-07 | E | NAN |
1994-07 | F | NAN |
1994-08 | A | 90 |
1994-08 | B | 60 |
1994-08 | C | 70 |
1994-08 | D | 95 |
1994-08 | E | 100 |
1994-08 | F | 110 |
1994-08 | G | NAN |
对于July/1994,我只有 4 列“B”填充了值,因此 50% 将是 2 个最高的 MV。之后的一个月,我有 6 只股票,这给了我 3 个最高值:
month | A | B |
---|---|---|
1994-07 | C | 70 |
1994-07 | D | 80 |
1994-08 | D | 95 |
1994-08 | E | 100 |
1994-08 | F | 110 |
我试过:
df = df.groupby(pd.Grouper(freq="M")).apply(lambda g: g.nsmallest(len(g)//2, 'B'))
但是,它不会忽略“NAN”并将其计为一个数字。例如,对于 July/1994,它计算 6 个值,因此它 return 是当月最高值的 3 个(6 个的 50%)。相反,它应该算作有 4 个值,return 我是最高的 2 个。
IIUC,你想使用 g['B'].count()
因为 count
忽略 NaNs:
(df
.groupby('month')
.apply(lambda g: g.nlargest(g['B'].count()//2, columns='B'))
.droplevel(0).sort_index()
)
或者,dropna
首先:
(df
.dropna(subset='B')
.groupby('month')
.apply(lambda g: g.nlargest(len(g)//2, 'B'))
.droplevel(0).sort_index()
)
输出:
month A B
2 1994-07 C 70.0
3 1994-07 D 80.0
9 1994-08 D 95.0
10 1994-08 E 100.0
11 1994-08 F 110.0
或者,您可以将 median
传递给 groupby.transform
,然后过滤掉大于中位数(即前 50%)的值。由于 median
方法默认跳过 NaN,因此没有问题。
out = df[df['B'] > df.groupby('month')['B'].transform('median')]
输出:
month A B
2 1994-07 C 70.0
3 1994-07 D 80.0
9 1994-08 D 95.0
10 1994-08 E 100.0
11 1994-08 F 110.0