Python不使用for循环统计各时间戳系统内客户数量的实现方法
无循环实现每小时系统内客户数统计的方案
你当前使用的双层for循环时间复杂度为O(M*N)(M为小时时间点数量,N为客户记录条数),数据量大时效率极低,以下两种方案可完全避免显式for循环,性能提升数十倍以上:
方案1:pandas广播比较(简单易维护,适配中小数据量)
利用numpy广播特性做批量比较,全程底层C实现运算:
import pandas as pd # 提取三个时间列的numpy数组 time_arr = time_range['Time'].values arrival_arr = test['Arrival'].values departure_arr = test['Departure'].values # 广播对比后按行求和,直接得到每个时间点的客户数 time_range['Census'] = ((time_arr[:, None] >= arrival_arr) & (time_arr[:, None] < departure_arr)).sum(axis=1)
注:[:, None]作用是将一维时间数组扩展为二维数组,触发广播机制和所有客户的到离时间批量对比
方案2:事件差分法(性能最优,适配百万级以上大数据量)
如果数据量极大,广播法会占用较多内存,差分法时间复杂度仅为O(M + N log N),内存占用极低:
# 1. 构造事件序列:到店客户数+1,离店客户数-1 events = pd.concat([ pd.DataFrame({'Time': test['Arrival'], 'delta': 1}), pd.DataFrame({'Time': test['Departure'], 'delta': -1}) ]) # 2. 按时间排序事件后计算累计客户数 events = events.sort_values('Time') events['cum_cnt'] = events['delta'].cumsum() # 3. 把累计客户数匹配到小时时间戳上 time_range['Census'] = pd.merge_asof( time_range.sort_values('Time'), events, on='Time', direction='backward' )['cum_cnt'].fillna(0).astype(int)
注意:两种方案使用前请确保Time、Arrival、Departure三列均为pandas datetime类型,避免字符串比较逻辑错误
内容的提问来源于stack exchange,提问作者Nsh
相关产品推荐
相关产品推荐

