我有一个看起来像这样的数据框(通常有很多用户):
userid | activityday
222 2015-01-09 12:00
222 2015-01-10 12:00
222 2015-01-11 12:00
222 2015-01-13 12:00
222 2015-01-14 12:00
222 2015-01-15 12:00
222 2015-01-17 12:00
222 2015-01-18 12:00
222 2015-01-19 12:00
222 2015-01-20 12:00
222 2015-01-20 12:00
我想获取到给定日期的连续活动天数和非活动天数的总数。例如,如果日期为2015-01-23,则:
userid | days_active_jb | days_inactive_jb | ttl_days_active | ttl_days_inactive
222 | 3 | 2 | 10 | 2
或者,如果给定的日期是2015年1月15日,则:
userid | days_active_jb | days_inactive_jb | ttl_days_active | ttl_days_inactive
222 | 2 | 0 | 5 | 1
我有大约300.000行要处理以获取此最终数据帧。我想知道什么是实现这一目标的有效方法。有任何想法吗?
以下是每列的说明:
days_active_jb
:学生在给定日期之前连续进行活动的天数。days_inactive_jb
:学生在给定日期之前连续没有活动的天数。ttl_days_active
:学生在给定日期前一天进行活动的天数。ttl_days_inactive
:学生在给定日期前一天没有活动的天数。 最佳答案
设定:
df
Out[1714]:
userid activityday
0 222 2015-01-09 12:00:00
1 222 2015-01-10 12:00:00
2 222 2015-01-11 12:00:00
3 222 2015-01-13 12:00:00
4 222 2015-01-14 12:00:00
5 222 2015-01-15 12:00:00
6 222 2015-01-17 12:00:00
7 222 2015-01-18 12:00:00
8 222 2015-01-19 12:00:00
9 222 2015-01-20 12:00:00
11 322 2015-01-09 12:00:00
12 322 2015-01-10 12:00:00
13 322 2015-01-11 12:00:00
14 322 2015-01-13 12:00:00
15 322 2015-01-14 12:00:00
16 322 2015-01-15 12:00:00
17 322 2015-01-17 12:00:00
18 322 2015-01-18 12:00:00
19 322 2015-01-19 12:00:00
20 322 2015-01-20 12:00:00
解
def days_active_jb(x):
x = x[x<pd.to_datetime(cut_off_days)]
if len(x) == 0:
return 0
x = [e.date() for e in x.sort_values(ascending=False)]
prev = x.pop(0)
i = 1
for e in x:
if (prev-e).days == 1:
i+=1
prev = e
else:
break
return i
def days_inactive_jb(x):
diff = (pd.to_datetime(cut_off_days) -max(x)).days
return 0 if diff<0 else diff
def ttl_days_active(x):
x = x[x<pd.to_datetime(cut_off_days)]
return len(x[x<pd.to_datetime(cut_off_days)])
def ttl_days_inactive(x):
#counter the missing days between start and end dates
x = x[x<pd.to_datetime(cut_off_days)]
return len(pd.date_range(min(x),max(x))) - len(x)
#drop duplicate userid-activityday pairs
df = df.drop_duplicates(subset=['userid','activityday'])
cut_off_days = '2015-01-23'
df.sort_values(by=['userid','activityday'],ascending=False).\
groupby('userid')['activityday'].\
agg([days_active_jb,
days_inactive_jb,
ttl_days_active,
ttl_days_inactive]).\
astype(np.int64)
Out[1856]:
days_active_jb days_inactive_jb ttl_days_active ttl_days_inactive
userid
222 4 2 10 2
322 4 2 10 2
cut_off_days = '2015-01-15'
df.sort_values(by=['userid','activityday'],ascending=False).\
groupby('userid')['activityday'].\
agg([days_active_jb,
days_inactive_jb,
ttl_days_active,
ttl_days_inactive]).\
astype(np.int64)
Out[1863]:
days_active_jb days_inactive_jb ttl_days_active ttl_days_inactive
userid
222 2 0 5 1
322 2 0 5 1