pandas:填充组中的缺失值,但我仍然无法解决我的问题....
假设我具有以下数据框
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”,即
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
我不确定该去哪里:
grouped = df.groupby('name').mean()
谢谢。
/>
#1 楼
一种方法是使用transform
:>>> 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
#2 楼
fillna
+ groupby
+ transform
+ mean
这似乎很直观:
df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))
groupby
+ transform
语法图原始数据帧索引的分组均值。这大致相当于@DSM的解决方案,但避免了定义匿名lambda
函数的需要。#3 楼
@DSM为IMO提供了正确的答案,但我想分享我对该问题的概括和优化:多个列进行分组,并具有多个值列: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],
}
)
...给出...
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
在这种一般情况下,我们希望将
category
和name
分组,并仅对value
进行归因。可以通过以下方法解决:
df['value'] = df.groupby(['category', 'name'])['value']\
.transform(lambda x: x.fillna(x.mean()))
请注意group-by子句中的列列表,并在组之后选择
value
列-通过。这使得转换只能在该特定列上运行。您可以将其添加到末尾,但是随后将对所有列运行它,仅抛出末尾一个度量列之外的所有列。标准的SQL查询计划程序可能已经能够优化此功能,但是pandas(0.19.2)似乎无法做到这一点。通过...提高数据集的性能测试...
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
...确认这将提高速度,与您不必估算的列数成正比:
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
最后一点,如果您要推算多个而不是全部的列,则可以进一步推广:
df[['value', 'other_value']] = df.groupby(['category', 'name'])['value', 'other_value']\
.transform(lambda x: x.fillna(x.mean()))
评论
感谢您的出色工作。我想知道如何使用for循环来成功完成相同的转换。速度与我无关,因为我正在尝试寻找手动方法。谢谢@AndréC.Andersen
–奥兹坎·塞塔斯(Ozkan Serttas)
19年1月9日在21:55
#4 楼
我会这样df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
评论
与此版本df ['value_imputed'] = np.where(df.value.isnull(),df.groupby('group')。value.transform('mean'),df.value)略有不同的版本
–tsando
19年7月16日在10:13
#5 楼
上面的大多数答案都涉及使用“ groupby”和“ transform”填充缺失值。但是我更喜欢将“ groupby”与“ apply”一起填充缺失值,这对我来说更直观。
>>> df['value']=df.groupby('name')['value'].apply(lambda x:x.fillna(x.mean()))
>>> df.isnull().sum().sum()
0
快捷方式:Groupby + Apply / Lambda + Fillna + Mean
如果要按多列分组以替换,此解决方案仍然有效缺少值。
>>> 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
#6 楼
精选的高答案仅适用于只有两列的熊猫数据框。如果您有更多的专栏案例,请改用:df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
lambda x: x.fillna(x.mean()))
评论
谢谢,这个答案对我有用。对于刚接触大熊猫的人,也可以使用切片符号df.groupby(“ continent”)['Crude_Birth_rate']进行索引...我认为这是建议的转换
–亚当·休斯(Adam Hughes)
19年11月7日在19:07
#7 楼
def groupMeanValue(group):
group['value'] = group['value'].fillna(group['value'].mean())
return group
dft = df.groupby("name").transform(groupMeanValue)
#8 楼
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
评论
请给您的答案一些解释。为什么在Google偶然发现此页面的人将您的解决方案用于其他6个答案?
– Divibisan
18-10-4在20:28
@vino请添加一些解释
–努斯纳兹
19年2月16日在19:28
#9 楼
您也可以使用"dataframe or table_name".apply(lambda x: x.fillna(x.mean()))
。
评论
当我开始坐下来阅读文档时,我发现它很有帮助。在groupby部分中介绍了这一部分。有太多的事情要记住,但是您会选择诸如“转换是针对每个组操作的规则,这些操作要像原始帧一样被索引”之类的规则。
– DSM
13年13月13日在22:57
还要寻找韦斯·麦金尼(Wes McKinney)的书。我个人认为groupby上的文档非常糟糕,这本书稍好一些。
–木质的骄傲
13年11月14日,0:51
如果您有两列以上,请确保指定列名称df [“ value”] = df.groupby(“ name”)。transform(lambda x:x.fillna(x.mean()))['value ']
–劳伦
17年1月10日在16:57
@Lauren好点。我想补充一下,出于性能方面的考虑,您可能考虑将value列的说明进一步移到group-by子句。这样,lambda函数仅在该特定列(而不是每个列)中调用值,然后才选择列。做了一个测试,使用两根色谱柱的速度是它的两倍。当然,无需插入更多的列,您也可以获得更好的性能:df [“ value”] = df.groupby(“ name”)[“ value”]。transform(lambda x:x.fillna(x.mean ()))
–AndréC. Andersen
17年7月28日在12:11
我已经搜索了两天。。只是您的一个问题。为什么用循环很难做到这一点?因为在我的情况下,有两个多重索引,即State和Age_Group,然后我试图用组均值填充那些组中的缺失值(来自同一年龄组中的同一州取均值并填充组中的缺失)。
–奥兹坎·塞塔斯(Ozkan Serttas)
19年1月9日在20:26