Pandas: filling missing values by mean in each group
这应该很简单,但是我发现的最接近的是这篇文章:
大熊猫:填补小组中缺失的价值观,但我仍然无法解决我的问题...。
假设我有以下数据框
1 2 3 4 5 6 7 8 9 10 11 12 | df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C']}) name value 0 A 1 1 A NaN 2 B NaN 3 B 2 4 B 3 5 B 1 6 C 3 7 C NaN 8 C 3 |
我想在每个"名称"组中用平均值填写" NaN",即
1 2 3 4 5 6 7 8 9 10 | name value 0 A 1 1 A 1 2 B 2 3 B 2 4 B 3 5 B 1 6 C 3 7 C 3 8 C 3 |
我不确定该去哪里:
1 | grouped = df.groupby('name').mean() |
谢谢你
一种方法是使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | >>> df name value 0 A 1 1 A NaN 2 B NaN 3 B 2 4 B 3 5 B 1 6 C 3 7 C NaN 8 C 3 >>> df["value"] = df.groupby("name").transform(lambda x: x.fillna(x.mean())) >>> df name value 0 A 1 1 A 1 2 B 2 3 B 2 4 B 3 5 B 1 6 C 3 7 C 3 8 C 3 |
@DSM为IMO提供了正确的答案,但我想分享我对该问题的概括和优化:将多个列分组,并具有多个值列:
1 2 3 4 5 6 7 8 | df = pd.DataFrame( { 'category': ['X', 'X', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y'], 'name': ['A','A', 'B','B','B','B', 'C','C','C'], 'other_value': [10, np.nan, np.nan, 20, 30, 10, 30, np.nan, 30], 'value': [1, np.nan, np.nan, 2, 3, 1, 3, np.nan, 3], } ) |
...给...
1 2 3 4 5 6 7 8 9 10 | category name other_value value 0 X A 10.0 1.0 1 X A NaN NaN 2 X B NaN NaN 3 X B 20.0 2.0 4 X B 30.0 3.0 5 X B 10.0 1.0 6 Y C 30.0 3.0 7 Y C NaN NaN 8 Y C 30.0 3.0 |
在这种一般情况下,我们希望按
可以解决以下问题:
1 2 | df['value'] = df.groupby(['category', 'name'])['value']\ .transform(lambda x: x.fillna(x.mean())) |
请注意group-by子句中的列列表,并且我们在group-by之后选择
通过执行以下操作增加数据集来进行性能测试:
1 2 3 4 5 6 7 | big_df = None for _ in range(10000): if big_df is None: big_df = df.copy() else: big_df = pd.concat([big_df, df]) df = big_df |
...确认这将使速度与您不必估算的列数成正比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd from datetime import datetime def generate_data(): ... t = datetime.now() df = generate_data() df['value'] = df.groupby(['category', 'name'])['value']\ .transform(lambda x: x.fillna(x.mean())) print(datetime.now()-t) # 0:00:00.016012 t = datetime.now() df = generate_data() df["value"] = df.groupby(['category', 'name'])\ .transform(lambda x: x.fillna(x.mean()))['value'] print(datetime.now()-t) # 0:00:00.030022 |
最后要指出的是,如果您要推算多个而不是全部的列,则可以进一步推广:
1 2 | df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\ .transform(lambda x: x.fillna(x.mean())) |
这看起来很直观:
1 | df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean')) |
我会这样
1 | df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean') |
以上大多数答案都涉及使用" groupby"和" transform"填充缺失值。
但是我更喜欢使用" groupby"和" apply"来填充缺少的值,这对我来说更直观。
1 2 3 | >>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean())) >>> df.isnull().sum().sum() 0 |
快捷方式:Groupby + Apply / Lambda + Fillna + Mean
如果要按多列分组以替换缺少的值,则此解决方案仍然有效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | >>> df = pd.DataFrame({'value': [1, np.nan, np.nan, 2, 3, np.nan,np.nan, 4, 3], 'name': ['A','A', 'B','B','B','B', 'C','C','C'],'class':list('ppqqrrsss')}) >>> df value name class 0 1.0 A p 1 NaN A p 2 NaN B q 3 2.0 B q 4 3.0 B r 5 NaN B r 6 NaN C s 7 4.0 C s 8 3.0 C s >>> df['value']=df.groupby(['name','class'])['value'].apply(lambda x:x.fillna(x.mean())) >>> df value name class 0 1.0 A p 1 1.0 A p 2 2.0 B q 3 2.0 B q 4 3.0 B r 5 3.0 B r 6 3.5 C s 7 4.0 C s 8 3.0 C s |
精选的高答案仅适用于只有两列的熊猫数据框。如果您有更多的列,请改用:
1 2 | df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform( lambda x: x.fillna(x.mean())) |
1 2 3 4 5 | def groupMeanValue(group): group['value'] = group['value'].fillna(group['value'].mean()) return group dft = df.groupby("name").transform(groupMeanValue) |
您也可以使用
1 | df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True) |