【问题标题】:Pandas Pivot Table with Fancy Stacking带有花式堆叠的 Pandas 数据透视表
【发布时间】:2016-09-11 17:40:32
【问题描述】:

给定以下数据框:

results = pd.DataFrame({'Contractor':[1,1,0,0,0,1],
                    'President':[1,0,0,0,1,1],
                   'Item 1':[1,1,0,0,1,np.nan],
                   'Item 2':[1,0,0,1,0,1]})
results[['Contractor','President','Item 1','Item 2']]

results

    Contractor  President   Item 1  Item 2
0        1          1       1       1
1        1          0       1       0
2        0          0       0       0
3        0          0       0       1
4        0          1       1       0
5        1          1       NaN     1

这个供参考的项目(见下文):

    Position    Item(s)
0   Contractor  1
1   President   1,2

...我想对数据进行透视以产生这个:

    Position    Overall%
0   Contractor  100
1   President   80

...基于这个逻辑:

由于总统关心第 1 项和第 2 项,因此需要考虑 5 个数字:第 1 项中的(1 和 1)和第 2 项中的(1、0 和 1)。项目总和 为 4,跨项计数 为 5(不计算 'NaN'),即为 80%。

由于承包商只关心项目 1,因此需要考虑 2 个数字:1 和 1 - 不应计算“NaN” - (分别来自感兴趣的行)。因此,总和是计数中的 2,即 2,即为 100%

提前致谢!

【问题讨论】:

    标签: python-3.x pandas pivot-table


    【解决方案1】:
    import numpy as np
    import pandas as pd
    
    results = pd.DataFrame({'Contractor':[1,1,0,0,0,1],
                        'President':[1,0,0,0,1,1],
                       'Item 1':[1,1,0,0,1,np.nan],
                       'Item 2':[1,0,0,1,0,1]})
    reference =  pd.DataFrame({'Position':['Contractor','President'],
                               'Item(s)':[(1,), (1,2)]})
    
    longref = pd.DataFrame([('Item {}'.format(item), row['Position']) 
                            for index, row in reference.iterrows() 
                            for item in row['Item(s)']], columns=['Item', 'Position'])
    melted = pd.melt(results, id_vars=['Item 1','Item 2'], var_name='Position')
    melted = melted.loc[melted['value']==1]
    melted = pd.melt(melted, id_vars=['Position'], 
                     value_vars=['Item 1','Item 2'], var_name='Item')
    merged = pd.merge(longref, melted, how='left')
    grouped = merged.groupby(['Position'])
    result = (grouped['value'].sum() / grouped['value'].count())*100
    result = result.rename('Overall%').reset_index()
    print(result)
    

    产量

         Position  Overall%
    0  Contractor     100.0
    1   President      80.0
    

    说明Hadley Wickham有一篇文章 (PDF) 提出优势 使数据“整洁”。主要原则是每一行都应该 代表一个“观察”,每一列代表一些因素或变量。

    事实证明,表达计算所需的工具 一旦数据整理好,就会很自然地到位。 这个问题的难点很大程度上来自于数据不整齐。

    考虑results

    In [405]: results
    Out[405]: 
       Contractor  Item 1  Item 2  President
    0           1     1.0       1          1
    1           1     1.0       0          0
    2           0     0.0       0          0
    3           0     0.0       1          0
    4           0     1.0       0          1
    5           1     NaN       1          1
    

    与其为ContractorPresident 设置单独的列,不如设置一个名为Position 的列,因为Position 是变量,并且每个观察值或行可以有一个@987654332 的值@ -- ContractorPresident。 同样,Item 1Item 2 应该合并为一列 Item

    In [416]: melted
    Out[416]: 
          Position    Item  value
    0   Contractor  Item 1    1.0
    1   Contractor  Item 1    1.0
    2   Contractor  Item 1    NaN
    3    President  Item 1    1.0
    4    President  Item 1    1.0
    5    President  Item 1    NaN
    6   Contractor  Item 2    1.0
    7   Contractor  Item 2    0.0
    8   Contractor  Item 2    1.0
    9    President  Item 2    1.0
    10   President  Item 2    0.0
    11   President  Item 2    1.0
    

    melted 包含与results 相同的信息,但格式整齐。 value 列包含results[['Item 1', 'Item 2']] 中的值。每行对应一个“观察值”,其中 results['Contractor'] 或 result['President']` 等于 1,因为计算的逻辑只需要这些值。

    类似地,而不是

    In [407]: reference
    Out[407]: 
      Item(s)    Position
    0    (1,)  Contractor
    1  (1, 2)   President
    

    如果 DataFrame 的列是 ItemPosition,会更整洁:

    In [408]: longref
    Out[408]: 
         Item    Position
    0  Item 1  Contractor
    1  Item 1   President
    2  Item 2   President
    

    一旦您拥有meltedlongref 形式的整理版数据, 计算期望的结果相当简单:

    merged = pd.merge(longref, melted, how='left')
    #      Item    Position  value
    # 0  Item 1  Contractor    1.0
    # 1  Item 1  Contractor    1.0
    # 2  Item 1  Contractor    NaN
    # 3  Item 1   President    1.0
    # 4  Item 1   President    1.0
    # 5  Item 1   President    NaN
    # 6  Item 2   President    1.0
    # 7  Item 2   President    0.0
    # 8  Item 2   President    1.0
    
    grouped = merged.groupby(['Position'])
    result = (grouped['value'].sum() / grouped['value'].count())*100
    result = result.rename('Overall%').reset_index()
    

    如何将reference整理成longref

    只需遍历 reference 的行,并为每一行遍历项的元组以构建新的 DataFrame,longref

    longref = pd.DataFrame([('Item {}'.format(item), row['Position']) 
                            for index, row in reference.iterrows() 
                            for item in row['Item(s)']], columns=['Item', 'Position'])
    

    如何将results整理成melted

    可以通过两次调用pd.melt 来完成。 pd.melt 将“宽”格式转换为“长”格式 DataFrame。它可以将多列合并为一列。例如,要将 Contractor 和 President 列合并为一个 Position 列,您可以使用:

    melted = pd.melt(results, id_vars=['Item 1','Item 2'], var_name='Position')
    # we only care about rows where Contractor or President value was 1. So use .loc to select those rows.
    melted = melted.loc[melted['value']==1]
    #     Item 1  Item 2    Position  value
    # 0      1.0       1  Contractor      1
    # 1      1.0       0  Contractor      1
    # 5      NaN       1  Contractor      1
    # 6      1.0       1   President      1
    # 10     1.0       0   President      1
    # 11     NaN       1   President      1
    

    同样,要将Item 1Item 2 列合并为一个Item 列,请使用:

    melted = pd.melt(melted, id_vars=['Position'], 
                     value_vars=['Item 1','Item 2'], var_name='Item')
    #       Position    Item  value
    # 0   Contractor  Item 1    1.0
    # 1   Contractor  Item 1    1.0
    # 2   Contractor  Item 1    NaN
    # 3    President  Item 1    1.0
    # 4    President  Item 1    1.0
    # 5    President  Item 1    NaN
    # 6   Contractor  Item 2    1.0
    # 7   Contractor  Item 2    0.0
    # 8   Contractor  Item 2    1.0
    # 9    President  Item 2    1.0
    # 10   President  Item 2    0.0
    # 11   President  Item 2    1.0
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-28
    • 2022-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 2021-08-19
    • 1970-01-01
    相关资源
    最近更新 更多