
本文详解如何在时间序列数据中按时间点滚动计算均值,同时确保每个姓名仅保留最新记录(去重取 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 或异常捕获。
掌握此类“滚动 + 去重 + 聚合”组合逻辑,不仅适用于面试,更是构建用户行为分析、实时指标看板、时序特征工程的核心能力。核心要义始终是:明确窗口定义 → 精确筛选有效记录 → 安全聚合。










