一次运行即可通过不同的键对熊猫数据框进行分区

时间:2019-06-26 21:00:05

标签: python pandas

在SQL中,借助OLAP函数,我们可以一次性计算不同的键,从而提高了SQL性能:

select 
B, 
C,
D,
count(A) over (partition by B, C, D order by D) as by_BCD.
count(A) over (partition by B, C order by D) as by_BC,
count(A) over (partition by B order by D) as by_B,
count(A) over () as total,
from table;

我们可以在一次熊猫数据帧扫描中执行相同的操作,而不是按数据帧分组3次吗?

Input dataset:

A   B   C   D
1   LZ  0   1
2   LZ  0   1
3   LZ  1   1
4   LZ  1   2 
5   LZ  1   2
6   SB  0   1
7   SB  0   1
8   SB  1   1
9   SB  1   2
10  SB  1   2
11   PZ  0   1


Output dataset:

A   B   C   D   by_BCD   by_BC   by_B   total
1   LZ  0   1     2        2      5      11
2   LZ  0   1     2        2      5      11
3   LZ  1   1     1        3      5      11 
4   LZ  1   2     2        3      5      11
5   LZ  1   2     2        3      5      11
6   SB  0   1     2        2      5      11
7   SB  0   1     2        2      5      11
8   SB  1   1     1        3      5      11
9   SB  1   2     2        3      5      11
10  SB  1   2     2        3      5      11
11  PZ  0   1     1        1      1      11

以下是代码段:

d = {'A': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
     'B': ['LZ', 'LZ', 'LZ', 'LZ', 'LZ', 'SB', 'SB', 'SB', 'SB', 'SB', 'PZ'],
     'C': [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
     'D': [1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1]}
df = pd.DataFrame(d)

1 个答案:

答案 0 :(得分:0)

在上面的评论中,我建议使用Multiindex

我的假设是,性能损失源于group by语句中的隐式索引。

按照OP所述创建df:

import pandas as pd

d = {'A': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
     'B': ['LZ', 'LZ', 'LZ', 'LZ', 'LZ', 'SB', 'SB', 'SB', 'SB', 'SB', 'PZ'],
     'C': [0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0],
     'D': [1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1]}
df = pd.DataFrame(d)

排序并创建Multiindex。为了使DataFrame.groupby的性能更好,排序就足够了。我没有尝试过。

indexed = df.sort_values(['B', 'C', 'D']).set_index(['B', 'C', 'D'])

这将产生:

         A                                                                                                                                                                                    
B  C D                                                                                                                                                                                        
LZ 0 1   1                                                                                                                                                                                    
     1   2                                                                                                                                                                                    
   1 1   3                                                                                                                                                                                    
     2   4                                                                                                                                                                                    
     2   5                                                                                                                                                                                    
PZ 0 1  11                                                                                                                                                                                    
SB 0 1   6                                                                                                                                                                                    
     1   7                                                                                                                                                                                    
   1 1   8                                                                                                                                                                                    
     2   9                                                                                                                                                                                    
     2  10    

为单行选择计数:

indexed.loc['LZ', 0, 1].count()  # 2

分组和计数,例如在“ BC”上方:

indexed.groupby(['B', 'C']).count()

产量:

      A                                                                                                                                                                                       
B  C                                                                                                                                                                                          
LZ 0  2                                                                                                                                                                                       
   1  3                                                                                                                                                                                       
PZ 0  1                                                                                                                                                                                       
SB 0  2                                                                                                                                                                                       
   1  3   

如上所述,我对性能的假设只是假设。