我试图计算表中每个用户过去发生的事件数。实际上,我有两个数据帧,一个用于特定时间点'T'的每个用户,一个用于也在时间点发生的每个事件。
下面是用户表的示例:
ID_CLIENT START_DATE
0 A 2015-12-31
1 A 2016-12-31
2 A 2017-12-31
3 B 2016-12-31
事件表的示例:
ID_CLIENT DATE_EVENT
0 A 2017-01-01
1 A 2017-05-01
2 A 2018-02-01
3 A 2016-05-02
4 B 2015-01-01
这个想法是,我希望在"user">
在"start_date"上注册的日期之前发生的事件计数。最终结果示例:
ID_CLIENT START_DATE nb_event_tot
0 A 2015-12-31 0
1 A 2016-12-31 1
2 A 2017-12-31 3
3 B 2016-12-31 1
我已经创建了一个函数,利用".apply"熊猫的功能,但是太慢了…如果有人有一个关于如何加快它的想法,我将不胜感激。我有800K的用户行和200k的事件行,使用apply方法需要长达3个小时。
下面是我要复制的代码:import pandas as pd
def check_below_df(row, df_events, col_event):
# Select the ids
id_c = row['ID_CLIENT']
date = row['START_DATE']
# Select subset of events df
sub_df_events = df_events.loc[df_events['ID_CLIENT'] == id_c, :]
sub_df_events = sub_df_events.loc[sub_df_events[col_event] <= date, :]
count = len(sub_df_events)
return count
def count_events(df_clients: pd.DataFrame, df_event: pd.DataFrame, col_event_date: str = 'DATE_EVENEMENT',
col_start_date: str = 'START_DATE', col_end_date: str = 'END_DATE', col_event:str = 'nb_sin', events = ['compensation']):
df_clients_cp = df_clients[["ID_CLIENT", col_start_date]].copy()
df_event_cp = df_event.copy()
df_event_cp[col_event] = 1
# TOTAL
df_clients_cp[f'{col_event}_tot'] = df_clients_cp.apply(lambda row: check_below_df(row, df_event_cp, col_event_date), axis=1)
return df_clients_cp
# ------------------------------------------------------------------
# ------------------------------------------------------------------
df_users = pd.DataFrame(data={
'ID_CLIENT': ['A', 'A', 'A', 'B'],
'START_DATE': ['2015-12-31', '2016-12-31', '2017-12-31', '2016-12-31'],
})
df_users["START_DATE"] = pd.to_datetime(df_users["START_DATE"])
df_events = pd.DataFrame(data={
'ID_CLIENT': ['A', 'A', 'A', 'A', 'B'],
'DATE_EVENT': ['2017-01-01', '2017-05-01', '2018-02-01', '2016-05-02', '2015-01-01']
})
df_events["DATE_EVENT"] = pd.to_datetime(df_events["DATE_EVENT"])
tmp = count_events(df_users, df_events, col_event_date='DATE_EVENT', col_event='nb_event')
tmp
谢谢你的帮助。
我猜是由pd.apply(axis=1)
引起的,这里有解释。
我估计您可以通过使用不按行应用的函数来改进执行时间,例如通过使用merge和groupby。
首先我们合并帧:
df_merged = pd.merge(df_users, df_events, on='ID_CLIENT', how='left')
然后我们检查整个帧的DATE_EVENT
<=START_DATE
:
df_merged.loc[:, 'before'] = df_merged['DATE_EVENT'] <= df_merged['START_DATE']
然后按CLIENT_ID
和START_DATE
分组,对'before'
列求和:
df_grouped = df_merged.groupby(by=['ID_CLIENT', 'START_DATE'])
df_out = df_grouped['before'].sum() # returns a series
最后,我们将df_out
(一个序列)转换回一个数据框,将新列重命名为'nb_event_tot'
,然后重置索引以获得所需的输出:
df_out = df_out.to_frame('nb_event_tot')
df_out = df_out.reset_index()