Python 如何基于连续的行在两列中不做任何更改的情况下在Pandas中进行透视和聚合?

Python 如何基于连续的行在两列中不做任何更改的情况下在Pandas中进行透视和聚合?,python,pandas,pivot-table,aggregate,Python,Pandas,Pivot Table,Aggregate,假设我有以下数据,并且需要下面显示的输出 import pandas as pd data = [ {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 10)}, {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 11)}, {'job_id': 2, 'employee': 'Joe', 'date': dateti

假设我有以下数据,并且需要下面显示的输出

import pandas as pd

data = [
    {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 10)},
    {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 11)},
    {'job_id': 2, 'employee': 'Joe', 'date': datetime.date(2019, 6, 12)},
    {'job_id': 2, 'employee': 'Joe', 'date': datetime.date(2019, 6, 13)},
    {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 14)},
    {'job_id': 1, 'employee': 'Joe', 'date': datetime.date(2019, 6, 17)},
    {'job_id': 2, 'employee': 'Jill', 'date': datetime.date(2019, 6, 10)},
    {'job_id': 2, 'employee': 'Jill', 'date': datetime.date(2019, 6, 11)},
    {'job_id': 1, 'employee': 'Jill', 'date': datetime.date(2019, 6, 12)},
    {'job_id': 1, 'employee': 'Jill', 'date': datetime.date(2019, 6, 13)},
    {'job_id': 3, 'employee': 'Jill', 'date': datetime.date(2019, 6, 14)}
]

data_df = pd.DataFrame(data)

output_data = [
    {'job_id': 1, 'employee': 'Joe', 'start_date': datetime.date(2019, 6, 10), 'end_date': datetime.date(2019, 6, 11)},
    {'job_id': 2, 'employee': 'Joe', 'start_date': datetime.date(2019, 6, 12), 'end_date': datetime.date(2019, 6, 13)},
    {'job_id': 1, 'employee': 'Joe', 'start_date': datetime.date(2019, 6, 14), 'end_date': datetime.date(2019, 6, 17)},
    {'job_id': 2, 'employee': 'Jill', 'start_date': datetime.date(2019, 6, 10), 'end_date': datetime.date(2019, 6, 11)},
    {'job_id': 1, 'employee': 'Jill', 'start_date': datetime.date(2019, 6, 12), 'end_date': datetime.date(2019, 6, 13)},
    {'job_id': 3, 'employee': 'Jill', 'start_date': datetime.date(2019, 6, 14), 'end_date': datetime.date(2019, 6, 14)}
]

output_df = pd.DataFrame(output_data)
基本上,我是按
employee
,然后按升序
date
对表进行排序的。我需要一份给定工作的员工开始/结束日期的汇总表。需要注意的几点:

  • 员工可以在一份工作上,换到另一份工作,然后回到第一份工作(请参见
    Joe
    -他在工作1,然后是工作2,然后又回到工作1)。这应该为每个转换显示一个条目(参见输出数据中的行)
  • 该员工可能连续几天没有上班(例如,周末休息两天),但如果他在周四和周五上班,然后在周一返回,那么周四和周一都会有一个条目。再次查看Joe在工作1中的第二组工作日
  • 员工可能只工作一天。在这种情况下,开始日期和结束日期应该是同一天(请参见作业3中的吉尔)
  • 员工每天只能从事一项工作

  • 如果不是连续的周期,我只需要创建一个透视表,按用户/作业分组,并按最大和最小日期聚合。但是,我不知道如何进行分组,当我查找具有相同
    员工
    工作id
    的连续行时,您可以通过两个分组进行分组:

    # to mask the jobs chunks separately
    s  = data_df.groupby('employee').job_id.apply(lambda x: x.ne(x.shift()).cumsum())
    
    out_df = data_df.groupby(['employee', s]).agg({'job_id':'first', 'date':{'min','max'}})
    
    给出:

                    job_id        date            
                    job_id         max         min
    employee job_id                               
    Jill     1           2  2019-06-11  2019-06-10
             2           1  2019-06-13  2019-06-12
             3           3  2019-06-14  2019-06-14
    Joe      1           1  2019-06-11  2019-06-10
             2           2  2019-06-13  2019-06-12
             3           1  2019-06-17  2019-06-14
    
    可通过以下方式将其更改为您的表单:

    out_df.columns = ['job_id', 'end_date', 'start_date']
    out_df = out_df.reset_index(level=1,drop=True).reset_index()
    
    IIUC

    我的逻辑与Quang Hoang相似,但我使用1 groupby,因为您说您的数据已按
    员工
    日期
    排序。为连续相同的
    作业创建groupID\u id
    ,并将其保存为数组
    s
    。我在这里不使用
    groupby
    ,因为在下一步中,在两个相邻的行中,相同的
    job\u id
    ,不同的
    employee
    将由
    employee
    s
    的groupby分开

    s = data_df.job_id.diff().ne(0).cumsum().values
    
    下一步,
    groupby
    上的
    employee
    ,“job\u id”和
    s
    。使用
    日期上的
    first
    last
    调用
    agg
    ,并重置索引以放回列和
    删除不需要的列。最后,将`列重命名为适当的名称

    data_df.groupby(['employee', 'job_id', s], sort=False).date.agg(['first', 'last']) \
           .reset_index().drop('level_2', 1) \
           .rename(columns={'first': 'start_date', 'last': 'end_date'})
    
    Out[1283]:
      employee  job_id  start_date    end_date
    0      Joe       1  2019-06-10  2019-06-11
    1      Joe       2  2019-06-12  2019-06-13
    2      Joe       1  2019-06-14  2019-06-17
    3     Jill       2  2019-06-10  2019-06-11
    4     Jill       1  2019-06-12  2019-06-13
    5     Jill       3  2019-06-14  2019-06-14
    

    注意:我还测试了两个相邻行的样本数据,它们具有不同的
    employee
    ,但具有相同的
    job\u id
    。它仍然有效

    Sample:
    In [1289]: data_df
    Out[1289]:
             date employee  job_id
    0  2019-06-10      Joe       1
    1  2019-06-11      Joe       1
    2  2019-06-12      Joe       2
    3  2019-06-13      Joe       2
    4  2019-06-14      Joe       1
    5  2019-06-10     Jill       1
    6  2019-06-11     Jill       1
    7  2019-06-12     Jill       2
    8  2019-06-13     Jill       2
    9  2019-06-14     Jill       3
    
    
    s = data_df.job_id.diff().ne(0).cumsum().values
    data_df.groupby(['employee', 'job_id', s], sort=False).date.agg(['first', 'last']) \
           .reset_index().drop('level_2', 1) \
           .rename(columns={'first': 'start_date', 'last': 'end_date'})
    
    Out[1290]:
      employee  job_id  start_date    end_date
    0      Joe       1  2019-06-10  2019-06-11
    1      Joe       2  2019-06-12  2019-06-13
    2      Joe       1  2019-06-14  2019-06-14
    3     Jill       1  2019-06-10  2019-06-11
    4     Jill       2  2019-06-12  2019-06-13
    5     Jill       3  2019-06-14  2019-06-14
    

    谢谢这似乎奏效了。快速提问-作业id行索引发生了什么变化?或者这仅仅是由于groupby引起的一些标签问题?这是来自
    s
    ,其名称是
    job\u id
    ,而不是来自
    data\u df
    。啊。。这是有道理的(不幸的是,我的ID使用了1、2、3,并且正好有3个组)。