高效实现:统计用户每段新订阅期首次观看的内容title
解决大数据量下订阅期首次观看内容统计问题
核心思路
放弃循环,用Pandas的高效时间匹配和分组聚合方法,避免内存溢出。以下是分步实现方案:
1. 数据预处理:统一时间格式+优化内存
先确保所有时间列都是datetime类型,同时优化数据类型降低内存占用:
import pandas as pd # 处理订阅DF(记为df_sub) df_sub['start_ts'] = pd.to_datetime(df_sub['start_ts']) df_sub['end_ts'] = pd.to_datetime(df_sub['end_ts']) df_sub['ids'] = df_sub['ids'].astype('category') # 处理观看记录DF(记为df_view) df_view['ts_start'] = pd.to_datetime(df_view['ts_start']) df_view['ids'] = df_view['ids'].astype('category') df_view['title'] = df_view['title'].astype('category')
2. 高效匹配订阅期与观看记录
用merge_asof按用户ID和时间范围匹配,这比普通merge或循环快几个数量级:
# 先对两个DF按ids和时间列排序(merge_asof要求) df_sub_sorted = df_sub.sort_values(['ids', 'start_ts']) df_view_sorted = df_view.sort_values(['ids', 'ts_start']) # 匹配:每个观看记录对应到它所属的订阅期 df_merged = pd.merge_asof( df_view_sorted, df_sub_sorted, left_on='ts_start', right_on='start_ts', by='ids', direction='backward', # 找ts_start之前最近的未过期订阅期 allow_exact_matches=True ) # 过滤掉观看时间超出订阅期的记录(避免匹配到已过期的订阅) df_merged = df_merged[df_merged['ts_start'] <= df_merged['end_ts']]
3. 提取每个订阅期内的首次观看内容
按用户ID和订阅期(用start_ts标识唯一订阅期)分组,取每组中最早的观看记录对应的title:
# 按ids和start_ts分组,保留每个组中ts_start最小的行 first_watches = df_merged.sort_values('ts_start').groupby(['ids', 'start_ts']).first().reset_index() # 提取首次观看的title列表 first_titles = first_watches['title']
4. 统计title频次
直接用value_counts统计即可:
title_stats = first_titles.value_counts().reset_index() title_stats.columns = ['title', 'count']
额外性能优化建议
- 如果内存仍紧张,用
dask.dataframe替代Pandas,它支持分块处理大数据集,无需一次性加载全部数据到内存。 - 可先过滤
df_view中重复的(ids, ts_start, title)记录,减少匹配的数据量。
内容的提问来源于stack exchange,提问作者Dmitri
相关产品推荐
相关产品推荐

