如何基于groupby用平均值替换0值

时间:2018-07-05 11:16:54

标签: python pandas replace transform

我有一个具有两个功能的数据框:gps_height(数字)和区域(分类)。

gps_height包含很多0值,在这种情况下,它们是缺少的值。我想用相干区域的平均值填充0值。

我的推理如下: 1.删​​除零值并取gps_height的平均值,按区域分组

df[df.gps_height !=0].groupby(['region']).mean()

但是如何用这些平均值替换数据框中的零值?

样本数据:

gps_height区域 0 1390伊林加 1 1400马拉 2 0伊林加 3250伊林加 ...

2 个答案:

答案 0 :(得分:1)

使用:

df = pd.DataFrame({'region':list('aaabbbccc'),
                   'gps_height':[2,3,0,3,4,5,1,0,0]})
print (df)
  region  gps_height
0      a           2
1      a           3
2      a           0
3      b           3
4      b           4
5      b           5
6      c           1
7      c           0
8      c           0

0替换为缺失的值,然后将NAN替换为fillna,将mean替换为GroupBy.transform每组:

df['gps_height'] = df['gps_height'].replace(0, np.nan)
df['gps_height']=df['gps_height'].fillna(df.groupby('region')['gps_height'].transform('mean'))
print (df)
  region  gps_height
0      a         2.0
1      a         3.0
2      a         2.5
3      b         3.0
4      b         4.0
5      b         5.0
6      c         1.0
7      c         1.0
8      c         1.0

或过滤掉0个值,汇总means并映射所有0行:

m = df['gps_height'] != 0
s = df[m].groupby('region')['gps_height'].mean()
df.loc[~m, 'gps_height'] = df['region'].map(s)
#alternative
#df['gps_height'] = np.where(~m, df['region'].map(s), df['gps_height'])
print (df)
  region  gps_height
0      a         2.0
1      a         3.0
2      a         2.5
3      b         3.0
4      b         4.0
5      b         5.0
6      c         1.0
7      c         1.0
8      c         1.0

答案 1 :(得分:1)

我最终遇到了@ahbon提出的相同问题:如果要分组的列超过一个,该怎么办?这是我发现的最接近我的问题的问题。经过认真的斗争,我找到了解决方案。

据我所知(有pandas个特定的功能可以做类似的事情)这可能不是一种优雅/正统的功能,所以我希望得到一些反馈。

发生了什么

import pandas as pd
import random

random.seed(123)
df = pd.DataFrame({"A":list('a'*4+'b'*4+'c'*4+'d'*4),
                  "B":list('xy'*8),
                  "C":random.sample(range(17), 16)})
print(df)

    A  B   C
0   a  x   1
1   a  y   8
2   a  x  16
3   a  y  12
4   b  x   6
5   b  y   4
6   b  x  14
7   b  y   0
8   c  x  13
9   c  y   5
10  c  x   2
11  c  y   9
12  d  x  10
13  d  y  11
14  d  x   3
15  d  y  15

首先获取0值的索引以检索非零数据并按组获取均值。

idx = list(df[df["C"] != 0].index)
data_to_group = df.iloc[idx,]
grouped_data = pd.DataFrame(data_to_group.groupby(["A", "B"])["C"].mean())

现在是棘手的部分。这是给我的印象,它可能是一种更优雅的解决方案:

  • 堆叠,卸载并重置索引
  • 然后与df中的行子集合并,其中C0;从第一个删除C,从第二个删除C
  • 最后更新df的子集,其中C中没有零。
grouped_data = grouped_data.stack().unstack().reset_index()
zero_rows = df[df.C == 0]
zero_rows_replaced = pd.merge(left = zero_rows, right = grouped_data, 
                              how = "left", on=["A", "B"],
                              suffixes=('_x','')).drop('C_x', axis=1)
zero_rows_replaced = zero_rows_replaced.set_index(zero_rows.index.copy())
df.update(zero_rows_replaced)
print(df)

    A  B   C
0   a  x   1
1   a  y   8
2   a  x  16
3   a  y  12
4   b  x   6
5   b  y   4
6   b  x  14
7   b  y   4
8   c  x  13
9   c  y   5
10  c  x   2
11  c  y   9
12  d  x  10
13  d  y  11
14  d  x   3
15  d  y  15