Python 什么样的操作可以帮助我进行groupby和aggregate by column组合?

Python 什么样的操作可以帮助我进行groupby和aggregate by column组合?,python,pandas,group-by,pivot-table,Python,Pandas,Group By,Pivot Table,下面是我正在尝试做的一个例子: bar foo o1 o2 thing 0 1 1 0.0 3.3 a 1 1 1 1.1 4.4 a 2 3 2 2.2 5.5 b foo_1_bar_3_o1 foo_1_bar_3_o2 foo_2_bar_3_o1 foo_2_bar_3_o2 \ 0 NaN NaN NaN

下面是我正在尝试做的一个例子:

   bar  foo   o1   o2 thing
0    1    1  0.0  3.3     a
1    1    1  1.1  4.4     a
2    3    2  2.2  5.5     b
   foo_1_bar_3_o1  foo_1_bar_3_o2  foo_2_bar_3_o1  foo_2_bar_3_o2  \
0             NaN             NaN             NaN             NaN   
1             NaN             NaN             2.2             5.5   

   foo_1_bar_1_o1  foo_1_bar_1_o2  foo_2_bar_1_o1  foo_2_bar_1_o2 thing  
0             1.1             7.7             NaN             NaN     a  
1             NaN             NaN             NaN             NaN     b  
第一个是我的输入数据帧,第二个是我想要的输出数据帧(
NaN
s可以用0代替)

这应该是某种groupby(在
thing
列上),然后是对
o1
o2
列中的值的某种聚合函数,该函数基于
foo
bar
的所有可能值组合进行聚合。请注意,
foo\u 1\u bar\u 2\u o2
是7.7,因为它是组“a”的
foo==1和&bar==2时,
o2
列上的总和

我曾尝试在
pandas
中研究
dcast
crosstab
pivot
,但似乎没有一个能满足我的要求

我编写的基本Python代码实现了我想要的功能,但是,我想再次使用现有函数将其转换为更友好的格式。我不认为我的用例不够模糊,不可能做到这一点

下面是此操作的基本Python代码

import pandas as pd
import numpy as np
import itertools

df = pd.DataFrame({'thing': ['a', 'a', 'b'], 
                   'foo': [1, 1, 2], 
                   'bar': [1, 1, 3], 
                   'o1': [0.0, 1.1, 2.2], 
                   'o2': [3.3, 4.4, 5.5]})

key_columns = ['foo', 'bar']

key_value_pairs = [df[key].values.tolist() for key in key_columns]

key_value_pairs = list(set(itertools.product(*key_value_pairs)))

output_columns = ['o1', 'o2']

def aggregate(df):
  new_columns = []
  for pair in key_value_pairs:
    pair = list(zip(key_columns, pair))
    new_column = '_'.join(['%s_%d' % (key, value) for key, value in pair])
    for o in output_columns:
      criteria = list()
      for key, value in pair:
        criterion = (df[key] == value)
        criteria.append(criterion)
      new_columns.append('%s_%s' % (new_column, o))
      df[new_columns[-1]] = df[np.logical_and.reduce(criteria)][o].sum()
  return df.head(1)[new_columns + ['thing']]

things = df['thing'].value_counts().index.tolist()

groups = df.groupby('thing')

dfs = []
for thing in things:
  dfs.append(aggregate(groups.get_group(thing).reset_index()))
  #print(aggregate(groups.get_group(thing).reset_index(drop=True)))

print(df)
print(pd.concat(dfs).reset_index(drop=True))

我认为您仍然必须使用
itertools.product()
,因为Pandas的设计目的不是考虑不存在的数据。但一旦定义了这些额外的组合,就可以使用
groupby()
unstack()
来获得所需的输出

使用您定义的
键值对

for k,v in key_value_pairs:
    if not len(df.loc[df.foo.eq(k) & df.bar.eq(v)]):
        df = df.append({"foo":k, "bar":v, "o1":np.nan, "o2":np.nan, "thing":"a"}, ignore_index=True)
        df = df.append({"foo":k, "bar":v, "o1":np.nan, "o2":np.nan, "thing":"b"}, ignore_index=True)

df
   bar  foo   o1   o2 thing
0    1    1  0.0  3.3     a
1    1    1  1.1  4.4     a
2    3    2  2.2  5.5     b
3    3    1  NaN  NaN     a
4    3    1  NaN  NaN     b
5    1    2  NaN  NaN     a
6    1    2  NaN  NaN     b
现在
groupby
unstack

gb = df.groupby(["thing", "foo", "bar"]).sum().unstack(level=[1,2])
gb.columns = [f"foo_{b}_bar_{c}_{a}" for a,b,c in gb.columns]
输出:

       foo_1_bar_1_o1  foo_1_bar_3_o1  foo_2_bar_1_o1  foo_2_bar_3_o1  \
thing                                                                   
a                 1.1             NaN             NaN             NaN   
b                 NaN             NaN             NaN             2.2   

       foo_1_bar_1_o2  foo_1_bar_3_o2  foo_2_bar_1_o2  foo_2_bar_3_o2  
thing                                                                  
a                 7.7             NaN             NaN             NaN  
b                 NaN             NaN             NaN             5.5  

我尝试创建动态解决方案:

key_columns = ['foo', 'bar']
output_columns = ['o1', 'o2']
首先将
key\u列
字符串添加到具有以下内容的值:

然后在列中通过-get
MultiIndex
聚合和重塑:

df = df.groupby(['thing'] + key_columns)[output_columns].sum().unstack(key_columns)
print (df)
         o1          o2      
bar   bar_1 bar_3 bar_1 bar_3
foo   foo_1 foo_2 foo_1 foo_2
thing                        
a       1.1   NaN   7.7   NaN
b       NaN   2.2   NaN   5.5
通过为创建所有可能的组合,然后和:

最后通过
map
join
删除
multi-index

df.columns = df.columns.map('_'.join)
df = df.reset_index()
print (df)
  thing  foo_1_bar_1_o1  foo_1_bar_1_o2  foo_1_bar_3_o1  foo_1_bar_3_o2  \
0     a             1.1             7.7             NaN             NaN   
1     b             NaN             NaN             NaN             NaN   

   foo_2_bar_1_o1  foo_2_bar_1_o2  foo_2_bar_3_o1  foo_2_bar_3_o2  
0             NaN             NaN             NaN             NaN  
1             NaN             NaN             2.2             5.5  

那是一只强壮的熊猫。
mux = pd.MultiIndex.from_product(df.columns.levels, names=df.columns.names)
print (mux)
MultiIndex(levels=[['o1', 'o2'], ['foo_1', 'foo_2'], ['bar_1', 'bar_3']],
           labels=[[0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 1, 1, 0, 0, 1, 1],
                   [0, 1, 0, 1, 0, 1, 0, 1]],
           names=[None, 'foo', 'bar'])


df = df.reindex(columns=mux).reorder_levels(key_columns + [None], axis=1).sort_index(axis=1)
df.columns = df.columns.map('_'.join)
df = df.reset_index()
print (df)
  thing  foo_1_bar_1_o1  foo_1_bar_1_o2  foo_1_bar_3_o1  foo_1_bar_3_o2  \
0     a             1.1             7.7             NaN             NaN   
1     b             NaN             NaN             NaN             NaN   

   foo_2_bar_1_o1  foo_2_bar_1_o2  foo_2_bar_3_o1  foo_2_bar_3_o2  
0             NaN             NaN             NaN             NaN  
1             NaN             NaN             2.2             5.5