如何规范熊猫多索引数据框?

时间:2020-07-07 18:10:47

标签: pandas pandas-groupby

我对标准化分组数据框中的计数有疑问。

我的数据如下:

import pandas as pd

data = [{'system': 'S1', 'id': '1', 'output': ['apple', 'pear']},
    {'system': 'S1', 'id': '2', 'output': []},
    {'system': 'S1', 'id': '3', 'output': []},
    {'system': 'S2', 'id': '4', 'output': ['apple', 'grape']},
    {'system': 'S2', 'id': '5', 'output': ['apple']}] 

df = pd.DataFrame(data) 

以表格格式显示如下:

  system id          output
0     S1  1   [apple, pear]
1     S1  2              []
2     S1  3              []
3     S2  4  [apple, grape]
4     S2  5         [apple]

如何获得每个系统每个输出的归一化计数?

它应该像这样:

system  output  perc
S1      apple   0.33
S1      pear    0.33
S2      apple   1.0
S2      grape   0.5
 

意味着applepear出现在所有S1输出的三分之一中,apple出现在所有S2输出中,grape出现S2输出的一半。

我试图爆炸每个系统的输出并获得每个系统ID的单独计数,但是合并它们会丢失output列:

outputs = df.explode('output').groupby(['system', 'output']).count()                                                                                                                                        
counts = df.groupby('system').agg('count').id
pd.merge(outputs, counts, on="system")

2 个答案:

答案 0 :(得分:1)

对于0.25+的熊猫,我们可以使用explode

(df.explode('output')
   .groupby('system')
   .apply(lambda x:x['output'].value_counts()/x['id'].nunique())
   .reset_index()
)

输出:

  system level_1    output
0     S1    pear  0.333333
1     S1   apple  0.333333
2     S2   apple  1.000000
3     S2   grape  0.500000

答案 1 :(得分:1)

IIUC,SeriesGroupBy.value_counts()Serives.value_counts()Series.map()

new_df = (df.explode('output').groupby('system')['output'].value_counts()
           .reset_index(name='perc')
           .assign(perc=lambda x: x['perc'].div(x['system']\
                                                .map(df['system'].value_counts()))))
print(new_df)

  system output      perc
0     S1  apple  0.333333
1     S1   pear  0.333333
2     S2  apple  1.000000
3     S2  grape  0.500000

示例数据框的时间

%%timeit

new_df = (df.explode('output').groupby('system')['output'].value_counts()
           .reset_index(name='perc')
           .assign(perc=lambda x: x['perc'].div(x['system']\
                                                .map(df['system'].value_counts()))))


9.19 ms ± 64.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
(df.explode('output')
   .groupby('system')
   .apply(lambda x:x['output'].value_counts()/x['id'].nunique())
   .reset_index()
)
12.3 ms ± 134 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)