我希望能够从可以多种方式分组的数据集中生成摘要统计信息和数据透视表。由于每个条目可以属于一个分类轴内的多个组,因此会出现复杂情况(参见下面的示例)。
到目前为止,我已经找到了一种基于多索引的解决方案,并且重复每个记录的次数与category1 * category2组合中出现的次数一样多。但是,这似乎不灵活(我需要检查条目是否出现在不同数据源的相同类别中,我可能想要添加另一个类别系统,称为category3,类别“d”可能会被添加到category1系统等)。而且,它似乎违背了数据库设计的基本原则。
我的问题是:除了我的解决方案之外,还有其他(更优雅,更灵活)解决此问题的方法吗?我可以设想保存各种表,一个包含实际数据,另一个包含分组信息(很像下面的堆栈表)并灵活地使用它们作为Groupby的输入,但我不知道这是否可行以及如何制作那工作。任何改进建议也欢迎。谢谢!
原始数据如下所示:
import pandas
data={'ID' : [1 , 2, 3, 4],
'year' : [2004, 2008 , 2006, 2009],
'money' : [10000 , 5000, 4000, 11500],
'categories1' : [ "a,b,c" , "c" , "a,c" , "" ],
'categories2' : ["one, two" , "one" , "five" , "eight"]}
df= pandas.DataFrame(data)
df.set_index('ID', inplace=True)
print df
给出了:
categories1 categories2 money year
ID
1 a,b,c one, two 10000 2004
2 c one 5000 2008
3 a,c five 4000 2006
4 eight 11500 2009
我希望能够制作如下所示的数据透视表:
Average money
year 2004 2005 2006 2007
category
a
b
c
还有:
Average money
category2 one two three four
category1
a
b
c
到目前为止,我有:
步骤1:使用get_dummies提取类别信息:
cat1=df['categories1'].str.get_dummies(sep=",")
print cat1
给出了:
a b c
ID
1 1 1 1
2 0 0 1
3 1 0 1
4 0 0 0
第2步:堆叠:
stack = cat1.stack()
stack.index.names=['ID', 'cat1']
stack.name='in_cat1'
print stack
给出了:
ID cat1
1 a 1
b 1
c 1
2 a 0
b 0
c 1
3 a 1
b 0
c 1
4 a 0
b 0
c 0
Name: in_cat1, dtype: int64
步骤3:将其连接到原始数据框以创建多索引数据框
dl = df.join(stack, how='inner')
print dl
看起来像这样:
categories1 categories2 money year in_cat1
ID cat1
1 a a,b,c one, two 10000 2004 1
b a,b,c one, two 10000 2004 1
c a,b,c one, two 10000 2004 1
2 a c one 5000 2008 0
b c one 5000 2008 0
c c one 5000 2008 1
3 a a,c five 4000 2006 1
b a,c five 4000 2006 0
c a,c five 4000 2006 1
4 a eight 11500 2009 0
b eight 11500 2009 0
c eight 11500 2009 0
步骤4:然后可以使用pandas groupby和pivot_table命令
dl.reset_index(level=1, inplace=True)
pt= dl.pivot_table(values='money', columns='year', index='cat1')
print pt
并做我想做的事:
year 2004 2006 2008 2009
cat1
a 10000 4000 5000 11500
b 10000 4000 5000 11500
c 10000 4000 5000 11500
我已经使用category2重复了步骤2 + 3,因此现在数据帧具有3级索引。
答案 0 :(得分:0)
我创建了一个带有DataFrame
和列名的函数。预计列名指定的列具有可以由','
拆分的字符串。它会将此拆分附加到具有适当名称的索引。
def expand_and_add(df, col):
expand = lambda x: pd.concat([x for i in x[col].split(',')], keys=x[col].split(','))
df = df.apply(expand, axis=1).stack(0)
df.index.levels[-1].name = col
df.drop(col, axis=1, inplace=1)
return df
现在这将有助于创建3层MultiIndex
。我相信操纵MultiIndex
提供了创建所需枢轴所需的所有灵活性。
new_df = expand_and_add(expand_and_add(df, 'categories1'), 'categories2')
看起来像:
money year
ID categories1 categories2
1 a two 10000.0 2004.0
one 10000.0 2004.0
b two 10000.0 2004.0
one 10000.0 2004.0
c two 10000.0 2004.0
one 10000.0 2004.0
2 c one 5000.0 2008.0
3 a five 4000.0 2006.0
c five 4000.0 2006.0
4 eight 11500.0 2009.0
你的枢轴仍然会个别凌乱,但这里有一些。
new_df.set_index(ndf.year.astype(int), append=True)['money'].groupby(level=[1, 3]).mean().unstack()
year 2004 2006 2008 2009
categories1
NaN NaN NaN 11500.0
a 10000.0 4000.0 NaN NaN
b 10000.0 NaN NaN NaN
c 10000.0 4000.0 5000.0 NaN
new_df.groupby(level=[1, 2])['money'].mean().unstack()
categories2 two eight five one
categories1
NaN 11500.0 NaN NaN
a 10000.0 NaN 4000.0 10000.0
b 10000.0 NaN NaN 10000.0
c 10000.0 NaN 4000.0 7500.0