【问题标题】:Subtract mean of columns grouped by one column减去按一列分组的列的平均值
【发布时间】:2019-05-29 01:42:47
【问题描述】:

我有一个 Pandas DataFrame,如下所示:

data = {'user_id':[1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3],
        'time':[10, 12, 11, 20, 40, 41, 42, 100, 60, 22, 0, 3],
        'height':[1.23, 1.1, 0.5, 10.3, 3.33, 4.55, 2.22, 2.21, 2.25, 7.75, 9.2, 5.5],
        'width':[3, 4, 6, 2, 4, 8, 9, 0, 6, 6, 6, 4]}
df = pd.DataFrame(data)

现在,我想从每一列(user_id 列除外)中减去按user_id 分组的平均值。这意味着对于user_id 1,time 的平均值为 13.25 ((10 + 12 + 11 + 20) / 4),因此从 10、12、11 和 20 中减去 13.25 导致

'time':[-3.25, -1.25, -2.25, 6.75, 40, 41, 42, 100, 60, 22, 0, 3]

我想为所有列和所有用户执行此操作。如何做到这一点?

【问题讨论】:

    标签: python pandas pandas-groupby


    【解决方案1】:

    您可以使用groupby.transform 创建一个与您的数据框形状相同的数组。然后从您的time 列中减去它:

    m = df.groupby('user_id')['time'].transform('mean')
    
    df['time'].add(-m)
    

    0     -3.25
    1     -1.25
    2     -2.25
    3      6.75
    4     -1.00
    5      0.00
    6      1.00
    7     63.00
    8     23.00
    9    -15.00
    10   -37.00
    11   -34.00
    Name: time, dtype: float64
    

    m 的输出结果为:

    print(m)
    
    0     13.25
    1     13.25
    2     13.25
    3     13.25
    4     41.00
    5     41.00
    6     41.00
    7     37.00
    8     37.00
    9     37.00
    10    37.00
    11    37.00
    Name: time, dtype: float64
    

    【讨论】:

    • 这与 OP 的输出不匹配!
    • 我只为 user_id 1 显示了时间列的输出,所以我认为它是匹配的
    • 这是否也可以应用于所有列(除了 user_id 列)而不明确说明每一列?
    • @machinery:检查我的答案
    • @shaikmoed 是正确的。 OP 的输出只显示一个减法。也可以写成:df.time -= df.groupby('user_id').time.transform('mean').
    【解决方案2】:

    这是你想要的吗?

    df[df.columns.difference(['user_id'])].sub(df.groupby('user_id').transform('mean'))
    

    来自@piRSquare:

    df.update(df - df.groupby('user_id').transform('mean'))
    

    df.loc[:, ['height', 'time', 'width']] -= df.groupby('user_id').transform('mean')    
    

    来自@anky_91:

    df.drop('user_id',1).sub(df.groupby('user_id').time.transform('mean'),axis=0)
    
    
    Out[2054]:
          height   time  width
    0  -2.052500  -3.25  -0.75
    1  -2.182500  -1.25   0.25
    2  -2.782500  -2.25   2.25
    3   7.017500   6.75  -1.75
    4  -0.036667  -1.00  -3.00
    5   1.183333   0.00   1.00
    6  -1.146667   1.00   2.00
    7  -3.172000  63.00  -4.40
    8  -3.132000  23.00   1.60
    9   2.368000 -15.00   1.60
    10  3.818000 -37.00   1.60
    11  0.118000 -34.00  -0.40
    

    【讨论】:

    • 是的,完全正确。我是否必须明确说明每一列,或者是否可以在不提供列名的情况下将其应用于除 user_id 列之外的所有列?
    • df.loc[:, ['height', 'time', 'width']] -= df.groupby('user_id').transform('mean')
    • 更简洁df.update(df - df.groupby('user_id').transform('mean'))
    • df.drop('user_id',1).sub(df.groupby('user_id').time.transform('mean'),axis=0)
    • @anky_91:很好。我从没想过在sub 之前放弃user_id。将您的答案添加到答案中:)。 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 2021-04-19
    • 2018-11-22
    相关资源
    最近更新 更多