Примените функцию к строкам фрейма данных, основываясь на результатах предыдущих функций

#python #pandas #dataframe

#питон #панды #фрейм данных

Вопрос:

Я пытаюсь перебрать строки фрейма данных pandas и применить функцию к строкам одну за другой. Входное значение функции зависит от результатов предыдущей строки.

Вот пример:

 import numpy as np import pandas as pd import math   def predict_loc(df, lon, lat):  R = 6378.1 # Radius of the Earth  brng = np.deg2rad(df.wdir) # Bearing is radians.  d = df.wspd * df.delta * 60 / 1e3 # Distance in km   lat2 = math.asin(  math.sin(lat) * math.cos(d / R)    math.cos(lat) * math.sin(d / R) * math.cos(brng)  )   lon2 = lon   math.atan2(  math.sin(brng) * math.sin(d / R) * math.cos(lat),  math.cos(d / R) - math.sin(lat) * math.sin(lat2),  )   lat2 = np.rad2deg(lat2)  lon2 = np.rad2deg(lon2)   return lon2, lat2   dates = pd.date_range("20130101", periods=6, freq="1H") df = pd.DataFrame(  np.random.randn(6, 3),  index=dates,  columns=[  "wdir",  "wspd",  "delta",  ], )  lon = 0 lat = 1  for index, row in df.iterrows():  lon, lat = predict_loc(row, lon, lat)  

В этом примере начальные значения lon и lat равны 0 и 1 соответственно. Затем местоположение предсказывается predict_loc функцией. Новые lon и lat являются входными данными для следующей строки. Что мне нужно, так это окончательные лон и лат.

Есть ли более быстрый способ завершить эту задачу? Спасибо.

Комментарии:

1. Привет, под «более быстрым способом выполнения задачи» вы подразумеваете, что хотите упростить predict_loc или что функция и так хороша, но вы ищете что-то более быстрое, чем iterrows() ?

2. Привет @Laurent, я имею в виду что-то более быстрое, чем iterrows() .

Ответ №1:

Итак, как бы то ни было, ваш код выполняется в среднем за 0,0002 секунды:

 import statistics import time  np.random.seed(0) # In order to get consistant results  iterations = 25_000  elapsed_time = [] for i in range(iterations):  start_time = time.time()  lon = 0  lat = 1  for index, row in df.iterrows():  lon, lat = predict_loc(row, lon, lat)  elapsed_time.append(time.time() - start_time)  print(lon, lat) # 6861.350646683788 -63.005854847412145 print(f"--- {statistics.mean(elapsed_time):2f} seconds in average ---") # --- 0.000233 seconds in average ---  

На данном этапе вашей работы, учитывая тот факт, что вас интересуют только конечные результаты , вам не нужны Панды, и я бы предложил вместо этого использовать Python, слегка изменив predict_loc и определив вспомогательную функцию, которая управляет lists , а Series не, как это:

 def new_predict_loc(*args):  wdir, wspd, delta, lon, lat = args  R = 6378.1 # Radius of the Earth  brng = np.deg2rad(wdir) # Bearing is radians.  d = wspd * delta * 60 / 1e3 # Distance in km   lat2 = math.asin(  math.sin(lat) * math.cos(d / R)    math.cos(lat) * math.sin(d / R) * math.cos(brng)  )   lon2 = lon   math.atan2(  math.sin(brng) * math.sin(d / R) * math.cos(lat),  math.cos(d / R) - math.sin(lat) * math.sin(lat2),  )   lat2 = np.rad2deg(lat2)  lon2 = np.rad2deg(lon2)   return lon2, lat2   def compute_coordinates(df):  n = 0  wdir = df["wdir"].to_list()  wspd = df["wspd"].to_list()  delta = df["delta"].to_list()  lon, lat = 0, 1   while n lt; df.shape[0]:  lon, lat = new_predict_loc(wdir[n], wspd[n], delta[n], lon, lat)  n  = 1  return lon, lat  

Таким образом, вычисление выполняется в среднем за 0,00003 секунды, что почти в 7 раз быстрее, чем ранее:

 elapsed_time = [] for i in range(iterations):  start_time = time.time()  lon, lat = compute_coordinates(df)  elapsed_time.append(time.time() - start_time)  print(lon, lat) # Same results as before # 6861.350646683788 -63.005854847412145 print(f"--- {statistics.mean(elapsed_time):2f} seconds in average ---") # --- 0.000027 seconds in average ---  

Комментарии:

1. Спасибо! Ха, я не знаю, что цикл while быстрее, чем цикл строк. Это вызвано чтением данных строк или чем-то еще?

2. Возможно, да. По сравнению со списками, есть накладные расходы на получение строк и доступ к значениям с помощью точечной записи.