Улучшение производительности сравнения даты и времени в пандах - PullRequest
1 голос
/ 29 апреля 2019

У меня есть информационный фрейм pandas со следующими значениями:

df['ORDER_RECEIVED_DATE'].head()
Out[91]: 
0   2018-01-01
1   2018-01-01
2   2018-01-01
3   2018-01-01
4   2018-01-01

Я определяю пользовательскую функцию для создания другого столбца «Период» в зависимости от сравнения со значениями даты в «ORDER_RECEIVED_DATE»

def period(x):
    if x<pd.to_datetime('01-04-2018'):
        y=0
    elif x<pd.to_datetime('04-05-2018'):
        y=1
    elif x<pd.to_datetime('05-31-2018'):
        y=2
    elif x<pd.to_datetime('08-02-2018'):
       y=3
    elif x<pd.to_datetime('09-27-2018'):
        y=4
    elif x<pd.to_datetime('01-03-2019'):
        y=5
    elif x<pd.to_datetime('02-14-2019'):
        y=6
    elif x<pd.to_datetime('03-28-2019'):
        y=7
    else:
        y=8
    return y

Наконец, применить его к столбцу Панд:

df['Period'] = df['ORDER_RECEIVED_DATE'].apply(lambda x:period(x))

Но это невероятно медленно на ~ 1м записи. Как я могу ускорить это?

Ответы [ 2 ]

1 голос
/ 29 апреля 2019

Предполагая, что вы делаете массив дат

dates = pd.to_datetime([
    '01-04-2018', '04-05-2018', '05-31-2018',
    '08-02-2018', '09-27-2018', '01-03-2019',
    '02-14-2019', '03-28-2019'
]).values

Вы можете использовать searchsorted, который сообщит вам позицию, к которой относится каждая сравниваемая дата, в порядке dates

df.assign(Period=dates.searchsorted(df.ORDER_RECEIVED_DATE))

   ORDER_RECEIVED_DATE  Period
0           2018-01-01       0
1           2018-02-01       1
2           2018-03-01       1
3           2018-04-01       1
4           2018-05-01       2
5           2018-06-01       3
6           2018-07-01       3
7           2018-08-01       3
8           2018-09-01       4
9           2018-10-01       5
10          2018-11-01       5
11          2018-12-01       5
12          2019-01-01       5
13          2019-02-01       6
14          2019-03-01       7
15          2019-04-01       8
​
1 голос
/ 29 апреля 2019

Попробуйте:

old_date = '01-01-1970'
future_date = '01-01-2050'
cuts = pd.to_datetime([old_date, '01-04-2018', '04-05-2018', '05-31-2018',
                '08-02-2018', '09-27-2018', '01-03-2019',
                '02-14-2019', '03-28-2019', future_date])

df = pd.DataFrame({'date': pd.date_range('01-01-2018', '04-05-2019', freq='MS')})
df['ped'] = pd.cut(df['date'], bins=cuts).cat.codes

Вывод:

+----+---------------------+-------+
|    | date                |   ped |
|----+---------------------+-------|
|  0 | 2018-01-01 00:00:00 |     0 |
|  1 | 2018-02-01 00:00:00 |     1 |
|  2 | 2018-03-01 00:00:00 |     1 |
|  3 | 2018-04-01 00:00:00 |     1 |
|  4 | 2018-05-01 00:00:00 |     2 |
|  5 | 2018-06-01 00:00:00 |     3 |
|  6 | 2018-07-01 00:00:00 |     3 |
|  7 | 2018-08-01 00:00:00 |     3 |
|  8 | 2018-09-01 00:00:00 |     4 |
|  9 | 2018-10-01 00:00:00 |     5 |
| 10 | 2018-11-01 00:00:00 |     5 |
| 11 | 2018-12-01 00:00:00 |     5 |
| 12 | 2019-01-01 00:00:00 |     5 |
| 13 | 2019-02-01 00:00:00 |     6 |
| 14 | 2019-03-01 00:00:00 |     7 |
| 15 | 2019-04-01 00:00:00 |     8 |
+----+---------------------+-------+

Редактировать: существует проблема с датой окончания, т.е. 2019-03-28 дает 7 в этом коде вместо 8 вваш код.Это можно решить, уменьшив пороги на 1 день.

...