Python: разделить дату начала и дату окончания на все дни между датой начала и даты окончания - PullRequest
0 голосов
/ 16 июня 2020

У меня есть данные под названием «Запланированный отпуск», которые включают «дату начала», «дату окончания», «идентификатор пользователя» и «тип отпуска».

Я хочу иметь возможность создать новый data-frame, который показывает все дни между начальной и конечной датами для каждого «идентификатора пользователя».

До сих пор мне удалось создать только date_list, который предоставляет диапазон дат между начальной и конечной датой, но я не могу найти способ включить это для каждого идентификатора пользователя и типа выхода.

Вот моя текущая функция:

def datesplit(data):
    x = pd.DataFrame(columns=['Date'])
    for i in plannedleave.iterrows():
        start = data['Start Date'][i]
        end = data['End Date'][i]
        date_list = [start + dt.timedelta(days=x) for x in range((end-start).days)]
    x.append(date_list)
    return x

>>> datesplit(plannedleave)
>>> Value Error: Can only Tuple-index with a MultiIndex

Вот как выглядят данные:

>>> plannedleave.dtypes
>>>
    Employee ID                      int64
    First Name                      object
    Last Name                       object
    Leave Type                      object
    Start Date              datetime64[ns]
    End Date                datetime64[ns]
dtype: object

Буду бесконечно признателен, если вы найдете здесь решение! :-)

Ответы [ 2 ]

0 голосов
/ 16 июня 2020

Вот необходимые циклы, поэтому я предпочитаю DataFrame.itertuples больше как DataFrame.iterrows для производительности в понимании списка:

def datesplit(df):
    df1 = df.rename(columns={'Start Date':'sdate','End Date':'edate', 'Employee ID':'ID'})
    return  (pd.concat([pd.Series(r.ID,pd.date_range(r.sdate, r.edate)) 
                        for r in df1.itertuples()])
               .rename_axis('Date')
               .reset_index(name='Employee ID'))

df = datesplit(plannedleave)
print (df)
         Date  Employee ID
0  2020-05-10         1001
1  2020-05-11         1001
2  2020-05-12         1001
3  2020-05-13         1001
4  2020-05-14         1001
5  2020-05-15         1001
6  2020-05-18         1002
7  2020-05-19         1002
8  2020-05-20         1002
9  2020-05-21         1002
10 2020-05-22         1002

Производительность с 200 строками:

plannedleave = pd.concat([plannedleave] * 100, ignore_index=True)


def datesplit(df):
    df1 = df.rename(columns={'Start Date':'sdate','End Date':'edate', 'Employee ID':'ID'})
    return  (pd.concat([pd.Series(r.ID,pd.date_range(r.sdate, r.edate)) 
                        for r in df1.itertuples()])
               .rename_axis('Date')
               .reset_index(name='Employee ID'))


def datesplitvb(data):
    parts = []
    for idx, row in data.iterrows():
        parts.append(pd.DataFrame(row['Employee ID'], columns=['Employee ID'],
            index=pd.date_range(start=row['Start Date'], end=row['End Date'],
                name='Date')))
    return pd.concat(parts).reset_index()



In [152]: %timeit datesplit(plannedleave.copy())
98.2 ms ± 4.96 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [153]: %timeit datesplitvb(plannedleave.copy())
193 ms ± 30.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
0 голосов
/ 16 июня 2020

На мой взгляд, одного столбца Дата недостаточно. Ваш выходной DataFrame должен также содержать как минимум идентификатор сотрудника , чтобы знать, какой человек находится в отпуске в данный день.

Для выполнения вашей задачи определите следующую функцию:

def datesplit(data):
    parts = []
    for idx, row in data.iterrows():
        parts.append(pd.DataFrame(row['Employee ID'], columns=['Employee ID'],
            index=pd.date_range(start=row['Start Date'], end=row['End Date'],
                name='Date')))
    return pd.concat(parts).reset_index()

Эта функция:

  • Для каждой исходной строки собираются «частичные DataFrames», на данный момент:
    • единственный столбец - Идентификатор сотрудника ,
    • индекс - это диапазон дат между начальной и конечной датами,
    • данный ID сотрудника ( одиночное значение) фактически транслируется для всех строк (каждый день текущий сотрудник находится в отпуске).
  • После l oop объединяет их и преобразует индекс ( Дата ) в «обычный» столбец.

Затем назовите его:

result = datesplit(plannedleave)

Чтобы проверить свой код, я использовал в качестве исходного DataFrame ( планировать выход ):

   Employee ID First Name Last Name Leave Type Start Date   End Date
0         1001       John     Brown       Xxxx 2020-05-10 2020-05-15
1         1002      Betty     Smith       Yyyy 2020-05-18 2020-05-22

Результат для вышеуказанных данных:

         Date  Employee ID
0  2020-05-10         1001
1  2020-05-11         1001
2  2020-05-12         1001
3  2020-05-13         1001
4  2020-05-14         1001
5  2020-05-15         1001
6  2020-05-18         1002
7  2020-05-19         1002
8  2020-05-20         1002
9  2020-05-21         1002
10 2020-05-22         1002
...