【问题标题】:Pandas - Count different values by date - A more efficient way?Pandas - 按日期计算不同的值 - 一种更有效的方法?
【发布时间】:2020-10-27 16:27:35
【问题描述】:

这里是新手...

我有一个名为“yes_no”的数据框,结构如下(但它有大约 50K 条目):

      Date        Yes/No
0     2020-10-27     No
1     2020-10-27     No
2     2020-10-26    Yes
3     2020-10-26    Yes
4     2020-10-26    No
5     2020-10-25    No
6     2020-10-25    Yes
7     2020-10-25    No
8     2020-10-24    Yes
9     2020-10-24    Yes

我需要计算每个日期的“是”和“否”的数量,并计算比率,最终得到如下结果:

     Date        Yes   No  Percentage
0   2020-10-27  1142  120    0.904913
1   2020-10-26  4112  388    0.913778
2   2020-10-25  1055   68    0.939448
3   2020-10-24  1012   86    0.921676
4   2020-10-23  1476  163    0.900549
5   2020-10-22  1633  182    0.899725
6   2020-10-21  1773  237    0.882090
7   2020-10-20  2332  246    0.904577
8   2020-10-19  2868  326    0.897934
9   2020-10-18   892  107    0.892893
10  2020-10-17   992  110    0.900181
11  2020-10-16  2106  207    0.910506
12  2020-10-15  5628  632    0.899042
13  2020-10-14  9304  937    0.908505
14  2020-10-13  8129  881    0.902220

我通过字典使它与以下代码一起工作,但它非常长:

by_date = {}
for date in yes_no['Date']:
  by_date[date] = yes_no.loc[yes_no['Date'] == date]


for date in by_date:
  by_date[date] =  by_date[date]['Yes/No'].value_counts()

for date in by_date:
  if 'No' not in by_date[date]:
    by_date[date]['No'] = 0

for date in by_date:
  if 'Yes' not in by_date[date]:
    by_date[date]['Yes'] = 0

for date in by_date:
  by_date[date] = [by_date[date]['Yes'], by_date[date]['No'], (by_date[date]['Yes']/(by_date[date]['Yes'] + by_date[date]['No']))]


df_yes = pd.DataFrame(list(by_date.values()),columns = ['Yes', 'No', 'Percentage'])
df_yes['Date'] = list(by_date.keys())
df_yes = df_yes[['Date', 'Yes', 'No', 'Percentage']]

它适用于较小的数据帧 (1-2K),但这段代码需要很长时间才能处理 50K 条目:

for date in yes_no['Date']:
  by_date[date] = yes_no.loc[yes_no['Date'] == date]

一定有更好的方法来做到这一点!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您可以使用矢量化操作(无显式 python 循环)更有效地完成此操作。这意味着我们所有的操作都由底层 C/C++ 函数执行,以实现巨大的加速。

    out = (df.groupby("Date")["Yes/No"]
           .value_counts()
           .unstack(fill_value=0)
           .rename_axis(columns=None)
           .eval("percentage = Yes / (Yes + No)")
          )
    
    print(out)
                No  Yes  percentage
    Date                           
    2020-10-24   0    2    1.000000
    2020-10-25   2    1    0.333333
    2020-10-26   1    2    0.666667
    2020-10-27   2    0    0.000000
    
    脚步:
    • df.groupby("Date")["Yes/No"]:按“日期”对我们的数据框进行分组,然后从这些分组中选择“是/否”列
    • .value_counts():获取每个分组在此列中每个“是”和“否”的计数。
    • .unstack(fill_value=0):现在我们有了计数,我们将“是”和“否”放入各自的列中。
    • .rename_axis(columns=None):我们有一个有趣的列索引名称,我个人不喜欢这些,所以我要去掉它。
    • .eval("percentage = Yes / (Yes + No)"):创建一个名为百分比的新列,并为其分配所有“是”计数除以总响应计数的值(“是”+“否”

    【讨论】:

    • 谢谢 - 这很好地解决了它,几乎是瞬间的。
    【解决方案2】:
    # groupby date and yes/no columns and get the size
    # then pivot 
    new_df = df.groupby(['Date', 'Yes/No'], as_index=False).size().pivot('Date', 'Yes/No', 'size').replace(np.nan, 0)
    # divide the yes column by the size of each group
    new_df['percent_yes'] = new_df['Yes'] / new_df.sum(1)
    print(new_df)
    
    Yes/No       No  Yes  percent_yes
    Date                             
    2020-10-24  0.0  2.0     1.000000
    2020-10-25  2.0  1.0     0.333333
    2020-10-26  1.0  2.0     0.666667
    2020-10-27  2.0  0.0     0.000000
    

    【讨论】:

    • 使用unstack(fill_value=0) 代替枢轴
    • 您需要从 groupby 调用中删除 as_index=False 才能使用 unstack(...) 方法
    【解决方案3】:

    您应该研究一次性编码。熊猫使用pd.get_dummies

    我的解决方案是:

    df_new = pd.get_dummies(yes_no, columns=["Yes/No"]).groupby("Date").sum().rename(columns={"Yes/No_No":"No", "Yes/No_Yes":"Yes"}
    

    然后你可以很容易地计算出百分比。

    【讨论】:

      【解决方案4】:

      有一个非常简单的方法可以做到这一点,也许还有一些更优雅的方法:

      import pandas as pd
      
      df = pd.DataFrame({'Yes_no': ['yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no','yes','no','yes', 'yes', 'no'],
          'Dates': ['2019-07-01','2019-07-01','2019-07-01', '2019-07-03', '2019-07-03','2019-07-03','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07','2019-07-07','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07','2019-07-07','2019-07-07','2019-07-07', '2019-07-07', '2019-07-07']})
      dff = df.groupby(['Yes_no','Dates'])['Yes_no'].count()
      dff.unstack().T
      

      要创建带有比例的额外列,只需定义一个新列

      dff['prop']=dff['no']/dff['yes']
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 2019-12-05
        相关资源
        最近更新 更多