3. 边缘数据预处理与清洗
任务说明
本案例针对边缘网关采集到的温度传感器原始数据流,实现一个轻量级的数据预处理模块,完成三项核心任务:去噪(剔除突变异常值)、缺失值填充(线性插值)和格式标准化(统一时间戳与数值精度)。处理后的数据可直接用于边缘侧的上层分析或转发至云端。
实现方案
使用Python标准库实现,不依赖第三方数据处理框架,便于在资源受限的边缘设备上直接运行。核心逻辑封装为Preprocessor类,输入为原始记录列表,输出为清洗后的标准化记录列表。
- 去噪:采用滑动窗口中值滤波,窗口大小为5,能有效去除单点脉冲噪声,同时保留真实温度变化趋势。
- 缺失值填充:检测时间戳间隔超过阈值(2秒)的缺失区间,使用前后有效值的线性插值进行填充。
- 标准化:时间戳统一为Unix毫秒整数,温度值保留1位小数,输出字段顺序固定为
timestamp, temperature。
完整代码
import json
from collections import deque
from typing import List, Dict, Tuple
class Preprocessor:
def __init__(self, window_size: int = 5, max_gap_ms: int = 2000):
self.window_size = window_size
self.max_gap_ms = max_gap_ms
def _median_filter(self, values: List[float]) -> List[float]:
"""滑动窗口中值滤波去噪"""
result = []
q = deque()
for v in values:
q.append(v)
if len(q) > self.window_size:
q.popleft()
window = sorted(q)
result.append(window[len(window) // 2])
return result
def _fill_missing(self, records: List[Tuple[int, float]]) -> List[Tuple[int, float]]:
"""基于时间间隔检测缺失,线性插值填充"""
filled = []
for i in range(len(records) - 1):
ts_cur, val_cur = records[i]
ts_next, val_next = records[i + 1]
filled.append((ts_cur, val_cur))
gap = ts_next - ts_cur
if gap > self.max_gap_ms:
# 计算缺失点数(最多填充10个点,防止异常大间隙)
n_points = min(int(gap / self.max_gap_ms) - 1, 10)
for j in range(1, n_points + 1):
ratio = j / (n_points + 1)
ts_interp = int(ts_cur + gap * ratio)
val_interp = round(val_cur + (val_next - val_cur) * ratio, 1)
filled.append((ts_interp, val_interp))
filled.append(records[-1])
return filled
def process(self, raw_data: List[Dict]) -> List[Dict]:
"""主处理流程:去噪 → 缺失填充 → 标准化"""
# 1. 按时间戳排序并提取数值
raw_sorted = sorted(raw_data, key=lambda x: x['timestamp'])
timestamps = [r['timestamp'] for r in raw_sorted]
values = [float(r['value']) for r in raw_sorted]
# 2. 中值滤波去噪
denoised = self._median_filter(values)
# 3. 重组为记录并填充缺失
records = list(zip(timestamps, denoised))
filled_records = self._fill_missing(records)
# 4. 标准化输出
result = []
for ts, val in filled_records:
result.append({
'timestamp': int(ts), # 毫秒整数
'temperature': round(val, 1) # 保留1位小数
})
return result
# ========== 最小可运行示例 ==========
if __name__ == '__main__':
# 模拟传感器原始数据(含噪声、缺失、时间戳抖动)
raw_input = [
{"timestamp": 1000, "value": 22.5},
{"timestamp": 1001, "value": 22.6},
{"timestamp": 1002, "value": 45.2}, # 噪声尖峰
{"timestamp": 1003, "value": 22.4},
{"timestamp": 1004, "value": 22.7},
{"timestamp": 1007, "value": 22.9}, # 缺失1005-1006
{"timestamp": 1008, "value": 23.1},
{"timestamp": 1009, "value": 23.0},
]
pre = Preprocessor()
cleaned = pre.process(raw_input)
print(json.dumps(cleaned, indent=2))
运行与验证
运行方式:将代码保存为preprocess.py,在终端执行python3 preprocess.py。
预期输出:程序打印清洗后的JSON数组。关键验证点:
- 时间戳1002处的噪声值45.2被中值滤波修正为22.5左右(窗口内中值);
- 时间戳1005、1006被插值填充,温度值介于22.7和22.9之间线性过渡;
- 所有时间戳为整数毫秒,温度值均为1位小数。
通过条件:输出中不存在原始噪声值45.2,缺失区间被合理填充,且每条记录字段完整、格式统一。若需处理其他传感器数据,只需调整输入JSON的字段名与process方法中的键名映射。