#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. Возможно, да. По сравнению со списками, есть накладные расходы на получение строк и доступ к значениям с помощью точечной записи.