Python Pandas создают запущенный id на основе условий - PullRequest
0 голосов
/ 29 июня 2018

Мне нужно создать уникальное поле «ID» для моих строк Pandas на основе определенных условий, связанных с предыдущими строками.

Ниже вы увидите образец моих данных:

  current_driver customer_id    pu_actual_dt      service
0        167       1214      2018-06-28 13:24:00    DED
1        167       1214      2018-06-28 13:25:00    DED
2        167       1214      2018-06-28 14:43:00    DED
3        243       1214      2018-06-28 19:41:00    DED
4        243       1214      2018-06-28 19:41:00    DED
5        250       1214      2018-06-28 17:19:00    DED
6        250       1214      2018-06-28 18:00:00    DED
7        250       1214      2018-06-28 18:18:00    DED
8        259       1214      2018-06-28 19:40:00    DED
9        259       1214      2018-06-28 19:40:00    DED
10       259       1214      2018-06-28 20:14:00    DED
11       260       1214      2018-06-28 17:39:00    DED
12       260       1214      2018-06-28 17:39:00    DED
13       260       1214      2018-06-28 17:39:00    DED
14       260       1214      2018-06-28 17:39:00    DED
15       263       1214      2018-06-28 18:34:00    DED
16       263       1214      2018-06-28 18:43:00    DED
17       263       1214      2018-06-28 18:43:00    DED

Что мне нужно сделать, это создать еще один столбец со следующей логикой: если current_driver такой же, как current_driver предыдущей строки, И customer_id такой же, как customer_id предыдущей строки И pu_actual_dt находится в пределах половины час предыдущего ряда, тогда он должен иметь одинаковый идентификатор. Таким образом, он будет начинаться с «1» для первых двух строк, но, поскольку третий ряд pu_actual_dt более чем через полчаса, он будет иметь идентификатор «2». Тогда четвертый ряд имеет другой драйвер, поэтому он будет иметь идентификатор «3» вместе со строкой № 5, поскольку он имеет тот же драйвер / customer_id / pu_actual_dt, что и строка № 4.

До того, как я учел незначительные различия в pu_actual_dt (см. Первые две строки), я смог решить эту проблему путем объединения полей и запуска нового идентификатора каждый раз, когда строка не совпадала с предыдущей конкатенацией. Так, например, я использовал это для создания идентификатора раньше:

df = df.assign(id=(df['route_concate']).astype('category').cat.codes)

Однако эта логика конкатенации не работает, когда у меня есть небольшие различия в pu_actual_dt.

Поэтому я попытался учесть незначительные изменения во времени, выполнив следующее:

df['id'] = np.where((df['current_driver'] == df['current_driver'].shift(1) ) 
& (df['customer_id'] == df['customer_id'].shift(1)) 
& (df['pu_actual_dt'] < df['pu_actual_dt'].shift(1) + pd.Timedelta(minutes=30)) 
& (df['pu_actual_dt'] > df['pu_actual_dt'].shift(1) - pd.Timedelta(minutes=30)) 
& (df['service'] == 'DED'), df['id'].shift(1), df['id'].shift(1) + 1)

То, что я пытаюсь сделать здесь, это сказать для каждой строки, если current_driver = current_driver в строке выше и customer_id = customer_id в строке выше, pu_actual_dt в течение 30 минут до или после pu_actual_dt в предыдущей строке и service = ' DED ', затем используйте идентификатор предыдущего ряда. Если нет, то добавьте 1 к идентификатору предыдущей строки.

Я не уверен, что я делаю неправильно, но это возвращает очень непредсказуемые результаты. В какой-то момент он падает с ID 75 до 34, а затем обратно до 36?

Как лучше решить мою проблему? (Также тот, где идентификатор будет начинаться с «1»). Спасибо за вашу помощь, как всегда!

1 Ответ

0 голосов
/ 29 июня 2018

ваш np.where - хорошая идея с небольшой разницей: присвойте 1, если условие не выполняется, и None, если оно выполнено, например:

df['id'] = np.where((df['current_driver'] == df['current_driver'].shift(1) ) 
& (df['customer_id'] == df['customer_id'].shift(1)) 
& (df['pu_actual_dt'] < df['pu_actual_dt'].shift(1) + pd.Timedelta(minutes=30)) 
& (df['pu_actual_dt'] > df['pu_actual_dt'].shift(1) - pd.Timedelta(minutes=30)) 
& (df['service'] == 'DED'), None, 1) # NOTE the None and 1 here are explain above

Теперь у вас есть 1 для каждой строки, которую вы хотите увеличить в id, поэтому используйте cumsum, ffill и astype (чтобы целое число не было плавающим) такие как:

df['id'] = df['id'].cumsum().ffill().astype(int)

дает на вашем примере

    current_driver  customer_id        pu_actual_dt service  id
0              167         1214 2018-06-28 13:24:00     DED   1
1              167         1214 2018-06-28 13:25:00     DED   1
2              167         1214 2018-06-28 14:43:00     DED   2
3              243         1214 2018-06-28 19:41:00     DED   3
4              243         1214 2018-06-28 19:41:00     DED   3
5              250         1214 2018-06-28 17:19:00     DED   4
6              250         1214 2018-06-28 18:00:00     DED   5
7              250         1214 2018-06-28 18:18:00     DED   5
8              259         1214 2018-06-28 19:40:00     DED   6
9              259         1214 2018-06-28 19:40:00     DED   6
10             259         1214 2018-06-28 20:14:00     DED   7
11             260         1214 2018-06-28 17:39:00     DED   8
12             260         1214 2018-06-28 17:39:00     DED   8
13             260         1214 2018-06-28 17:39:00     DED   8
14             260         1214 2018-06-28 17:39:00     DED   8
15             263         1214 2018-06-28 18:34:00     DED   9
16             263         1214 2018-06-28 18:43:00     DED   9
17             263         1214 2018-06-28 18:43:00     DED   9
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...