【问题标题】:get total by groups for all rows, selected rows and percent of total pandas按组获取所有行、选定行和熊猫总数的百分比
【发布时间】:2018-06-15 21:08:35
【问题描述】:

假设我有一个名为 mydf 的 pandas 数据框。即,

import pandas as pd

mydf = pd.DataFrame({
    'type':['A','A','A', 'B','B','B', 'C'], 
    'state':['NY','CA','NY', 'NY','CA','CA', 'WY'], 
    'date':['2018-01-02','2018-01-04','2018-02-06', 
            '2018-01-01','2018-01-24','2018-02-10','2018-01-24']
})

Out[28]: 
         date state type
0  2018-01-02    NY    A
1  2018-01-04    CA    A
2  2018-02-06    NY    A
3  2018-01-01    NY    B
4  2018-01-24    CA    B
5  2018-02-10    CA    B
6  2018-01-24    WY    C

我想要一个表格,用于计算 A 类型的所有记录、所有记录(A、B、C 类型)的每个州和日期(仅年月而不是每天的日期)的记录总数,然后每组中A占总数的百分比。

即,最终输出将是另一个具有以下列和值的 pandas 数据框:

date_ym state   total_count total_type_A    percentage
20181   CA      2           1               50
20181   NY      2           1               50
20181   WY      1           0               0
20182   CA      1           0               0
20182   NY      1           1               50

我可以创建两个表,然后将它们合并然后计数,但我正在寻找更简单的单行代码...

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    另一种选择是创建一个函数,该函数返回包含所需列的系列。

    完整示例:

    import pandas as pd
    
    df = pd.DataFrame({
        'type':['A','A','A', 'B','B','B', 'C'], 
        'state':['NY','CA','NY', 'NY','CA','CA', 'WY'], 
        'date':['2018-01-02','2018-01-04','2018-02-06', 
                '2018-01-01','2018-01-24','2018-02-10','2018-01-24']
    })
    
    df['date_ym'] = pd.to_datetime(df['date']).dt.strftime('%Y%#m') # switch # with - on linux
    
    def func(x):
        cnt = len(x)
        cnt_A = sum(x == 'A')
        return pd.Series({
            'total_count': cnt,
            'total_type_A': cnt_A,
            'percentage': cnt_A/cnt*100
        })
    
    df = df.groupby(['date_ym','state'])['type'].apply(func).unstack().reset_index()
    
    print(df)
    

    返回:

      date_ym state  total_count  total_type_A  percentage
    0   20181    CA          2.0           1.0        50.0
    1   20181    NY          2.0           1.0        50.0
    2   20181    WY          1.0           0.0         0.0
    3   20182    CA          1.0           0.0         0.0
    4   20182    NY          1.0           1.0       100.0
    

    【讨论】:

      【解决方案2】:

      第一次将日期转换为月份:

      mydf["date"] = mydf["date"].dt.strftime("%Y%m")
      

      然后使用groupby.agg:

      def total_type_A(x):
          return sum(x == "A")
      
      def percentage(x):
          return sum(x == "A") / len(x)
      
      mydf.groupby(["date", "state"]).agg([len, total_type_A,  percentage])
      

      【讨论】:

      • Tbh,我更喜欢这个解决方案。但是我会使用pd.to_datetime(df['date']).dt.strftime('%Y%#m')
      • @Kopytok 谢谢。编码方面我更喜欢这个解决方案,因为它非常干净清晰,但由于某种原因,它的执行速度比其他解决方案慢得多,不知道为什么。
      • @Dnaiel 是的。也许它调用函数的次数太多了。我认为我们可以在其他操作完成后通过计算百分比来加快速度。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 2023-03-03
      • 1970-01-01
      • 2021-01-14
      • 1970-01-01
      • 2020-10-19
      • 2019-05-20
      相关资源
      最近更新 更多