【问题标题】:How do I Group By Date and Measure fields to calculate rank?如何按日期和度量字段分组以计算排名?
【发布时间】:2019-12-09 16:29:28
【问题描述】:

我有一个包含学生姓名、交易日期和金额的数据集。 每个学生都进行了多次交易。

我想根据每个学生的总金额计算当月排名和上个月排名。

我可以按学生姓名分组以计算每个学生的总金额:

transactions['Totals'] = transactions.groupby('Student Name')['Sale Amount'].transform('sum')

如何扩展它以创建两个不同的列来计算每个学生的上个月总计和当前月份总计,以便我可以为他们分配上个月和当前月份的排名?

日期格式如下:

    09/05/2015 04:18 PM
    07/15/2019 09:50 AM
    05/18/2018 02:34 PM
    08/11/2018 06:29 PM
    06/14/2018 07:42 AM

编辑:添加数据框以供参考:

Out[15]: 
      Date of Transaction       Student Name  Sale Amount
0     09/05/2015 04:18 PM          Dan Kelly         4333
1     07/15/2019 09:50 AM         Peter Dyer         8805
2     05/18/2018 02:34 PM  Natalie Robertson         5640
3     08/11/2018 06:29 PM        Sean Miller         6485
4     06/14/2018 07:42 AM     Thomas Forsyth         6815
                  ...                ...          ...
9977  03/15/2018 09:28 PM        Grace Vance         6379
9978  08/07/2019 11:14 PM  Alexandra Cameron         6688
9979  01/09/2015 10:53 AM  Sebastian Vaughan         2262
9980  05/19/2019 10:00 PM     Caroline Blake         6977
9981  01/11/2016 04:05 AM     Austin Edmunds         3205

[9982 rows x 3 columns]

编辑:添加示例预期输出:

【问题讨论】:

  • 您能提供更准确的数据集吗?与您的预期输出?
  • @Datanovice - 只有三列是我已经提到的。学生姓名、销售额和交易日期。我添加了 DataFrame 以供参考。我的预期输出是两个新列:上个月排名和当前月份排名。
  • pd.crosstab( df["Student Name"], df["Date"].dt.strftime("%b"), df["Sale Amount"], aggfunc="sum").fillna(0).reset_index() 这应该可以工作。
  • 这给了我一个包含离散月份的交叉表。我想我需要连续几个月来选择当前和上个月的数据来计算排名。
  • 你能提供你想要的输出吗?如果是这样,提供解决方案会容易得多。

标签: python pandas pandas-groupby


【解决方案1】:

我用您告知的最少数据创建了一个数据框:“学生姓名”、“销售金额”、“日期”

我的数据框:

          df = pd.DataFrame([['12/05/2019 04:18 PM','Marisa',500],
               ['11/29/2019 04:18 PM','Marisa',500],
               ['11/20/2019 04:18 PM','Marisa',800],
               ['12/04/2019 04:18 PM','Peter',300],
               ['11/30/2019 04:18 PM','Peter',300],
               ['12/05/2019 04:18 PM','Debra',400],
               ['11/28/2019 04:18 PM','Debra',200],
               ['11/15/2019 04:18 PM','Debra',600],
               ['10/23/2019 04:18 PM','Debra',200]],columns=['Date','Student Name','Sale Amount']
               )

确保日期是日期时间列。

df.Date = pd.to_datetime(df.Date)

这将为您提供原始数据框中每个学生每月的总金额:

df['Total'] = df.groupby(['Student Name',pd.Grouper(key='Date', freq='1M')])['Sale Amount'].transform('sum')


    Date Student             Name       Sale Amount  Total
0 2019-12-05 16:18:00       Marisa          500      500
1 2019-11-29 16:18:00       Marisa          500     1300
2 2019-11-20 16:18:00       Marisa          800     1300
3 2019-12-04 16:18:00        Peter          300      300
4 2019-11-30 16:18:00        Peter          300      300
5 2019-12-05 16:18:00        Debra          400      400
6 2019-11-28 16:18:00        Debra          200      800
7 2019-11-15 16:18:00        Debra          600      800
8 2019-10-23 16:18:00        Debra          200      200

如何只打印选中的结果?

df 现在更新了:

dnew = df

让我们去掉日期时间以仅保留月份:

#Strip date to month
dnew['Date'] = dnew['Date'].apply(lambda x:x.date().strftime('%m'))

按学生姓名和日期删除销售金额条目和分组(新数据框为“销售”):

#Drop Sale Amount 
sales = dnew.drop(['Sale Amount'], axis=1).groupby(['Student Name','Date'])['Total'].max()


print(sales)
Student Name  Date
Debra         10       200
              11       800
              12       400
Marisa        11      1300
              12       500
Peter         11       300
              12       300

实际上,“销售”是 pandas.core.series.Series,知道这一点很重要

print(sales.index)
MultiIndex([( 'Debra', '10'),
        ( 'Debra', '11'),
        ( 'Debra', '12'),
        ('Marisa', '11'),
        ('Marisa', '12'),
        ( 'Peter', '11'),
        ( 'Peter', '12')],
       names=['Student Name', 'Date'])    

 from datetime import datetime      
 curMonth = int(datetime.today().strftime('%m')) #transform to integer to perform (curMonth-1)
 #12

 #months of interest
 moi = sales.iloc[(sales.index.get_level_values('Date') == str(curMonth-1)) | (sales.index.get_level_values('Date') == str(curMonth))]

 print(moi)

 Student Name  Date
 Debra         11       800
               12       400
 Marisa        11      1300
               12       500
 Peter         11       300
               12       300

【讨论】:

  • 这是有道理的。但是如何扩展它以创建两个新列,上个月排名和当前月份排名?
  • @NickAdams,我已经编辑了我的答案,以便向您展示新问题的可能解决方案。它从“如何只打印选定的结果?”开始
  • 这很好用,但与我的预期输出有点不同。两点:1)如果我的数据有很多前几年的交易,这仍然有效吗?它会调整到数据中存在的最新月份,还是使用系统日期来计算当前和以前的月份? 2) 我需要在 Tableau 中可视化这些数据,并希望保留原始行。是否可以创建两个新列,而不是根据这些月份的销售额来保存当前和上个月的排名? (甚至是您计算的销售额,如果不是排名)
  • 1) 你需要前几年吗?如果不这样做,您可以清理或调整数据。你说你想要当前月份和上个月,如果你注意我使用 datetime.today() 的代码。这意味着系统日期时间。 2)如果你想添加两个新行,它更像我给你的第一个解决方案,因为你总是会有销售金额(Sale Amount)列。
  • 我需要带有历史数据(前几年)的原始数据集来进行趋势和总计等分析。排名系统是另一种分析,仅基于上个月和当月的销售额。理想情况下,我不想为这两个分析创建同一数据集的两个不同版本。我知道它可以在同一个数据集中完成,只是不知道如何。我能想到的最好的方法是添加两个具有先前和当前月份排名的新列,这将以更高的详细程度运行。这将确保我可以使用一个修改后的数据集进行两种分析。
猜你喜欢
  • 1970-01-01
  • 2020-02-18
  • 2013-03-31
  • 2014-12-28
  • 2011-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多