Эффективный способ применить специфические для строки условия - PullRequest
1 голос
/ 30 сентября 2019

У меня есть данные об исходящих рейсах, с информацией о дне, месяце, аэропорту и т. Д. Я хотел бы пройтись по строкам, и для каждого из них подсчитать количество рейсов, которые вылетали из того же аэропорта в +- 15м. Кажется, мой код работает, но он очень медленный (на 100 тыс. Строк это занимает ~ час). Есть ли способ повысить его эффективность? Вот пример файла ссылка Спасибо!

time_allowance = 15
close_out = []
i=0
for index, row in df.iterrows():
    i+=1

    idf = df.loc[(df['Origin'] == row['Origin']) &
                 (df['Month'] == row['Month']) &
                 (df['DayofMonth'] == row['DayofMonth']) &
                 (df['DepTime'] < row['DepTime'] + time_allowance) &
                 (df['DepTime'] > row['DepTime'] - time_allowance), :]

    close_out.append(len(idf))   

col_name = 'close_out' + str(time_allowance)
df[col_name] = close_out

1 Ответ

1 голос
/ 30 сентября 2019

Ваш код

import pandas as pd

cols = ['Month', 'DayofMonth', 'DayOfWeek', 'DepTime', 'UniqueCarrier', 'Origin', 'Dest', 'Distance']
data = [
  ['c-8', 'c-21', 'c-7', 1934, 'AA', 'ATL', 'DFW', 732],
  ['c-6', 'c-19', 'c-2', 1942, 'AA', 'ATL', 'CLE', 999],
  ['c-6', 'c-19', 'c-2', 1955, 'AA', 'ATL', 'CLE', 111],
  ['c-4', 'c-20', 'c-3', 1548, 'US', 'PIT', 'MCO', 834],
  ['c-9', 'c-2', 'c-5', 1422, 'XE', 'RDU', 'CLE', 416],
  ['c-11', 'c-25', 'c-6', 1015, 'OO', 'DEN', 'MEM', 872],
  ['c-10', 'c-7', 'c-6', 1828, 'WN', 'MDW', 'OMA', 423]
]

df = pd.DataFrame(data=data, columns=cols)
df['close_out15'] = 0

def algo_v1(df):


time_allowance = 15
  close_out = []
  i=0
  for index, row in df.iterrows():
      i+=1

      idf = df.loc[(df['Origin'] == row['Origin']) &
                  (df['Month'] == row['Month']) &
                  (df['DayofMonth'] == row['DayofMonth']) &
                  (df['DepTime'] < row['DepTime'] + time_allowance) &
                  (df['DepTime'] > row['DepTime'] - time_allowance), :]

      close_out.append(len(idf))   

  col_name = 'close_out' + str(time_allowance)
  df[col_name] = close_out

  return df

Тестирование:

#print(algo_v1(df))
#%timeit algo_v1(df)

      Month DayofMonth DayOfWeek  DepTime  ... Origin Dest Distance  close_out15
0   c-8       c-21       c-7     1934  ...    ATL  DFW      732            1
1   c-6       c-19       c-2     1942  ...    ATL  CLE      999            2
2   c-6       c-19       c-2     1955  ...    ATL  CLE      111            2
3   c-4       c-20       c-3     1548  ...    PIT  MCO      834            1
4   c-9        c-2       c-5     1422  ...    RDU  CLE      416            1
5  c-11       c-25       c-6     1015  ...    DEN  MEM      872            1
6  c-10        c-7       c-6     1828  ...    MDW  OMA      423            1

[7 rows x 9 columns]
10 loops, best of 3: 28.4 ms per loop

Некоторые базовые улучшения только при использовании методов groupby и apply.

def filter_and_count(df):
  time_threshold = 15

  for idx, row in df.iterrows():
    row['close_out15'] = df['UniqueCarrier'].loc[
      (df['DepTime'] <= row['DepTime'] + time_threshold)
      & (df['DepTime'] >= row['DepTime'] - time_threshold)
    ].count()


def algo_v2(df):
  df.groupby(['Origin', 'Month', 'DayofMonth']).apply(filter_and_count)

  return df

Тестирование производительности

#print(algo_v2(df))
#%timeit algo_v2(df)

  Month DayofMonth DayOfWeek  DepTime  ... Origin Dest Distance  close_out15
0   c-8       c-21       c-7     1934  ...    ATL  DFW      732            1
1   c-6       c-19       c-2     1942  ...    ATL  CLE      999            2
2   c-6       c-19       c-2     1955  ...    ATL  CLE      111            2
3   c-4       c-20       c-3     1548  ...    PIT  MCO      834            1
4   c-9        c-2       c-5     1422  ...    RDU  CLE      416            1
5  c-11       c-25       c-6     1015  ...    DEN  MEM      872            1
6  c-10        c-7       c-6     1828  ...    MDW  OMA      423            1

[7 rows x 9 columns]
100 loops, best of 3: 18.8 ms per loop

Улучшение примерно на 34% можно заметить, просто группируя по некоторым полям.

Следующие шаги для улучшения производительности

Существует два основных варианта:

  • Продолжать улучшать производительность алгоритма
  • Распараллеливание

Обратите внимание, что эти два параметра также могут работать вместе.

Улучшение производительности

Использование Numba или Ctyhon может быть хороших опций .

Распараллеливание

Многопроцессорный модуль является альтернативой. Другой более высокий уровень абстракции - это этот .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...