Как я могу оптимизировать этот код фрейма данных pandas

#python #pandas #optimization #vectorization

#питон #панды #оптимизация #векторизация

Вопрос:

У меня есть большой фрейм данных ( resultsDF ), настроенный с индексом из трех столбцов: [Ticker, Fiscal Year, Fiscal Period] примерно так

 Ticker Fiscal Year Fiscal Period Market Returns ROI 21 AA 2017 Q3 0.028904 0.006549 23 AA 2019 Q2 0.038022 -0.026191 24 AA 2018 Q3 0.024746 -0.002533 25 AA 2018 Q4 -0.058857 0.004141 26 AA 2019 Q3 0.010057 -0.015065 ... ... ... ... ... ... 36582 ZTS 2017 Q1 0.056305 0.031115 36583 ZTS 2019 Q1 0.014543 0.028669 36584 ZTS 2018 Q4 -0.058857 0.032013 36585 ZTS 2019 Q4 0.033800 0.033261 36586 ZTS 2020 Q1 -0.041786 0.036693  

Часть первая: Я создаю колонку Beat Market (Overall) , чтобы отслеживать, превышает ли средняя рентабельность инвестиций для тикера среднюю доходность рынка. Поскольку он отслеживает средние значения, этот новый столбец будет либо единицей, либо нулем для всего запаса. Таким образом, каждое значение в Beat Market (Overall) for AA может быть 1, где, как и каждое значение в Beat Market (Overall) for ZTS , может быть 0. Сложность в том, что их ROI нужно будет суммировать для каждого тикера, возможно, с помощью groupby функции, но я не уверен, как использовать это в данном контексте.

Часть вторая: У меня есть фрейм данных поиска companies , в котором содержится информация об идентификаторе отрасли для каждого тикера. Я хочу сопоставить Sector столбец в конечном кадре данных с правильным идентификатором отрасли для каждого тикера без использования цикла.

Проблема в том, что выполнение этого кода для этого набора данных занимает слишком много времени, и если бы я мог его векторизовать, это было бы намного быстрее.

Вот цикл, который я хотел бы векторизовать:

 # find if AVG returns for each ticker is greater than AVG returns for market avg_ror = resultsDF["Market Returns"].unique().mean()  for index, row in resultsDF.iterrows():  roi = resultsDF[resultsDF["Ticker"] == row["Ticker"]]["ROI"].mean()  resultsDF.loc[index, "Beat Market (Overall)"] = 1 if roi gt; avg_ror else 0  try:  resultsDF.loc[index, "Sector"] = companies.loc[row["Ticker"]][  "IndustryId"  ] # ["Sector"]  except:  pass  

Конечный кадр данных (за вычетом некоторых других столбцов) будет выглядеть следующим образом:

 Ticker Fiscal Year Fiscal Period Sector Market Returns ROI Beat Market (Overall) 21 AA 2017 Q3 110004 0.028904 0.006549 0.0 23 AA 2019 Q2 110004 0.038022 -0.026191 0.0 24 AA 2018 Q3 110004 0.024746 -0.002533 0.0 25 AA 2018 Q4 110004 -0.058857 0.004141 0.0 26 AA 2019 Q3 110004 0.010057 -0.015065 0.0 ... ... ... ... ... ... ... ... 36582 ZTS 2017 Q1 106005.0 0.056305 0.031115 1.0 36583 ZTS 2019 Q1 106005.0 0.014543 0.028669 1.0 36584 ZTS 2018 Q4 106005.0 -0.058857 0.032013 1.0 36585 ZTS 2019 Q4 106005.0 0.033800 0.033261 1.0 36586 ZTS 2020 Q1 106005.0 -0.041786 0.036693 1.0  

Ответ №1:

(1) Вы можете groupby Ticker найти среднее значение группы transform и сравнить его со средним значением рыночной доходности для каждого элемента в кадре данных

(2) Вы можете использовать .map метод для отображения Sector в companies фрейме данных (здесь я предположил AA , что он находится в секторе A и ZTS находится в B )

 resultsDF['Beat Market (Overall)'] = (resultsDF.groupby('Ticker')['ROI'].transform(np.mean) gt; resultsDF['Market Returns'].unique().mean()).astype(int) resultsDF['Sector'] = resultsDF['Ticker'].map(companies.set_index('Ticker')['IndustryId'])  

Выход:

 Ticker Fiscal Year Fiscal Period Market Returns ROI Beat Market Sector 21 AA 2017 Q3 0.028904 0.006549 0 A 23 AA 2019 Q2 0.038022 -0.026191 0 A 24 AA 2018 Q3 0.024746 -0.002533 0 A 25 AA 2018 Q4 -0.058857 0.004141 0 A 26 AA 2019 Q3 0.010057 -0.015065 0 A 36582 ZTS 2017 Q1 0.056305 0.031115 1 B 36583 ZTS 2019 Q1 0.014543 0.028669 1 B 36584 ZTS 2018 Q4 -0.058857 0.032013 1 B 36585 ZTS 2019 Q4 0.033800 0.033261 1 B 36586 ZTS 2020 Q1 -0.041786 0.036693 1 B