如何用 pandas 中 2 列 groupby 的均值中位数填充 NA?
How to fill NAs with median of means of 2-column groupby in pandas?
使用 pandas,我有一个包含两个层次结构 A
和 B
的数据框,其中 B 可以是 NaN
,我想在其中填充一些 NaN D
以特定方式:
在下面的示例中,A 有 "B-subgroups",其中 D 根本没有值(例如 (1, 1)
),而 A 在其他子组中也有 D 的值(例如 (1, 3)
).
现在想得到每个子组的mean
(120, 90 and 75
for A==1
),求出这些均值的median
(90
for A==1
) 并使用此中位数填充 A==1
.
的其他子组中的 NaN
像 A==2
这样的组,其中只有 D 的 NaN,不应被填充。
像 A==3
这样的组,其中有一些 D 的值,但只有 B 为 NaN 的行在 D 中有 NaN,如果可能的话不应该被填充(我打算稍后用所有的平均值填充这些他们整个A组的D值)。
示例 df:
d = {'A': [1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3],
'B': [1, 2, 3, 3, 4, 5, 6, 1, 1, np.NaN, np.NaN],
'D': [np.NaN, np.NaN, 120, 120, 90, 75, np.NaN, np.NaN, 60, 50, np.NaN]}
df = pd.DataFrame(data=d)
A B D
1 1 NaN
1 2 NaN
1 3 120
1 3 120
1 4 90
1 5 75
1 6 NaN
2 1 NaN
3 1 60
3 NaN 50
3 NaN NaN
预期结果:
A B D
1 1 90
1 2 90
1 3 120
1 3 120
1 4 90
1 5 75
1 6 90
2 1 NaN
3 1 60
3 NaN 50
3 NaN NaN
使用 df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
或 .median()
我似乎得到了正确的值,但是使用
df['D'] = df['D'].fillna(
df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
)
似乎没有更改 D 中的任何值。
非常感谢任何帮助,我已经坚持了一段时间,无法在任何地方找到任何解决方案。
你的第一步是正确的。之后,我们使用 Series.map
将正确的中位数映射到列 A
.
中的每个组
最后我们使用np.where
有条件地填充列D
if B is not NaN
:
medians = df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
df['D'] = np.where(df['B'].notna(), # if B is not NaN
df['D'].fillna(df['A'].map(medians)), # fill in the median
df['D']) # else keep the value of column D
A B D
0 1 1.00 90.00
1 1 2.00 90.00
2 1 3.00 120.00
3 1 3.00 120.00
4 1 4.00 90.00
5 1 5.00 75.00
6 1 6.00 90.00
7 2 1.00 nan
8 3 1.00 60.00
9 3 nan 50.00
10 3 nan nan
使用 pandas,我有一个包含两个层次结构 A
和 B
的数据框,其中 B 可以是 NaN
,我想在其中填充一些 NaN D
以特定方式:
在下面的示例中,A 有 "B-subgroups",其中 D 根本没有值(例如 (1, 1)
),而 A 在其他子组中也有 D 的值(例如 (1, 3)
).
现在想得到每个子组的mean
(120, 90 and 75
for A==1
),求出这些均值的median
(90
for A==1
) 并使用此中位数填充 A==1
.
像 A==2
这样的组,其中只有 D 的 NaN,不应被填充。
像 A==3
这样的组,其中有一些 D 的值,但只有 B 为 NaN 的行在 D 中有 NaN,如果可能的话不应该被填充(我打算稍后用所有的平均值填充这些他们整个A组的D值)。
示例 df:
d = {'A': [1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3],
'B': [1, 2, 3, 3, 4, 5, 6, 1, 1, np.NaN, np.NaN],
'D': [np.NaN, np.NaN, 120, 120, 90, 75, np.NaN, np.NaN, 60, 50, np.NaN]}
df = pd.DataFrame(data=d)
A B D
1 1 NaN
1 2 NaN
1 3 120
1 3 120
1 4 90
1 5 75
1 6 NaN
2 1 NaN
3 1 60
3 NaN 50
3 NaN NaN
预期结果:
A B D
1 1 90
1 2 90
1 3 120
1 3 120
1 4 90
1 5 75
1 6 90
2 1 NaN
3 1 60
3 NaN 50
3 NaN NaN
使用 df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
或 .median()
我似乎得到了正确的值,但是使用
df['D'] = df['D'].fillna(
df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
)
似乎没有更改 D 中的任何值。
非常感谢任何帮助,我已经坚持了一段时间,无法在任何地方找到任何解决方案。
你的第一步是正确的。之后,我们使用 Series.map
将正确的中位数映射到列 A
.
最后我们使用np.where
有条件地填充列D
if B is not NaN
:
medians = df.groupby(['A', 'B'])['D'].mean().groupby(['A']).agg('median')
df['D'] = np.where(df['B'].notna(), # if B is not NaN
df['D'].fillna(df['A'].map(medians)), # fill in the median
df['D']) # else keep the value of column D
A B D
0 1 1.00 90.00
1 1 2.00 90.00
2 1 3.00 120.00
3 1 3.00 120.00
4 1 4.00 90.00
5 1 5.00 75.00
6 1 6.00 90.00
7 2 1.00 nan
8 3 1.00 60.00
9 3 nan 50.00
10 3 nan nan