Py学习  »  Python

如何在python中用mean(基于类别的mean)替换nan值[duplicate]

Raj • 4 年前 • 1159 次点击  

这应该很简单,但我发现最接近的是这篇文章: pandas: Filling missing values within a group ,我仍然无法解决我的问题…

假设我有以下数据帧

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”组的平均值,即

      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()

多谢。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/42973
 
1159 次点击  
文章 [ 8 ]  |  最新文章 4 年前
keith singleton
Reply   •   1 楼
keith singleton    6 年前

我刚做了这个

df.fillna(df.mean(), inplace=True)

数据框中所有缺少的值都将平均填充。如果这就是你要找的。这对我有效。很简单,就能完成任务。

Paul Roub Prateek Deshmukh
Reply   •   2 楼
Paul Roub Prateek Deshmukh    5 年前
df.fillna(df.groupby(['name'], as_index=False).mean(), inplace=True)
Prajit Patil
Reply   •   3 楼
Prajit Patil    8 年前
def groupMeanValue(group):
    group['value'] = group['value'].fillna(group['value'].mean())
    return group

dft = df.groupby("name").transform(groupMeanValue)
Philipp Schwarz
Reply   •   4 楼
Philipp Schwarz    7 年前

特色的高排名答案只适用于只有两列的熊猫数据框。如果有更多列的情况,请使用:

df['Crude_Birth_rate'] = df.groupby("continent").Crude_Birth_rate.transform(
    lambda x: x.fillna(x.mean()))
jpp
Reply   •   5 楼
jpp    5 年前

fillna + groupby + transform + mean

这似乎很直观:

df['value'] = df['value'].fillna(df.groupby('name')['value'].transform('mean'))

这个 子句 + 转型 语法将GroupWise平均值映射到原始数据帧的索引。这大致相当于 @DSM's solution ,但不需要定义匿名 lambda 功能。

IanS WeNYoBen
Reply   •   6 楼
IanS WeNYoBen    6 年前

我会这样做的

df.loc[df.value.isnull(), 'value'] = df.groupby('group').value.transform('mean')
André C. Andersen
Reply   •   7 楼
André C. Andersen    6 年前

@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子句中的列列表,我们选择 价值 列在“分组依据”之后。这使得转换只能在该特定列上运行。您可以将它添加到末尾,但随后您将对所有列运行它,只会在末尾抛出除一个度量值列以外的所有列。一个标准的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()))
DSM
Reply   •   8 楼
DSM    10 年前

一种方法是 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