使用以下数据框:
import pandas as pd
df = pd.DataFrame(
{
'user_id': ['1', '2', '3'],
'promo_date': ['01012023','01012023','01012023'],
'logins': [['10242022', '11242022', '04122023'], ['10242022', '04122023'], []]
}
)
看起来像:
user_id promo_date logins
0 1 01012023 [10242022, 11242022, 04122023]
1 2 01012023 [10242022, 04122023]
2 3 01012023 []
我正在尝试统计促销日期前 3 个月内某人登录的所有次数。我有一个使用 apply
调用的函数来执行此操作,但对于我拥有的记录数量来说,它太慢了。
from dateutil.relativedelta import relativedelta
EXPECTED_DATE_FORMAT = '%m%d%Y'
def calculate_NTimesLoggedInXMonths(x_months, promo_date_str, login_dates):
login_count = 0
promo_date = pd.to_datetime(promo_date_str, format=EXPECTED_DATE_FORMAT)
x_month_back = promo_date - relativedelta(months=x_months)
for date in login_dates:
if x_month_back < pd.to_datetime(date, format=EXPECTED_DATE_FORMAT) < promo_date:
login_count += 1
return login_count
# Start the calculation
start = datetime.now()
print("Start time is ", start)
df[f'NTimesLoggedIn3Months'] = df.apply(
lambda row: calculate_NTimesLoggedInXMonths(3, row['promo_date'], row['logins']),
axis=1
)
end = datetime.now()
print("Run time:", end - start)
预期结果是:
promo_date logins NTimesLoggedIn3Months
0 01012023 [10242022, 11242022, 04122023] 2
1 01012023 [10242022, 04122023] 1
2 01012023 [] 0
我认为最好的解决方案是利用 Series.dt 访问器,但我不确定如何使用列表来做到这一点。即使我将列表分开,以便每次登录时都会重复每个 id,我仍然不确定如何使用 dt 访问器来获取此计数。
最佳答案
我建议扩展列表,以便更好地利用 pandas 优化来处理 Series。
exp = df.explode('logins')
exp['promo_date'] = pd.to_datetime(exp['promo_date'], format='%m%d%Y')
exp['logins'] = pd.to_datetime(exp['logins'], format='%m%d%Y')
exp['within_3mo'] = ((exp['promo_date'] - pd.DateOffset(months=3) <= exp['logins']) &
(exp['logins'] <= exp['promo_date']))
然后,您可以使用 user_id 上的 groupby 来计算总和。
>>> exp.groupby('user_id')['within_3mo'].sum()
user_id
1 2
2 1
3 0
Name: within_3mo, dtype: int64
关于python - 计算一个日期在另一个日期的 x 个月内出现的次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74748653/