Пара сотрудников, которые работали вместе в течение самого длительного периода времени - Python / Pandas - PullRequest
2 голосов
/ 07 июня 2019

Мне недавно пришлось написать код, который возвращает пару сотрудников, которые больше всего работали вместе над общим проектом. Вот код, который я придумал:

Примечание 1: Null читается программой как "Today"

Примечание 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: Человек в комментариях напомнил мне упомянуть, что перекрывающиеся дни должны учитываться как, например:

Лица А и В работают над двумя проектами в течение всего июня. Это означает, что его следует считать общей общей работой за 30 дней (для двух проектов), а не суммировать оба времени проекта вместе, что приведет к 60 дням.

1 Ответ

2 голосов
/ 07 июня 2019

Вот один из самых простых способов сделать это.

  1. Разверните интервалы времени до одной строки за дату.
  2. Объедините все дни в одном проекте (чтобы получить все комбинации людей, которые работали вместе)
  3. Удалитьдублированные ряды людей, которые работают вместе в один и тот же день, но в разных проектах.
  4. Просто найдите, сколько строк в каждой рабочей паре.

Код:

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

Сотрудники 1 и 2 полностью перекрываются в течение 15 дней в двух проектах в ноябре 2014 года. Затем они работают вместев течение 2 дополнительных дней в другом проекте в 2015 году. 1, 2 и 3 работают вместе в течение 15 дней в рамках одного проекта.

Запустив этот тестовый пример, мы получим:

                 Days_Together
EmpID_x EmpID_y               
1       2                   17
        3                   15
2       3                   15
...