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列
字符串添加到具有以下内容的值:
然后在列中通过-getMultiIndex
聚合和重塑:
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