一次用于多列的 Pandas 数据透视表

Posted

技术标签:

【中文标题】一次用于多列的 Pandas 数据透视表【英文标题】:Pandas pivot table for multiple columns at once 【发布时间】:2017-10-25 05:25:16 【问题描述】:

假设我有一个 DataFrame:

   nj  ptype  wd  wpt
0   2      1   2    1
1   3      2   1    2
2   1      1   3    1
3   2      2   3    3
4   3      1   2    2

我想使用ptype 作为索引来聚合这些数据,如下所示:

             nj             wd            wpt
       1.0  2.0  3.0  1.0  2.0  3.0  1.0  2.0  3.0
ptype    
    1    1    1    1    0    2    1    2    1    0
    2    0    1    1    1    0    1    0    1    1

您可以通过使用aggfunc='count' 创建一个数据透视表,然后将它们全部连接起来,为最终值构建每个***列,如下所示:

nj = df.pivot_table(index='ptype', columns='nj', aggfunc='count').ix[:, 'wd']
wpt = df.pivot_table(index='ptype', columns='wpt', aggfunc='count').ix[:, 'wd']
wd = df.pivot_table(index='ptype', columns='wd', aggfunc='count').ix[:, 'nj']
out = pd.concat([nj, wd, wpt], axis=1, keys=['nj', 'wd', 'wpt']).fillna(0)
out.columns.names = [None, None]
print(out)
        nj             wd            wpt
         1    2    3    1    2    3    1    2    3
ptype
1      1.0  1.0  1.0  0.0  2.0  1.0  2.0  1.0  0.0
2      0.0  1.0  1.0  1.0  0.0  1.0  0.0  1.0  1.0

但我真的不喜欢这个,感觉不对。我想知道是否有一种方法可以以更简单的方式执行此操作,最好使用内置方法。提前致谢!

【问题讨论】:

【参考方案1】:

您可以先进行聚合,然后使用unstack 方法进行聚合,然后pivot 它:

(df.set_index('ptype')
 .groupby(level='ptype')
# to do the count of columns nj, wd, wpt against the column ptype using 
# groupby + value_counts
 .apply(lambda g: g.apply(pd.value_counts))
 .unstack(level=1)
 .fillna(0))

#      nj             wd            wpt
#       1    2    3    1    2    3    1    2    3
#ptype                                  
#1    1.0  1.0  1.0  0.0  2.0  1.0  2.0  1.0  0.0
#2    0.0  1.0  1.0  1.0  0.0  1.0  0.0  1.0  1.0

避免使用apply 方法的另一个选项:

(df.set_index('ptype').stack()
 .groupby(level=[0,1])
 .value_counts()
 .unstack(level=[1,2])
 .fillna(0)
 .sort_index(axis=1))

Naive Timing 样本数据:

原解决方案:

%%timeit
nj = df.pivot_table(index='ptype', columns='nj', aggfunc='count').ix[:, 'wd']
wpt = df.pivot_table(index='ptype', columns='wpt', aggfunc='count').ix[:, 'wd']
wd = df.pivot_table(index='ptype', columns='wd', aggfunc='count').ix[:, 'nj']
out = pd.concat([nj, wd, wpt], axis=1, keys=['nj', 'wd', 'wpt']).fillna(0)
out.columns.names = [None, None]
# 100 loops, best of 3: 12 ms per loop

选项一:

%%timeit
(df.set_index('ptype')
 .groupby(level='ptype')
 .apply(lambda g: g.apply(pd.value_counts))
 .unstack(level=1)
 .fillna(0))
# 100 loops, best of 3: 10.1 ms per loop

选项二:

%%timeit 
(df.set_index('ptype').stack()
 .groupby(level=[0,1])
 .value_counts()
 .unstack(level=[1,2])
 .fillna(0)
 .sort_index(axis=1))
# 100 loops, best of 3: 4.3 ms per loop

【讨论】:

绝对有效,但它似乎比我对约 80K 行数据框的解决方案慢。 @Grr 如果性能有问题,您可以尝试第二个选项,这似乎更快,因为它避免了循环(双 apply 方法)。 所以在终于回到这个问题时,我发现我偶尔会有一些数据具有唯一值 [1,2] 对于 nj 而不是 [1,2,3] 在这种情况下我觉得选项 1 更多信息丰富,因为它包括用零填充的值 3 的列。总而言之,它只比我原来的方法略长,但正如我所说,我觉得它包含更多信息。谢谢!【参考方案2】:

使用 groupby 和 unstack 的另一种解决方案。

df2 = pd.concat([df.groupby(['ptype',e])[e].count().unstack() for e in ['nj','wd','wpt']],axis=1).fillna(0).astype(int)    
df2.columns=pd.MultiIndex.from_product([['nj','wd','wpt'],[1.0,2.0,3.0]])

df2
Out[207]: 
       nj          wd         wpt        
      1.0 2.0 3.0 1.0 2.0 3.0 1.0 2.0 3.0
ptype                                    
1       1   1   1   0   2   1   2   1   0
2       0   1   1   1   0   1   0   1   1

【讨论】:

【参考方案3】:

一个更简单的解决方案是

employee.pivot_table(index= ‘Title’, values= “Salary”, aggfunc= [np.mean, np.median, min, max, np.std], fill_value=0)

在这种情况下,对于薪水列,我们使用不同的聚合函数

【讨论】:

以上是关于一次用于多列的 Pandas 数据透视表的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:排序数据透视表

Python:一次包含重复值的多个列的 Pandas 数据透视表

使用 Laravel 数据透视表的多行和多列输入表单

具有多列聚合的 SQL Server 数据透视表

具有多列日期的 SQL Server 数据透视表

Excel中数据透视选择了多列数据后,会出现一个表头,这个是啥原因,怎么删除啊。