#python #r #pandas
#питон #r #панды
Вопрос:
Я вычитаю years
из date column
в Python, который чувствовал себя намного медленнее, чем R, что обычно не так, поэтому мне интересно, есть ли более быстрый/ эффективный способ сделать это в python ?
(Так как после многих лет работы в R я возвращаюсь к python, поэтому мои навыки работы на python больше не хороши и я ищу оптимизацию кода на python).
код на python:
import numpy as np import pandas as pd import datetime as dt import time
Данные, которые я показываю ниже, являются просто фиктивными, чтобы дать представление о date format
том, с чем я работаю (количество строк в моих исходных данных: 466285).
df = pd.DataFrame({'date_str': ['Apr-84','Mar-66','May-85']}) df['date'] = pd.to_datetime(df['date_str'], format = '%b-%y')
Поскольку я получал некоторые неправильные даты в годах, такие как year: 2066, 2085
и т. Д. поэтому написал небольшую функцию для корректировки дат в соответствии с моими потребностями:
# year subtraction function def date_correction(x): if x gt; pd.to_datetime('2017-12-01'): x = (x - pd.to_timedelta(100 * 365.24, unit='d')) else: x = x return x start = time.time() df['date'] = df['date'].apply(date_correction) end = time.time() print("Time taken: ", end - start)
Time taken: 32.958526611328125
Вышеуказанное время, я думаю, в секундах, так как на это ушло много времени, и это заставило меня также засечь это в R.
Код R:
library(tidyverse) library(lubridate) library(microbenchmark)
df = data.frame(date_str = c('Apr-84','Mar-66','May-85')) df lt;- df %gt;% mutate(date = lubridate::my(date_str))
операция вычитания и времени:
mbm lt;- microbenchmark( 'date_subt' = { df lt;- df %gt;% mutate(date = if_else( df$date gt; ymd('2017-12-01'), df$date %m-% years(100), df$date )) } )
mbm
Результаты:
Unit: milliseconds expr min lq mean median uq max neval date_subt 324.3357 331.2416 372.4745 338.8745 396.3026 744.4625 100
autplot(mbm)
Комментарии:
1. Первой оптимизацией, которую я вижу, было бы вычисление объектов даты и времени 2017-12-01 и 100 лет вне функции. Это делает вычисления примерно в 10 раз быстрее (проверено с использованием 100000 элементов в фрейме данных).
2. Я только искал
vectorized
подходpython
, так как была огромная разница во времени выполнения R amp; python, что заставило меня задуматься о моем подходе.
Ответ №1:
Можете ли вы попробовать запустить свой код с помощью timedelta?
подобный этому:
from datetime import timedelta if dt gt; pd.to_datetime('2017-12-01'): dt -= timedelta(years=100)
Комментарии:
1. Я получал ошибку при попытке
dt -= timedelta(years=100)
, так как нет аргумента «годы», поэтому вместо этого попытался использовать дни:x -= dt.timedelta(days=100 * 365.24)
и снова это занялоTime taken: 32.42573404312134
секунды. спасибо, что предложили мне этот подход, но это также намного медленнее, чем операция R2. хорошо.. я думаю, что подход Корралиена-лучшая практика
Ответ №2:
Векторизованный способ с использованием логической маски и DateOffset
:
df.update(df.loc[df['date'] gt; '2017-12-01', 'date'] - pd.DateOffset(years=100)
Более лаконичный способ (без update
)
df.loc[df['date'] gt; '2017-12-01', 'date'] -= pd.DateOffset(years=100)
Комментарии:
1. Спасибо @Corralien, я думал, что с помощью
.apply()
этого я векторизовал его,python
но, думаю, я ошибся. Еще раз спасибо, что поделились кодом. Ценю твою помощь !2. К сожалению,
apply
это удобный способ для петли (почти)3. да, вы правы !!
4. И
Time taken: 0.00697779655456543
на этот раз это заняло несколько секунд.