【问题标题】:How to sum or count groups of multiple columns in pandas如何对熊猫中的多列组进行求和或计数
【发布时间】:2023-03-25 00:54:01
【问题描述】:

我正在尝试对多组列进行分组,以计算或汇总 pandas 数据框中的行

我已经检查了很多问题,我发现最相似的是这个 >Groupby sum and count on multiple columns in python,但是,据我所知,我必须做很多步骤才能达到我的目标。并且也在看这个link

例如,我有下面的数据框:

import numpy as np
df = pd.DataFrame(np.random.randint(0,5,size=(5, 7)), columns=["grey2","red1","blue1","red2","red3","blue2","grey1"])

     grey2   red1 blue1 red2 red3 blue2 grey1
0       4      3    0      2    4   0   2
1       4      2    0      4    0   3   1
2       1      1    3      1    1   3   1
3       4      4    1      4    1   1   1
4       3      4    1      0    3   3   1

我想在这里对所有列按颜色分组,例如,我期望的是:

如果我把数字相加,

blue  15
grey  22
red   34

如果我数 (x > 0) 那么我会得到,

  blue  7
  grey  10
  red   13

这是我迄今为止所取得的成就,所以现在我必须求和,然后用结果创建一个数据框,但如果我有 100 个组,这将非常耗时。

pd.pivot_table(data=df, index=df.index, values=["red1","red2","red3"], aggfunc='sum', margins=True)
   red1  red2   red3
0    3     2    4
1    2     4    0
2    1     1    1
3    4     4    1
4    4     0    3
ALL  14   11    9

pd.pivot_table(data=df, index=df.index, values=["red1","red2","red3"], aggfunc='count', margins=True)

但这里也算零:

     red1 red2  red3
   0    1   1   1
   1    1   1   1
   2    1   1   1
   3    1   1   1
   4    1   1   1
  All   5   5   5

不知道如何改变函数来获得我的结果,我已经花了几个小时,希望你能提供帮助。

注意: 我在这个例子中只使用颜色来简化案例,但我可以有很多列,它们被称为 col001 到 col300,等等...... 因此,这些组可能是:

blue = col131, col254, col005
red =  col023, col190, col053

等等……

【问题讨论】:

  • df.groupby(df.columns.str.replace('\d+', ''),axis=1).sum().sum()

标签: python pandas


【解决方案1】:

你可以使用pd.wide_to_long:

data= pd.wide_to_long(df.reset_index(), stubnames=['grey','red','blue'], 
                i='index',
                j='group',
                sep=''
               )

输出:

# data
             grey  red  blue
index group                 
0     1       2.0    3   0.0
      2       4.0    2   0.0
      3       NaN    4   NaN
1     1       1.0    2   0.0
      2       4.0    4   3.0
      3       NaN    0   NaN
2     1       1.0    1   3.0
      2       1.0    1   3.0
      3       NaN    1   NaN
3     1       1.0    4   1.0
      2       4.0    4   1.0
      3       NaN    1   NaN
4     1       1.0    4   1.0
      2       3.0    0   3.0
      3       NaN    3   NaN

还有:

data.sum()
# grey    22.0
# red     34.0
# blue    15.0
# dtype: float64

data.gt(0).sum()
# grey    10
# red     13
# blue     7
# dtype: int64

更新 wide_to_long 只是mergerename 的便捷快捷方式。所以如果你有一本字典{cat:[col_list]},你可以解决这个问题:

groups = {'blue' : ['col131', 'col254', 'col005'],
          'red' : ['col023', 'col190', 'col053']}

# create the inverse dictionary for mapping
inv_group = {v:k for k,v in groups.items()}

data = df.melt()

# map the original columns to group
data['group'] = data['variable'].map(inv_group)

# from now on, it's similar to other answers
# sum
data.groupby('group')['value'].sum()

# count
data['value'].gt(0).groupby(data['group']).sum()

【讨论】:

  • 谢谢 我从来没有听说过这个函数,我只是用颜色来命名列,但是如果用随机名称调用列怎么办,我可以在存根名称中使用字典吗?
【解决方案2】:

这里的复杂之处在于您希望同时按行列折叠,这通常很难同时做到。我们可以melt 将您的宽格式转换为更长的格式,然后将问题减少到单个groupby

# Get rid of the numbers + reshape
df.columns = pd.Index(df.columns.str.rstrip('0123456789'), name='color')
df = df.melt()

df.groupby('color').sum()
#       value
#color       
#blue      15
#grey      22
#red       34

df.value.gt(0).groupby(df.color).sum()
#color
#blue     7.0
#grey    10.0
#red     13.0
#Name: value, dtype: float64

对于不太容易分组的名称,我们需要在某处进行映射,步骤非常相似:

# Unnecessary in this case, but more general
d = {'grey1': 'color_1', 'grey2': 'color_1', 
     'red1': 'color_2', 'red2': 'color_2', 'red3': 'color_2',
     'blue1': 'color_3', 'blue2': 'color_3'}

df.columns = pd.Index(df.columns.map(d), name='color')
df = df.melt()
df.groupby('color').sum()

#         value
#color         
#color_1     22
#color_2     34
#color_3     15

【讨论】:

  • 哇,现在看起来很简单,因为我刚刚使用颜色来命名列,但是如果用随机名称调用列怎么办,也许我可以准备一本字典,说明它们需要如何命名被分组。例如:蓝色 = col001, col134, col567 红色 = col876, col324, col9876
  • @VMEscoli 上面仍然会将这三个分组,因为rstrip 会将所有数字都删除到右侧,所以这三个都将变为'col'。但是,如果您需要进行一些分组,例如 col001, col134, col56 然后 col002, col007, col131 ,那么显然我的选择将不起作用。在这种情况下,您需要准备字典 d ={'col001': 'label1', 'col134': 'label1', ...} 并将第一步替换为 = ... df.columns.map(d) ... 如果分组确实没有简单的模式,那么您将不得不写出字典
【解决方案3】:

用途:

df.groupby(df.columns.str.replace('\d+', ''),axis=1).sum().sum()

输出:

blue    15
grey    22
red     34
dtype: int64

无论列名中包含多少位数,这都有效:

df=df.add_suffix('22')
print(df)

   grey22222  red12222  blue12222  red22222  red32222  blue22222  grey12222
0          4         3          0         2         4          0          2
1          4         2          0         4         0          3          1
2          1         1          3         1         1          3          1
3          4         4          1         4         1          1          1
4          3         4          1         0         3          3          1

df.groupby(df.columns.str.replace('\d+', ''),axis=1).sum().sum()
blue    15
grey    22
red     34
dtype: int64

【讨论】:

    【解决方案4】:

    对于一般情况,您也可以这样做:

    colors = {'blue':['blue1','blue2'], 'red':['red1','red2','red3'], 'grey':['grey1','grey2']}
    orig_columns = df.columns
    df.columns = [key for col in df.columns for key in colors.keys() if col in colors[key]]
    print(df.groupby(level=0,axis=1).sum().sum())
    df.columns = orig_columns
    

    【讨论】:

      猜你喜欢
      • 2017-05-01
      • 2021-07-20
      • 1970-01-01
      • 2020-08-10
      • 2016-10-21
      • 1970-01-01
      • 2013-11-16
      • 2023-02-14
      • 1970-01-01
      相关资源
      最近更新 更多