Я работаю с большими наборами данных, в которых я хотел бы получить новый столбец, основанный на внешнем списке дат (в качестве примера рассмотрим праздничные дни).
Мой код работает ... но это крайне неэффективно, и я знаю, что я действительно разрываю вещи на куски.
HAVE:
+---------------+-----+------------------+
| name | age | last_purchase_dt |
+---------------+-----+------------------+
| John Smith | 23 | 2018-04-05 |
| Sugar Smith | 43 | 2019-10-05 |
| Edward Smith | 34 | 2019-05-05 |
| James Smith | 42 | 2018-03-05 |
| Sarah Smith | 65 | 2018-06-05 |
| Kate Smith | 22 | 2019-02-05 |
| Cynthia Smith | 53 | 2019-07-05 |
| Pat Smith | 66 | 2018-01-05 |
+---------------+-----+------------------+
+------------+
| Holiday_Dt |
+------------+
| 2017-01-16 |
| 2017-02-20 |
| … |
| 2020-01-20 |
| 2020-02-17 |
+------------+
WANT:
+---------------+-----+------------------+--------------------+
| name | age | last_purchase_dt | nearest_holiday_dt |
+---------------+-----+------------------+--------------------+
| John Smith | 23 | 2018-04-05 | 2018-02-19 |
| Sugar Smith | 43 | 2019-10-05 | 2019-10-14 |
| Edward Smith | 34 | 2019-05-05 | 2019-05-27 |
| James Smith | 42 | 2018-03-05 | 2018-02-19 |
| Sarah Smith | 65 | 2018-06-05 | 2018-05-28 |
| Kate Smith | 22 | 2019-02-05 | 2019-02-18 |
| Cynthia Smith | 53 | 2019-07-05 | 2019-07-04 |
| Pat Smith | 66 | 2018-01-05 | 2018-01-01 |
+---------------+-----+------------------+--------------------+
Нужны советы, как сделать это лучше иБыстрее.
Вот некоторый код, который иллюстрирует, что я делаю.
# here is some fake data (this dataframe is LARGE)
import pandas as pd
data = [['John Smith', 23, '2018-04-05'], ['Sugar Smith', 43, '2019-10-05'],
['Edward Smith', 34, '2019-05-05'], ['James Smith', 42, '2018-03-05'],
['Sarah Smith', 65, '2018-06-05'], ['Kate Smith', 22, '2019-02-05'],
['Cynthia Smith', 53, '2019-07-05'], ['Pat Smith', 66, '2018-01-05']]
df = pd.DataFrame(data, columns=["name","age","last_purchase_dt"])
Вот где начинается уродство.
# this is my terrible code
# GOAL: new column in df to have the nearest holiday date
# (so I can subtract and get a difference in days)
# this just adds a year to a given date
from dateutil.parser import parse
def addYears(d, years):
try:
#Return same day of the current year
return d.replace(year = d.year + years)
except ValueError:
#If not same day, it will return other, i.e. February 29 to March 1 etc.
return d + (date(d.year + years, 1, 1) - date(d.year, 1, 1))
# limit to a year beyond my data on either side, hopefully to help with performance?
min_data_date = df['last_purchase_dt'].min()
max_data_date = df['last_purchase_dt'].max()
min_data_date = addYears(parse(min_data_date),-1)
max_data_date = addYears(parse(max_data_date), 1)
# Now get the US holidays
import pandas.tseries.holiday as hol
us_cal = hol.USFederalHolidayCalendar()
dr = pd.date_range(start=min_data_date, end=max_data_date)
us_holidays = pd.DataFrame(us_cal.holidays(start=dr.min(), end=dr.max()))
И, наконец, попытка работы:
# function to find the closest date to a given date?
def closest_dt(dt, holidays):
return holidays.iloc[(holidays[0]-parse(dt)).abs().argsort()[:1]]
df['nearest_holiday_date'] = df['last_purchase_dt'].apply(lambda x: closest_dt(x, us_holidays))
Идеи о том, как сделать это лучше, элегантнее, но главное, быстрее на больших наборах данных?