一起工作时间最长的一对员工-Python/Pandas
问题描述
我最近不得不编写一段代码,它返回在公共项目上一起工作最多的那对员工。这是我想出来的代码:
注意1:NULL被程序读取为"今天"
注意2:数据来自.txt文件,格式如下:
EmpID,ProjectID,DateFrom,DateTo
1,101,2014-11-01,2015-05-01
1,103,2013-11-01,2016-05-01
2,101,2013-12-06,2014-10-06
2,103,2014-06-05,2015-05-14
3,100,2016-03-01,2018-07-03
3,102,2015-06-04,2017-09-04
3,103,2015-06-04,2017-09-04
4,102,2013-11-13,2014-03-13
4,103,2016-02-14,2017-03-15
4,104,2014-10-01,2015-12-01
5,100,2013-03-07,2015-11-07
5,101,2015-07-09,2019-01-19
5,102,2014-03-15,NULL
6,101,2014-03-15,2014-03-16
我目前遇到的问题是,我必须调整/更改代码,以返回彼此合作时间最长的那对员工(不是单个项目,而是所有项目的总和)。我在修改我当前的代码时遇到了麻烦,它运行得非常好,我在想是否应该把所有这些都划掉,从头开始(但这会花费我很多时间,而我目前没有时间),我想知道是不是应该把所有这些都去掉,从头开始(但这会花费我很多时间,而我目前没有时间)。我在获取共同处理项目的员工组合时遇到困难。
如果有人能给我一些建议,我将不胜感激!谢谢!
编辑1:评论中有人提醒我,重叠天数应按如下方式计算:
A和B在整个六月份都在做两个项目。这意味着应该将其计为30天的总共同工作(对于两个项目),而不是将两个项目的时间加在一起,这将导致60天。
解决方案
这里是我能想到的更直接的方法之一。
- 将时间跨度扩展到每个日期的一行。
- 合并同一项目中的所有日期(以获得共同工作人员的所有组合)
- 删除在同一天一起工作但项目不同的人员的重复行。
- 只需找出每个Worker配对中有多少行。
编码:
import pandas as pd
import numpy as np
def expand_period_daily(df, start, stop):
# Allows it to work for one day spans.
df.loc[df[stop].notnull(), stop] = (df.loc[df[stop].notnull(), stop]
+ pd.Timedelta(hours=1))
real_span = df[[start, stop]].notnull().all(1)
# Resample timespans to daily fields.
df['temp_id'] = range(len(df))
dailydf = (df.loc[real_span, ['temp_id', start, stop]].set_index('temp_id').stack()
.reset_index(level=-1, drop=True).rename('period').to_frame())
dailydf = (dailydf.groupby('temp_id').apply(lambda x: x.set_index('period')
.resample('d').asfreq()).reset_index())
# Merge back other information
dailydf = (dailydf.merge(df, on=['temp_id'])
.drop(columns=['temp_id', start, stop]))
return dailydf
# Make dates, fill missings.
df[['DateFrom', 'DateTo']] = df[['DateFrom', 'DateTo']].apply(pd.to_datetime, errors='coerce')
df[['DateFrom', 'DateTo']] = df[['DateFrom', 'DateTo']].fillna(pd.to_datetime('today').normalize())
dailydf = expand_period_daily(df.copy(), start='DateFrom', stop='DateTo')
# Merge, remove rows of employee with him/herself.
m = (dailydf.merge(dailydf, on=['period', 'ProjectID'])
.loc[lambda x: x.EmpID_x != x.EmpID_y])
# Ensure A-B and B-A are grouped the same
m[['EmpID_x', 'EmpID_y']] = np.sort(m[['EmpID_x', 'EmpID_y']].to_numpy(), axis=1)
# Remove duplicated projects on same date between employee pairs
m = m.drop_duplicates(['period', 'EmpID_x', 'EmpID_y'])
m.groupby(['EmpID_x', 'EmpID_y']).size().to_frame('Days_Together')
输出:
Days_Together
EmpID_x EmpID_y
1 2 344
3 333
4 78
2 6 2
3 4 396
5 824
测试用例
为了更清楚地说明它是如何处理重叠和组合不同项目的,下面是以下测试用例:
EmpID ProjectID DateFrom DateTo
0 1 101 2014-11-01 2014-11-15
1 1 103 2014-11-01 2014-11-15
2 1 105 2015-11-02 2015-11-03
3 2 101 2014-11-01 2014-11-15
4 2 103 2014-11-01 2014-11-15
5 2 105 2015-10-02 2015-11-05
6 3 101 2014-11-01 2014-11-15
2014年11月,员工1和2在2个项目上完美重叠15天。然后,他们在2015年的另一个项目上再合作2天。1、2和3在一个项目上共同工作15天。
使用此测试用例运行我们获得:
Days_Together
EmpID_x EmpID_y
1 2 17
3 15
2 3 15
相关文章