繁体   English   中英

使用 Pandas 的分组列的逐行累积平均值

[英]Row-wise Cumulative Mean Across Grouped Columns using Pandas

我想创建多个列来显示分组列的逐行累积平均值。 以下是一些示例数据:

import pandas as pd

data = [[1, 4, 6, 10, 15, 40, 90, 100], [2, 5, 3, 11, 25, 50, 90, 120], [3, 7, 9, 14, 35, 55, 100, 120]]
df = pd.DataFrame(data, columns=['a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'b3', 'b4'])

   a1  a2  a3  a4  b1  b2   b3   b4
0   1   4   6  10  15  40   90  100
1   2   5   3  11  25  50   90  120
2   3   7   9  14  35  55  100  120

我想要的是生成这样的新列:

  • 新列a1_2由列a1a2逐行计算。
  • 新列a1_3由列a1a2a3逐行计算。
  • 新列a1_4由列a1a2a3a4逐行计算。

对于带有b的分组列也应该发生同样的情况。 当然,您可以手动执行此操作,但是当您有太多变量时,这并不理想。 这是预期的 output:

df['a1_2'] = df[['a1', 'a2']].mean(axis=1)
df['a1_3'] = df[['a1', 'a2', 'a3']].mean(axis=1)
df['a1_4'] = df[['a1', 'a2', 'a3', 'a4']].mean(axis=1)
df['b1_2'] = df[['b1', 'b2']].mean(axis=1)
df['b1_3'] = df[['b1', 'b2', 'b3']].mean(axis=1)
df['b1_4'] = df[['b1', 'b2', 'b3', 'b4']].mean(axis=1)

   a1  a2  a3  a4  b1  b2   b3   b4  a1_2      a1_3  a1_4  b1_2       b1_3   b1_4
0   1   4   6  10  15  40   90  100   2.5  3.666667  5.25  27.5  48.333333  61.25 
1   2   5   3  11  25  50   90  120   3.5  3.333333  5.25  37.5  55.000000  71.25 
2   3   7   9  14  35  55  100  120   5.0  6.333333  8.25  45.0  63.333333  77.50  

所以我想知道是否有一些自动的方法可以做到这一点?

IIUC,您可以使用wide_to_long重塑形状,执行groupby.rolling ,然后取消unstack并展平多索引:

df.join(pd
   .wide_to_long(df.reset_index(), stubnames=['a', 'b'], i='index', j='n')
   .groupby(level='index').expanding().mean()
   .loc[lambda d: d.index.get_level_values('n')>1]
   .droplevel(0).unstack('n')
   .pipe(lambda d: d.set_axis(d.columns.map(lambda x: f'{x[0]}1_{x[1]}'), axis=1))
)

output:

   a1  a2  a3  a4  b1  b2   b3   b4  a1_2      a1_3  a1_4  b1_2       b1_3   b1_4
0   1   4   6  10  15  40   90  100   2.5  3.666667  5.25  27.5  48.333333  61.25
1   2   5   3  11  25  50   90  120   3.5  3.333333  5.25  37.5  55.000000  71.25
2   3   7   9  14  35  55  100  120   5.0  6.333333  8.25  45.0  63.333333  77.50

expanding.mean

for c in ('a', 'b'):
    m = df.filter(like=c).expanding(axis=1).mean().iloc[:, 1:]
    df[m.columns.str.replace(r'(\d+)$', r'1_\1', regex=True)] = m

结果

   a1  a2  a3  a4  b1  b2   b3   b4  a1_2      a1_3  a1_4  b1_2       b1_3   b1_4
0   1   4   6  10  15  40   90  100   2.5  3.666667  5.25  27.5  48.333333  61.25
1   2   5   3  11  25  50   90  120   3.5  3.333333  5.25  37.5  55.000000  71.25
2   3   7   9  14  35  55  100  120   5.0  6.333333  8.25  45.0  63.333333  77.50

另外的选择:

out = [value.expanding(axis=1).mean()
            .rename(columns = lambda col: f"{col[0]}1_{col[1]}") 
       for _, value in df.groupby(df.columns.str[0], axis = 1)]

pd.concat([df]+out, axis = 1)
   a1  a2  a3  a4  b1  b2   b3   b4  a1_1  a1_2      a1_3  a1_4  b1_1  b1_2       b1_3   b1_4
0   1   4   6  10  15  40   90  100   1.0   2.5  3.666667  5.25  15.0  27.5  48.333333  61.25
1   2   5   3  11  25  50   90  120   2.0   3.5  3.333333  5.25  25.0  37.5  55.000000  71.25
2   3   7   9  14  35  55  100  120   3.0   5.0  6.333333  8.25  35.0  45.0  63.333333  77.50
groups   = df.groupby(lambda col: col[0], axis=1)
cummeans = (groups.cumsum(axis=1).div(groups.cumcount().add(1))
                  .filter(regex="[^1]$")
                  .rename(lambda col: re.sub(r"(\d+)$", r"1_\1", col), axis=1))
result   = df.join(cummeans)
  • 获取由列的第一个字符确定的组(或其他方式取决于模式)

  • 获得累积均值 = cumsum / cumcount+1

  • 过滤掉第一个 cummeans,例如,to-be a1_1 等。

  • 在 cummean 列名中插入“1_”

  • 加入原始df

In [19]: groups = df.groupby(lambda col: col[0], axis=1)

In [20]: cummeans = groups.cumsum(axis=1).div(groups.cumcount().add(1))

In [21]: cummeans
Out[21]:
    a1   a2        a3    a4    b1    b2         b3     b4
0  1.0  2.5  3.666667  5.25  15.0  27.5  48.333333  61.25
1  2.0  3.5  3.333333  5.25  25.0  37.5  55.000000  71.25
2  3.0  5.0  6.333333  8.25  35.0  45.0  63.333333  77.50

In [22]: _.filter(regex="[^1]$")
Out[22]:
    a2        a3    a4    b2         b3     b4
0  2.5  3.666667  5.25  27.5  48.333333  61.25
1  3.5  3.333333  5.25  37.5  55.000000  71.25
2  5.0  6.333333  8.25  45.0  63.333333  77.50

In [23]: _.rename(lambda col: re.sub(r"(\d+)$", r"1_\1", col), axis=1)
Out[23]:
   a1_2      a1_3  a1_4  b1_2       b1_3   b1_4
0   2.5  3.666667  5.25  27.5  48.333333  61.25
1   3.5  3.333333  5.25  37.5  55.000000  71.25
2   5.0  6.333333  8.25  45.0  63.333333  77.50

In [24]: df.join(_)
Out[24]:
   a1  a2  a3  a4  b1  b2   b3   b4  a1_2      a1_3  a1_4  b1_2       b1_3   b1_4
0   1   4   6  10  15  40   90  100   2.5  3.666667  5.25  27.5  48.333333  61.25
1   2   5   3  11  25  50   90  120   3.5  3.333333  5.25  37.5  55.000000  71.25
2   3   7   9  14  35  55  100  120   5.0  6.333333  8.25  45.0  63.333333  77.50

作为“一”行:

df.join(df.groupby(lambda col: col[0], axis=1)
          .pipe(lambda gr: gr.cumsum(axis=1).div(gr.cumcount().add(1))
          .filter(regex="[^1]$")
          .rename(lambda col: re.sub(r"(\d+)$", r"1_\1", col), axis=1)))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM