使用Pandas构建一个新列,该列给出组中其他元素的平均值。

3
我希望通过使用Pandas来改善性能和代码优雅度,创建一个新的列,用于给出组内其他元素的平均值。
您可以将其视为每个日期的其他类型的平均值。
  • My original dataframe (df) is:

    idx = [np.array(['Jan-18', 'Jan-18', 'Feb-18', 'Mar-18', 'Mar-18', 'Mar-18','Mar-18', 'Mar-18', 'May-18', 'Jun-18', 'Jun-18', 'Jun-18','Jul-18', 'Aug-18', 'Aug-18', 'Sep-18', 'Sep-18', 'Oct-18','Oct-18', 'Oct-18', 'Nov-18', 'Dec-18', 'Dec-18',]),np.array(['A', 'B', 'B', 'A', 'B', 'C', 'D', 'E', 'B', 'A', 'B', 'C','A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'A', 'B', 'C'])]
    data = [{'xx': 1}, {'xx': 5}, {'xx': 3}, {'xx': 2}, {'xx': 7}, {'xx': 3},{'xx': 1}, {'xx': 6}, {'xx': 3}, {'xx': 5}, {'xx': 2}, {'xx': 3},{'xx': 1}, {'xx': 9}, {'xx': 3}, {'xx': 2}, {'xx': 7}, {'xx': 3}, {'xx': 6}, {'xx': 8}, {'xx': 2}, {'xx': 7}, {'xx': 9}]
    df = pd.DataFrame(data, index=idx, columns=['xx'])
    df.index.names=['date','type']
    df=df.reset_index()
    df['date'] = pd.to_datetime(df['date'],format = '%b-%y') 
    df=df.set_index(['date','type'])
    

我的代码如下:

df['avg'] = df.groupby('date').transform('mean')
df['N'] = (df.assign(TYPE = df.index.get_level_values('type')).groupby('date').TYPE.transform('nunique'))
df['zzz']= df['avg'].multiply(df['N'], axis=0)
df['hhh']= df['zzz']-df['xx']
df['yy'] = df['hhh'].div((df['N']-1))
del df['avg']
del df['N']
del df['zzz']
del df['hhh']

结果是:

                  xx    yy
date       type
2018-01-01 A     1.0  5.00
           B     5.0  1.00
2018-02-01 B     3.0   NaN
2018-03-01 A     2.0  4.25
           B     7.0  3.00
           C     3.0  4.00
           D     1.0  4.50
           E     6.0  3.25
2018-05-01 B     3.0   NaN
2018-06-01 A     5.0  2.50
           B     2.0  4.00
           C     3.0  3.50
2018-07-01 A     1.0   NaN
2018-08-01 B     9.0  3.00
           C     3.0  9.00
2018-09-01 A     2.0  7.00
           B     7.0  2.00
2018-10-01 C     3.0  7.00
           A     6.0  5.50
           B     8.0  4.50
2018-11-01 A     2.0   NaN
2018-12-01 B     7.0  9.00
           C     9.0  7.00

虽然我能够正确获取给定日期其他元素的平均值,但我认为 Pandas 必须有一种更清晰/更快速的方法来实现这一点。

欢迎提供任何改进代码的解决方案。谢谢!

2个回答

2

Here you go:

df['yy'] = (df.groupby('date').xx
              .apply(lambda x: (x.sum() - x)/(len(x) - 1))
           )

输出:

                xx  yy
date       type         
2018-01-01  A   1   5.00
            B   5   1.00
2018-02-01  B   3   NaN
2018-03-01  A   2   4.25
            B   7   3.00
            C   3   4.00
            D   1   4.50
            E   6   3.25
2018-05-01  B   3   NaN
2018-06-01  A   5   2.50
            B   2   4.00
            C   3   3.50
2018-07-01  A   1   NaN
2018-08-01  B   9   3.00
            C   3   9.00
2018-09-01  A   2   7.00
            B   7   2.00
2018-10-01  C   3   7.00
            A   6   5.50
            B   8   4.50
2018-11-01  A   2   NaN
2018-12-01  B   7   9.00
            C   9   7.00

优雅简洁 - run-out

1
我认为你的代码已经很好了。唯一需要做的是在单行中进行计算,不需要保存和删除中间列。
df['avg'] = df.groupby('date').transform('mean')
N = (df.assign(TYPE = df.index.get_level_values('type')).groupby('date').TYPE.transform('nunique'))
df['yy'] = (df['avg'].multiply(N, axis=0) - df['xx']).div(N-1)

这将给你最终结果。
N是一个单独的数据帧(如果您愿意,可以保留它,或者使用del N删除它),不需要删除其他列。
在性能方面,您有更少的赋值,因此速度应该稍微快一些(但可以忽略不计)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接