计算滚动时间窗口内去重姓名后的均值(面试题解析与高效实现)

5次阅读

计算滚动时间窗口内去重姓名后的均值(面试题解析与高效实现)

本文详解如何在时间序列数据中按时间点滚动计算均值,同时确保每个姓名仅保留最新记录(去重取 last),避免重复累加,提供可扩展、低冗余的 pandas 实现方案。

本文详解如何在时间序列数据中按时间点滚动计算均值,同时确保每个姓名仅保留最新记录(去重取 last),避免重复累加,提供可扩展、低冗余的 pandas 实现方案。

数据分析算法面试中,常遇到一类“带条件的滚动聚合”问题:要求在按时间递增的窗口中动态维护唯一键(如用户、姓名)的最新状态,并基于该状态实时计算统计量(如均值)。本题即典型场景——给定按 time 排序的观测数据,需对每个时间点 t,计算所有 time ≤ t 的记录中、每个 names 仅保留最后一次出现的 val 后的均值。

关键挑战在于:

  • ❌ 不能简单按 time 分组后求均值(会遗漏跨时间点的去重逻辑);
  • ❌ 不能对每个 t 全量重算去重集合(违反“不重复计算”的效率要求);
  • ✅ 正确路径是:对每个 t,构建“截至 t 的全部历史记录”,再按 names 去重(保留 last),最后对剩余 val 求均值。

以下为清晰、可读性强且符合工程实践的 Pandas 实现:

import pandas as pd  def rolling_mean_unique_last(data: pd.DataFrame, time_col: str = "time",                                name_col: str = "names", val_col: str = "val") -> dict:     """     计算滚动时间窗口下,按姓名去重(取最后一次)后的均值。      Parameters:     -----------     data : pd.DataFrame         输入数据,必须包含 time_col, name_col, val_col 列     time_col : str         时间列名(用于定义滚动窗口边界)     name_col : str         唯一键列名(如用户名、ID),需去重     val_col : str         数值列名(用于计算均值)      Returns:     --------     dict : {time_point: mean_value}     """     # 确保按时间升序排列(必要前提)     data = data.sort_values(by=time_col).reset_index(drop=True)      means = {}     for t in data[time_col].unique():  # 遍历每个唯一时间点         # 构建“截至时间 t”的子集(含所有 time <= t 的行)         window = data[data[time_col] <= t]         # 对 names 去重:保留每个名字在该窗口内的最后一条记录(即最新值)         mask = ~window[name_col].duplicated(keep="last")         # 计算去重后 val 的均值         means[t] = window[mask][val_col].mean()      return means  # 示例数据 data = pd.DataFrame({     'time': [1, 1, 1, 2, 2, 2],     'names': ["Andy", "Bob", "Karen", "Andy", "Matt", "Sim"],     'val': [1, 2, 3, 5, 6, 8] })  result = rolling_mean_unique_last(data) print(result) # 输出: {1: 2.0, 2: 4.8}

结果验证

  • time=1:窗口含 [Andy:1, Bob:2, Karen:3] → 无重复 → 均值 = (1+2+3)/3 = 2.0
  • time=2:窗口含全部6行;names 去重(keep=”last”)后保留:
    Andy→5(覆盖 time=1 的 1),Bob→2,Karen→3,Matt→6,Sim→8
    → 均值 = (5+2+3+6+8)/5 = 24/5 = 4.8

⚠️ 注意事项与优化建议

  • 时间复杂度:当前实现为 O(T × N),其中 T 是唯一时间点数,N 是总行数。对超大数据集,可改用 groupby().apply() + 累积状态字典进一步优化至 O(N),但可读性下降;面试场景中本解法已体现清晰逻辑与正确性优先原则。
  • 稳定性依赖:务必保证输入 data 已按 time 升序排序,否则 duplicated(keep=”last”) 在子窗口中行为不可控。代码中已内置 sort_values 防御。
  • 扩展性:函数参数化列名,支持任意字段命名;返回 dict 易于后续转为 Series 或 DataFrame(如 pd.Series(result))。
  • 边界处理:若某时间点无数据,window[mask][val_col] 将为空,.mean() 返回 NaN —— 可根据业务需求添加 skipna=False 或异常捕获。

掌握此类“滚动 + 去重 + 聚合”组合逻辑,不仅适用于面试,更是构建用户行为分析、实时指标看板、时序特征工程的核心能力。核心要义始终是:明确窗口定义 → 精确筛选有效记录 → 安全聚合

text=ZqhQzanResources