【问题标题】:Replacing values with groupby means用 groupby 方法替换值
【发布时间】:2013-01-23 12:31:09
【问题描述】:

我有一个 DataFrame,其中有一列包含一些带有各种负值的不良数据。我想用它们所在组的平均值替换

对于作为 NA 的缺失值,我会这样做:

data = df.groupby(['GroupID']).column
data.transform(lambda x: x.fillna(x.mean()))

但是如何在x < 0这样的条件下执行此操作?

谢谢!

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    使用@AndyHayden 的示例,您可以使用groupby/transformreplace

    df = pd.DataFrame([[1,1],[1,-1],[2,1],[2,2]], columns=list('ab'))
    print(df)
    #    a  b
    # 0  1  1
    # 1  1 -1
    # 2  2  1
    # 3  2  2
    
    data = df.groupby(['a'])
    def replace(group):
        mask = group<0
        # Select those values where it is < 0, and replace
        # them with the mean of the values which are not < 0.
        group[mask] = group[~mask].mean()
        return group
    print(data.transform(replace))
    #    b
    # 0  1
    # 1  1
    # 2  1
    # 3  2
    

    【讨论】:

    • 我在想类似的事情——.transform(lambda x: x.where(x&gt;=0).fillna(x[x&gt;=0].mean())) 但不喜欢这种情况的重复。您的方法很好地绕过了这一点。这种模式似乎很常见,我想知道pandas 是否应该发展一种内置的方式来支持它。
    • @DSM 我同意很高兴看到一些方法来做到这一点(这个 numpy-foo 令人印象深刻!):)
    • 非常好。我还没有看到 [~mask] 的用法 - tilda 只是表示not mask 吗?
    • @zach: mask 是一个 Series,它是 numpy 的 ndarray 类的子类。当应用于 numpy ndarray 时,波浪号是 invert operator。由于 mask 是 dtype bool (即布尔数组),因此对数组中的每个元素按位进行反转。 not mask 有不同的含义。这要求 Python 将 mask 作为一个整体对象减少到其布尔值,然后取反。 Numpy 数组拒绝被描述为 True 或 False。 not mask 引发 ValueError
    • 警告词:您的自定义函数不应就地修改组。它应该制作一个副本,然后对其进行修改。见pandas.pydata.org/docs/reference/api/…
    【解决方案2】:

    这是一种方法(对于'b' 列,在这个无聊的示例中):

    In [1]: df = pd.DataFrame([[1,1],[1,-1],[2,1],[2,2]], columns=list('ab'))
    In [2]: df
    Out[2]: 
       a  b
    0  1  1
    1  1 -1
    2  2  1
    3  2  2
    

    用 NaN 替换那些负值,然后计算每组的平均值 (b):

    In [3]: df['b'] = df.b.apply(lambda x: x if x>=0 else pd.np.nan)
    In [4]: m = df.groupby('a').mean().b
    

    然后在每一行中使用apply,将每个 NaN 替换为其组均值:

    In [5]: df['b'] = df.apply(lambda row: m[row['a']]
                                           if pd.isnull(row['b'])
                                           else row['b'],
                               axis=1) 
    In [6]: df
    Out[6]: 
       a  b
    0  1  1
    1  1  1
    2  2  1
    3  2  2
    

    【讨论】:

    • 我明白了,通过应用那个 lambda 函数,我可以让它们成为 nans!那么我不能只使用我在问题中写的.fillna 行吗?你的第二个.apply 似乎没有必要。
    • @Def_Os 我无法让这条线为我工作,但也许这是一个更好的方法:)
    【解决方案3】:

    对于您的附加问题,有一个很好的示例。

    df = pd.DataFrame({'A' : [1, 1, 2, 2], 'B' : [1, -1, 1, 2]})
    gb = df.groupby('A')
    def replace(g):
       mask = g < 0
       g.loc[mask] = g[~mask].mean()
       return g
    gb.transform(replace)
    

    链接:http://pandas.pydata.org/pandas-docs/stable/cookbook.html

    【讨论】:

    • 啊,我明白了。您的答案不能推广到更复杂的数据框。没关系,很聪明!我会继续玩。
    【解决方案4】:

    我遇到了同样的问题,想出了一个相当简单的解决方案

    func = lambda x : np.where(x < 0, x.mean(), x)
    
    df['Bad_Column'].transform(func)
    

    请注意,如果您想返回正确值的平均值(仅基于正值的平均值),您必须指定:

    func = lambda x : np.where(x < 0, x.mask(x < 0).mean(), x)
    

    【讨论】:

      猜你喜欢
      • 2019-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-16
      • 2018-12-13
      • 2021-01-19
      相关资源
      最近更新 更多