基于Pandas GroupBy计算四分位距与中位数:无零填充的向量化方案
嘿,我完全懂这种大数据量下的头疼——显式填充零直接把内存拉爆,遍历分组更是慢到离谱。其实你根本不需要填充零或者遍历,用pandas的向量化分组聚合就能完美解决,核心思路是只对有数据的非零值计算统计量(因为零不纳入统计,未提及的天数对应的零本来就不需要参与计算),具体方案如下:
第一步:先按user1、user2、day聚合每日总quantity
这一步你应该已经完成了,但还是贴出来确保流程完整:
import pandas as pd # 假设原始数据是df,先按三元组聚合得到每天的总quantity daily_totals = df.groupby(['user1', 'user2', 'day'])['quantity'].sum().reset_index()
第二步:按user1-user2对分组计算中位数和四分位距
这里我们可以用pandas原生的quantile来计算IQR(IQR=75分位数-25分位数),或者结合scipy.stats.iqr,两者都是向量化操作,完全不需要遍历:
方案1:纯pandas实现(无需额外依赖)
# 分组聚合,计算中位数和IQR result = daily_totals.groupby(['user1', 'user2'])['quantity'].agg( median='median', iqr=lambda x: x.quantile(0.75) - x.quantile(0.25) ).reset_index()
方案2:用scipy的iqr(如果需要更灵活的参数,比如处理nan)
from scipy.stats import iqr result = daily_totals.groupby(['user1', 'user2'])['quantity'].agg( median='median', iqr=lambda x: iqr(x, nan_policy='omit') # 若数据存在空值可忽略,你的场景里应该用不上 ).reset_index()
为什么这个方案可行?
你之前的误区是以为需要把365天的零都填充进去,但题目明确说零值不纳入统计——未提及的天数对应的零本来就不属于统计样本,所以我们只需要基于每个用户对已经存在的非零quantity值计算即可。这种方式全程是pandas的向量化操作,速度快、内存占用低,完全避免了填充零带来的内存爆炸问题。
额外补充:如果需要包含零值统计(比如计算365个值的IQR/中位数,包括零)
如果是这种特殊场景(虽然你明确说零不纳入统计,但以防万一),我们也可以用向量化方式计算,不需要显式填充零:
def iqr_with_zeros(x): n_non_zero = len(x) n_zeros = 365 - n_non_zero # 计算分位数位置(基于365个值的排序结果) q25_pos = (365 - 1) * 0.25 q75_pos = (365 - 1) * 0.75 if q75_pos < n_zeros: return 0.0 elif q25_pos >= n_zeros: return x.quantile(0.75) - x.quantile(0.25) else: q75_val = x.quantile((q75_pos - n_zeros)/n_non_zero) return q75_val - 0.0 def median_with_zeros(x): n_non_zero = len(x) n_zeros = 365 - n_non_zero median_pos = (365 - 1) * 0.5 if median_pos < n_zeros: return 0.0 else: return x.quantile((median_pos - n_zeros)/n_non_zero) result = daily_totals.groupby(['user1', 'user2'])['quantity'].agg( median=median_with_zeros, iqr=iqr_with_zeros ).reset_index()
内容的提问来源于stack exchange,提问作者irene
相关产品推荐
相关产品推荐

