Python计算客户每日在线时长无法获取指定范围全量日期数据问题
问题排查
原有代码存在以下几处核心问题,导致无法输出指定日期范围内的所有在线时长记录:
- 循环内未重置临时DataFrame:
train__df定义在循环外,每次迭代没有清空重建,上一个客户的ping数据会残留,引发日期统计错误 - 仅统计有ping记录的日期:当前的
unique_dates是从用户实际产生ping的日期中去重得到的,用户当天未上线(无ping记录)的日期不会出现在结果中,自然无法覆盖2017年6月1日到21日的全日期范围 - 无数据用户的判断逻辑错误:如果某客户完全没有ping记录,
train__df['timestamp']是空序列,取索引0的操作会直接抛出索引越界错误 - 废弃API性能问题:pandas的
append方法已废弃,逐行追加DataFrame效率极低,数据量大时性能会非常差
修复后实现代码
import pandas as pd import datetime import math # 定义目标统计日期范围 START_DATE = datetime.date(2017, 6, 1) END_DATE = datetime.date(2017, 6, 21) # 生成全量目标日期列表,格式和后续数据对齐 ALL_TARGET_DATES = [d.strftime('%Y-%m-%d') for d in pd.date_range(START_DATE, END_DATE)] final_train_list = [] # 用列表暂存结果,最后一次性转DataFrame,性能更高 excluded_cust_ids = [] for index, cust_id in enumerate(customer_data['id'][:10].values.tolist()): print(f'Started for CustID {cust_id} count is {index}') # 拉取当前客户的所有ping记录 cust_pings = pings_data.loc[pings_data['id'] == cust_id, "timestamp"].reset_index(drop=True) # 判断客户是否完全无有效ping记录 if len(cust_pings) == 0 or math.isnan(cust_pings.iloc[0]): excluded_cust_ids.append(cust_id) # 无任何记录的客户,所有日期时长填0,不需要可以删除下面的循环 for dt in ALL_TARGET_DATES: final_train_list.append({'id': cust_id, 'date': dt, 'hours': 0.0}) continue # 处理当前客户的ping数据 train_df = pd.DataFrame() train_df['timestamp'] = cust_pings train_df['date'] = cust_pings.apply(lambda ts: datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d')) train_df['time'] = cust_pings.apply(lambda ts: datetime.datetime.fromtimestamp(ts).strftime('%H:%M:%S')) # 打印当前客户有数据的唯一日期 unique_active_dates = pd.unique(train_df['date']).tolist() print(unique_active_dates) # 遍历所有目标日期,计算对应时长 for dt in ALL_TARGET_DATES: if dt not in unique_active_dates: # 当天无上线记录,时长记为0 final_train_list.append({'id': cust_id, 'date': dt, 'hours': 0.0}) continue # 当天有上线记录,计算当日在线时长 day_pings = train_df.loc[train_df['date'] == dt].sort_values(by='time') start_time = pd.to_datetime(day_pings['time'].iloc[0]) end_time = pd.to_datetime(day_pings['time'].iloc[-1]) diff_hours = round((pd.Timedelta(end_time - start_time).seconds / 3600), 1) final_train_list.append({'id': cust_id, 'date': dt, 'hours': diff_hours}) # 批量转成最终DataFrame final_train_df = pd.DataFrame(final_train_list) print(final_train_df) print(excluded_cust_ids) final_train_df.to_excel("Final_train_df_excluding_cust_ids.xlsx", index=False) print("completed for all customers except for non-active customers")
补充说明
当前代码沿用了你原有逻辑,用当日首次ping到末次ping的间隔作为在线时长。如果需要统计实际连续在线时长,可在计算时增加相邻ping的间隔判断,间隔小于阈值(比如5分钟)才计入在线时长,累加得到更准确的结果。
内容的提问来源于stack exchange,提问作者ashwinpatil1484
相关产品推荐
相关产品推荐

