[每日一练]过去30天的用户活动
#该题目来源于力扣:
1142. 过去30天的用户活动 II - 力扣(LeetCode)
Activity 表:+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| session_id | int |
| activity_date | date |
| activity_type | enum |
+---------------+---------+
该表没有主键,它可能有重复的行。
activity_type 列是 ENUM 类型,可以取(“ open_session”,“ end_session”,“ scroll_down”,“ send_message”)四种活动类型之一。
该表显示了社交媒体网站的用户活动。
请注意,每个会话只属于一个用户。编写解决方案,统计截至 2019-07-27(含)的 30 天内每个用户的平均会话数,四舍五入到小数点后两位。只统计那些会话期间用户至少进行一项活动的有效会话。结果格式如下例所示。示例:输入:
Activity 表:
+---------+------------+---------------+---------------+
| user_id | session_id | activity_date | activity_type |
+---------+------------+---------------+---------------+
| 1 | 1 | 2019-07-20 | open_session |
| 1 | 1 | 2019-07-20 | scroll_down |
| 1 | 1 | 2019-07-20 | end_session |
| 2 | 4 | 2019-07-20 | open_session |
| 2 | 4 | 2019-07-21 | send_message |
| 2 | 4 | 2019-07-21 | end_session |
| 3 | 2 | 2019-07-21 | open_session |
| 3 | 2 | 2019-07-21 | send_message |
| 3 | 2 | 2019-07-21 | end_session |
| 3 | 5 | 2019-07-21 | open_session |
| 3 | 5 | 2019-07-21 | scroll_down |
| 3 | 5 | 2019-07-21 | end_session |
| 4 | 3 | 2019-06-25 | open_session |
| 4 | 3 | 2019-06-25 | end_session |
+---------+------------+---------------+---------------+
输出:
+---------------------------+
| average_sessions_per_user |
+---------------------------+
| 1.33 |
+---------------------------+
解释:用户 1 和 2 每人在过去 30 天有 1 个会话,而用户 3 有 2 个会话。所以平均是 (1 + 1 + 2) / 3 = 1.33 。
思路流程
意思就是取分组后独一无二的session_id的综合除以user_id列的个数,条件是截至 2019-07-27(含)的 30 天内。
所以思路是:先进行时间节点的选择,在进行分组聚合,找出独一无二的user_id,然后再统计user_id的数量和计算session_id的总和,并 将这两个变量存储到新建的两个变量中,最后判断null值后计算公式,存放到自定义的数据框中。
首先是对时间节点的计算2019-07-27(含)的 30 天就是用2019-07-27-activity_date =29天,我们可以再切片中进行取值,首先设定字符串2019-07-27为日期形式并赋值给新建变量finall_time=(pd.to_datetime('2019-07-27')),然后进行finall_time-activity_date,通过代码dt.days返回天数<=29即可:
import pandas as pddef user_activity(activity: pd.DataFrame) -> pd.DataFrame:finall_time=pd.to_datetime('2019-07-27')activity=activity[(finall_time-activity['activity_date']).dt.days<=29]
条件筛选好了,可以进行分组聚合了:
分组后只需要返回唯一的session_id值即可:
import pandas as pddef user_activity(activity: pd.DataFrame) -> pd.DataFrame:finall_time=pd.to_datetime('2019-07-27')activity=activity[(finall_time-activity['activity_date']).dt.days<=29]data=activity.groupby('user_id').agg({'session_id':'nunique'}).reset_index()return data
'''
| user_id | session_id |
| ------- | ---------- |
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
由此可见nunique实现了自动独特值聚合
'''
然后我们兴建分组变量,以便于后面的公式计算取值
import pandas as pddef user_activity(activity: pd.DataFrame) -> pd.DataFrame:finall_time=pd.to_datetime('2019-07-27')activity=activity[(finall_time-activity['activity_date']).dt.days<=29]data=activity.groupby('user_id').agg({'session_id':'nunique'}).reset_index()sum_session_id=data['session_id'].sum()count_user_id=data['user_id'].count()
注意,有可能数据框出现所有的时间都不符合规定,所以可能会出现null值,题目要求如果是null值返回0。所以当条件不符合时,我们的聚合变量sum_session_id和count_user_id为null,他们的长度肯定为0,可以通过这个特性进行条件判断公式变量的null值:
import pandas as pddef user_activity(activity: pd.DataFrame) -> pd.DataFrame:finall_time=pd.to_datetime('2019-07-27')activity=activity[(finall_time-activity['activity_date']).dt.days<=29]data=activity.groupby('user_id').agg({'session_id':'nunique'}).reset_index()return datasum_session_id=data['session_id'].sum()count_user_id=data['user_id'].count()if sum_session_id>0:result=round((sum_session_id/count_user_id),2) else:result=0
最后将新建一个数据框,将公式变量result作为数据返回到数据框中即可。新建数据框的代码:
数据框变量=pd.DataFrame({'自定义列名': [储存的数据]})
import pandas as pddef user_activity(activity: pd.DataFrame) -> pd.DataFrame:finall_time=pd.to_datetime('2019-07-27')activity=activity[(finall_time-activity['activity_date']).dt.days<=29]data=activity.groupby('user_id').agg({'session_id':'nunique'}).reset_index()return datasum_session_id=data['session_id'].sum()count_user_id=data['user_id'].count()if sum_session_id>0:result=round((sum_session_id/count_user_id),2) else:result=0result_df = pd.DataFrame({'average_sessions_per_user': [result]})return result_df