Различия в датах с пандами (включая влияние на производительность) - PullRequest
0 голосов
/ 08 ноября 2019

Я работаю с большими наборами данных, в которых я хотел бы получить новый столбец, основанный на внешнем списке дат (в качестве примера рассмотрим праздничные дни).

Мой код работает ... но это крайне неэффективно, и я знаю, что я действительно разрываю вещи на куски.


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))

Идеи о том, как сделать это лучше, элегантнее, но главное, быстрее на больших наборах данных?

...