У меня есть dataframe c
с множеством разных столбцов. Кроме того, arr
- это кадр данных, который соответствует подмножеству c
: arr = c[c['A_D'] == 'A']
.
Основная идея моего кода - перебрать все строки в c
-dataframe и выполнить поиск всех возможных случаев (в фрейме данных arr
), где должны выполняться некоторые конкретные условия:
- Нужно только итератировать по строкам:
c['A_D'] == D
иc['Already_linked'] == 0
-
hour
вhour_aux
arr
должен быть меньше, чемhour_aux
вc
кадре данных - Столбец
Already_linked
изAlready_linked
данныхarr
должен быть равен нулю:arr.Already_linked == 0
-
Terminal
иOperator
должны быть одинаковыми в фрейме c иarr
В настоящее время условия сохраняются с использованием как булевых индексирования, так и groupby get_group:
- Группируйте рамку данных
arr
, чтобы выбрать один и тот же оператор и терминал:g = groups.get_group((row.Operator, row.Terminal
)) - Выберите только те места, где час меньше часа в
c
кадре данных и где Already_linked == 0:vb = g[(g.Already_linked==0) & (g.hour<row.hour_aux)]
Для каждой из строк в c
кадре данных, которые проверяют все условия, создается vb
. Естественно, этот кадр данных имеет разную длину на каждой итерации. После создания фрейма vb
моя цель - выбрать индекс vb.START
vb
который минимизирует время между vb.START
и c [ x
]. Идентификатор FightID
, соответствующий этому индексу, затем сохраняется в c
кадре c
в столбце a
. Кроме того, поскольку приезд был связан с отъездом, столбец Already_linked
в Already_linked
arr
изменяется с 0 на 1.
Важно заметить, что столбец Already_linked
из Already_linked
arr
может меняться на каждой итерации (и arr.Already_linked == 0
является одним из условий для создания arr.Already_linked == 0
vb
). Поэтому распараллеливать этот код невозможно.
Я уже использовал c.itertuples()
для эффективности, но поскольку c
имеет миллионы строк, этот код все еще слишком трудоемкий.
Другим вариантом также будет использование pd.apply
для каждой строки. Тем не менее, это не так просто, поскольку в каждом цикле есть значения, изменяющиеся как в c
и в arr
(также, я считаю, что даже с pd.apply
это было бы очень медленно).
Есть ли какой-либо возможный способ преобразования этого цикла в векторизованное решение (или уменьшить время работы на 10X (если возможно, даже больше))?
Исходный фрейм данных:
START END A_D Operator FlightID Terminal TROUND_ID tot
0 2017-03-26 16:55:00 2017-10-28 16:55:00 A QR QR001 4 QR002 70
1 2017-03-26 09:30:00 2017-06-11 09:30:00 D DL DL001 3 " " 84
2 2017-03-27 09:30:00 2017-10-28 09:30:00 D DL DL001 3 " " 78
3 2017-10-08 15:15:00 2017-10-22 15:15:00 D VS VS001 3 " " 45
4 2017-03-26 06:50:00 2017-06-11 06:50:00 A DL DL401 3 " " 9
5 2017-03-27 06:50:00 2017-10-28 06:50:00 A DL DL401 3 " " 19
6 2017-03-29 06:50:00 2017-04-19 06:50:00 A DL DL401 3 " " 3
7 2017-05-03 06:50:00 2017-10-25 06:50:00 A DL DL401 3 " " 32
8 2017-06-25 06:50:00 2017-10-22 06:50:00 A DL DL401 3 " " 95
9 2017-03-26 07:45:00 2017-10-28 07:45:00 A DL DL402 3 " " 58
Желаемый результат (некоторые столбцы были исключены в приведенной ниже таблице данных). Учитываются только столбцы a
и Already_linked
):
START END A_D Operator a Already_linked
0 2017-03-26 16:55:00 2017-10-28 16:55:00 A QR 0 1
1 2017-03-26 09:30:00 2017-06-11 09:30:00 D DL DL402 1
2 2017-03-27 09:30:00 2017-10-28 09:30:00 D DL DL401 1
3 2017-10-08 15:15:00 2017-10-22 15:15:00 D VS No_link_found 0
4 2017-03-26 06:50:00 2017-06-11 06:50:00 A DL 0 0
5 2017-03-27 06:50:00 2017-10-28 06:50:00 A DL 0 1
6 2017-03-29 06:50:00 2017-04-19 06:50:00 A DL 0 0
7 2017-05-03 06:50:00 2017-10-25 06:50:00 A DL 0 0
8 2017-06-25 06:50:00 2017-10-22 06:50:00 A DL 0 0
9 2017-03-26 07:45:00 2017-10-28 07:45:00 A DL 0 1
Код:
groups = arr.groupby(['Operator', 'Terminal'])
for row in c[(c.A_D == "D") & (c.Already_linked == 0)].itertuples():
try:
g = groups.get_group((row.Operator, row.Terminal))
vb = g[(g.Already_linked==0) & (g.hour<row.hour_aux)]
aux = (vb.START - row.x).abs().idxmin()
c.loc[row.Index, 'a'] = vb.loc[aux].FlightID
arr.loc[aux, 'Already_linked'] = 1
continue
except:
continue
c['Already_linked'] = np.where((c.a != 0) & (c.a != 'No_link_found') & (c.A_D == 'D'), 1, c['Already_linked'])
c.Already_linked.loc[arr.Already_linked.index] = arr.Already_linked
c['a'] = np.where((c.Already_linked == 0) & (c.A_D == 'D'),'No_link_found',c['a'])
Код для исходного c
кадра:
import numpy as np
import pandas as pd
import io
s = '''
A_D Operator FlightID Terminal TROUND_ID tot
A QR QR001 4 QR002 70
D DL DL001 3 " " 84
D DL DL001 3 " " 78
D VS VS001 3 " " 45
A DL DL401 3 " " 9
A DL DL401 3 " " 19
A DL DL401 3 " " 3
A DL DL401 3 " " 32
A DL DL401 3 " " 95
A DL DL402 3 " " 58
'''
data_aux = pd.read_table(io.StringIO(s), delim_whitespace=True)
data_aux.Terminal = data_aux.Terminal.astype(str)
data_aux.tot= data_aux.tot.astype(str)
d = {'START': ['2017-03-26 16:55:00', '2017-03-26 09:30:00','2017-03-27 09:30:00','2017-10-08 15:15:00',
'2017-03-26 06:50:00','2017-03-27 06:50:00','2017-03-29 06:50:00','2017-05-03 06:50:00',
'2017-06-25 06:50:00','2017-03-26 07:45:00'], 'END': ['2017-10-28 16:55:00' ,'2017-06-11 09:30:00' ,
'2017-10-28 09:30:00' ,'2017-10-22 15:15:00','2017-06-11 06:50:00' ,'2017-10-28 06:50:00',
'2017-04-19 06:50:00' ,'2017-10-25 06:50:00','2017-10-22 06:50:00' ,'2017-10-28 07:45:00']}
aux_df = pd.DataFrame(data=d)
aux_df.START = pd.to_datetime(aux_df.START)
aux_df.END = pd.to_datetime(aux_df.END)
c = pd.concat([aux_df, data_aux], axis = 1)
c['A_D'] = c['A_D'].astype(str)
c['Operator'] = c['Operator'].astype(str)
c['Terminal'] = c['Terminal'].astype(str)
c['hour'] = pd.to_datetime(c['START'], format='%H:%M').dt.time
c['hour_aux'] = pd.to_datetime(c['START'] - pd.Timedelta(15, unit='m'),
format='%H:%M').dt.time
c['start_day'] = c['START'].astype(str).str[0:10]
c['end_day'] = c['END'].astype(str).str[0:10]
c['x'] = c.START - pd.to_timedelta(c.tot.astype(int), unit='m')
c["a"] = 0
c["Already_linked"] = np.where(c.TROUND_ID != " ", 1 ,0)
arr = c[c['A_D'] == 'A']