Pandas groupby + resample / TimeGrouper从几个月开始改变

时间:2016-12-01 18:31:52

标签: python pandas

我有一份员工薪资数据的数据框(样本如下)其中'日期'是指员工的薪水何时生效:

Employee    Date        Salary
PersonA     1/1/2016    $50000 
PersonB     3/5/2014    $65000 
PersonB     3/1/2015    $75000 
PersonB     3/1/2016    $100000 
PersonC     5/15/2010   $75000 
PersonC     6/3/2011    $100000 
PersonC     3/10/2012   $110000 
PersonC     9/5/2012    $130000 
PersonC     3/1/2013    $150000 
PersonC     3/1/2014    $200000 

在这个例子中,PersonA今年以50,000美元开始,而PersonC已经在公司工作了一段时间,自从2010年5月15日开始以来已经收到了几次增加。

我需要在单个员工的基础上将Date列转换为Months from Start,其中Months from Start将以m个月为增量(由我指定)。例如,对于PersonB,假设为m=12,结果为:

Employee    Months From Start   Salary
PersonB     0                   $65000 
PersonB     12                  $65000 
PersonB     24                  $75000 

这意味着在第0个月(就业开始),PersonB的薪水为65,000美元; 12个月后,他的薪水为65,000美元,24个月后,他的薪水为75,000美元。请注意,下一个增量(36个月) NOT 会出现在PersonB的转换数据框上,因为该持续时间超过了PersonB的工作时间(将来会是这样)。

再次注意,我希望能够将m调整为任何月份增量。如果我想要增加6个月(m=6),结果将是:

Employee    Months From Start   Salary
PersonB     0                   $65000 
PersonB     6                   $65000 
PersonB     12                  $65000 
PersonB     18                  $75000 
PersonB     24                  $100000 
PersonB     30                  $100000 

作为最后一步,我还希望将今天的员工薪水包含在已转换的数据框中。再次使用PersonB,并假设m=6,这意味着结果将是:

Employee    Months From Start   Salary
PersonB     0                   $65000 
PersonB     6                   $65000 
PersonB     12                  $65000 
PersonB     18                  $75000 
PersonB     24                  $100000 
PersonB     30                  $100000 
PersonB     32.92               $100000 <--added (today is 32.92 months from start)

问题是否采用编程方式(我假设使用至少一个:groupbyresampleTimeGrouper)来实现所需的数据帧如上所述?

注意:您可以假设所有员工都处于活动状态(尚未离开公司)。

4 个答案:

答案 0 :(得分:2)

您可以将group_by和resample结合使用。要使用重新采样,您需要将日期作为索引。

df.index = pd.to_datetime(df.Date)
df.drop('Date',axis = 1, inplace = True)

然后:

df.groupby('Employee').resample('6m').pad()

在这种情况下,我使用了6个月的时间。请注意,它将在每个月的最后一天,我希望它不会成为一个问题。 然后你会有:

    Employee   Date      Salary
0   PersonA 2016-01-31   $50000
1   PersonB 2014-03-31   $65000
2   PersonB 2014-09-30   $65000
3   PersonB 2015-03-31   $75000
4   PersonB 2015-09-30   $75000
5   PersonB 2016-03-31  $100000
6   PersonC 2010-05-31   $75000
7   PersonC 2010-11-30   $75000
8   PersonC 2011-05-31   $75000
9   PersonC 2011-11-30  $100000
10  PersonC 2012-05-31  $110000
11  PersonC 2012-11-30  $130000
12  PersonC 2013-05-31  $150000
13  PersonC 2013-11-30  $150000
14  PersonC 2014-05-31  $200000

现在您可以创建“自启动以来的月份”列(cumcount函数检查每行在其组中出现的顺序)。请记住将它乘以您在每个时期使用的月数(在本例中为6):

df['Months since started'] = df.groupby('Employee').cumcount()*6

     Employee   Date      Salary     Months since started
0   PersonA 2016-01-31   $50000                  0
1   PersonB 2014-03-31   $65000                  0
2   PersonB 2014-09-30   $65000                  6
3   PersonB 2015-03-31   $75000                 12
4   PersonB 2015-09-30   $75000                 18
5   PersonB 2016-03-31  $100000                 24
6   PersonC 2010-05-31   $75000                  0
7   PersonC 2010-11-30   $75000                  6
8   PersonC 2011-05-31   $75000                 12
9   PersonC 2011-11-30  $100000                 18
10  PersonC 2012-05-31  $110000                 24
11  PersonC 2012-11-30  $130000                 30
12  PersonC 2013-05-31  $150000                 36
13  PersonC 2013-11-30  $150000                 42
14  PersonC 2014-05-31  $200000                 48

希望它有所帮助!

答案 1 :(得分:1)

您可以使用groupby

mergeDataFrames功能
>>> import pandas as pd
>>> df = pd.DataFrame([['PersonC','5/15/2010',75000],['PersonC','7/3/2011',100000],['PersonB','3/5/2014',65000],['PersonB','3/1/2015',75000],['PersonB','3/1/2016',100000]],columns=['Employee','Date','Salary'])
>>> df['Date']= pd.to_datetime(df['Date'])
>>> df
  Employee       Date  Salary
0  PersonC 2010-05-15   75000
1  PersonC 2011-07-03  100000
2  PersonB 2014-03-05   65000
3  PersonB 2015-03-01   75000
4  PersonB 2016-03-01  100000
>>> satrt_date = df.groupby('Employee')['Date'].min().to_frame().rename(columns={'Date':'Start Date'})
>>> satrt_date['Employee'] = satrt_date.index 
>>> df = df.merge(satrt_date,how='left', on= 'Employee')
>>> df['Months From Start'] = df['Date']-df['Start Date']
>>> df['Months From Start'] = df['Months From Start'].apply(lambda x: x.days)
>>> df['Months From Start']= df['Months From Start'].apply(lambda x: (x/30) - (x/30)%6)
>>> df
  Employee       Date  Salary Start Date  Months From Start
0  PersonC 2010-05-15   75000 2010-05-15                  0
1  PersonC 2011-07-03  100000 2010-05-15                 12
2  PersonB 2014-03-05   65000 2014-03-05                  0
3  PersonB 2015-03-01   75000 2014-03-05                 12
4  PersonB 2016-03-01  100000 2014-03-05                 24

在这里,您可以使用名为6的变量替换m并为其指定任意值

答案 2 :(得分:1)

好的,所以对于答案的第一部分,我会做这样的事情......

import numpy as np
import pandas as pd

df = pd.DataFrame({
    'Employee': ['PersonA', 'PersonB', 'PersonB', 'PersonB', 'PersonC', 'PersonC', 'PersonC', 'PersonC', 'PersonC', 'PersonC'], 
    'Date': ['1/1/2016', '3/5/2014', '3/1/2015', '3/1/2016', '5/15/2010', '6/3/2011', '3/10/2012', '9/5/2012', '3/1/2013', '3/1/2014'], 
    'Salary': [50000 , 65000 , 75000 , 100000 , 75000 , 100000 , 110000 , 130000 , 150000 , 200000]
})

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

m = 6
emp_groups = df.groupby('Employee')
df['months_from_start'] = df.Date - emp_groups.Date.transform(min)
df.months_from_start = df.months_from_start.dt.days / 30 // m * m

m可以是你想要的任何东西。我计算min日期之间的天数,然后除以一个月中的大致天数,然后进行一些整数除法到#34;四舍五入&#34;到你想要的窗口大小。

这会给你这样的东西......

        Date Employee  Salary  months_from_start
0 2016-01-01  PersonA   50000                  0
1 2014-03-05  PersonB   65000                  0
2 2015-03-01  PersonB   75000                 12
3 2016-03-01  PersonB  100000                 24
4 2010-05-15  PersonC   75000                  0
5 2011-06-03  PersonC  100000                 12
6 2012-03-10  PersonC  110000                 18
7 2012-09-05  PersonC  130000                 24
8 2013-03-01  PersonC  150000                 30
9 2014-03-01  PersonC  200000                 42

第二部分有点棘手。我会创建一个新的df并连接到第一个......

last_date_df = emp_groups.last()
last_date_df.months_from_start = (last_date_df.Date - emp_groups.first().Date).dt.days / 30
last_date_df.reset_index(inplace=True)

pd.concat([df, last_date_df], axis=0)

让你......

        Date Employee  Salary  months_from_start
0 2016-01-01  PersonA   50000           0.000000
1 2014-03-05  PersonB   65000           0.000000
2 2015-03-01  PersonB   75000          12.000000
3 2016-03-01  PersonB  100000          24.000000
4 2010-05-15  PersonC   75000           0.000000
5 2011-06-03  PersonC  100000          12.000000
6 2012-03-10  PersonC  110000          18.000000
7 2012-09-05  PersonC  130000          24.000000
8 2013-03-01  PersonC  150000          30.000000
9 2014-03-01  PersonC  200000          42.000000
0 2016-01-01  PersonA   50000           0.000000
1 2016-03-01  PersonB  100000          24.233333
2 2014-03-01  PersonC  200000          46.200000

答案 3 :(得分:0)

非常感谢提供的答案。不幸的是,所有答案都有点“关闭”。并没有完全实现目标。我最终在列表推导中嵌套了两个for循环来实现目标。