【问题标题】:How to replace 0 values with mean based on groupby如何用基于groupby的平均值替换0值
【发布时间】:2018-12-13 20:33:34
【问题描述】:

我有一个具有两个特征的数据框: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 伊林加 3 250 伊林加 ...

【问题讨论】:

    标签: python pandas replace transform


    【解决方案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 替换为缺失值,然后将NANs 替换为fillna,将means 替换为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
    

    【讨论】:

    • 两个非常好的解决方案!但是,gps_height 的 NaN 值仍然存在,没有被替换。
    • @NielsHoogeveen - 你能添加数据样本吗?缺失值为NaNs?
    • 缺失值为 0,如您所说,我将它们替换为 NaN。完美运行。但是第二步不行。我预计 gps_height 的行数是 NaN,但我仍然在这些行上得到 NaN。
    • @NielsHoogeveen - 也许NaNs 是字符串,尝试df['gps_height'] = pd.to_numeric(df['gps_height'], errors='coerce') 作为第一步解决方案。它将非数字替换为 NaN。
    • 如果这里groupby多列,我该如何修改这一行:df['gps_height'] = np.where(~m, df['region'].map(s), df['gps_height'])
    【解决方案2】:

    我最终遇到了@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
    • 最后用这个子集更新dfC 中没有零。
    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-19
      • 2018-12-02
      • 2023-03-08
      • 2021-05-11
      • 2013-04-01
      • 2019-03-21
      • 2018-02-05
      相关资源
      最近更新 更多