解析XML转pandas DataFrame及按统一时间戳合并问题排查
问题根因
你的解析函数存在两处核心逻辑错误:
- 示例XML中所有待提取字段都是
<Row>节点的标签属性,不存在同名字节点。代码仅对传入的第一个字段调用attrib.get()读取属性,其余字段全部用find()方法查找当前节点下的子元素,自然全部返回None。 - 循环取值时遍历了完整的
df_cols列表,会重复读取第一个字段,导致行数据长度和列数不匹配,存在逻辑冗余。
修正后的XML解析代码
直接从节点的attrib属性字典中提取目标字段即可,同时可以在解析阶段提前做类型转换,减少后续数据处理的工作量:
import pandas as pd import xml.etree.ElementTree as ET def parse_XML(xml_path, target_cols): root = ET.parse(xml_path).getroot() rows = [] for row_node in root: # 直接从节点属性字典提取目标列 row_data = {col: row_node.attrib.get(col) for col in target_cols} rows.append(row_data) df = pd.DataFrame(rows, columns=target_cols) # 时间列自动转datetime类型 if "DataSrvTime" in target_cols: df["DataSrvTime"] = pd.to_datetime(df["DataSrvTime"]) # 数值类列自动转数值类型,跳过时间、十六进制字符串类非数值列 numeric_cols = [col for col in target_cols if col not in ["DataSrvTime", "XData"]] df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric, errors="coerce") return df # 调用示例 path = "c:/mypath/" df_ptu = parse_XML(path + "PTU.xml", ["DataSrvTime", "SP", "T", "Hum", "Alt"]) df_ams = parse_XML(path + "AMS.xml", ["DataSrvTime", "MeasurementOffset", "GpsTO", "XData"]) # GPS文件按实际字段名传入即可 df_gps = parse_XML(path + "GPS.xml", ["DataSrvTime", "对应GPS字段1", "对应GPS字段2"])
多传感器数据时间对齐合并优化方案
你原本的resample+interpolate思路是可行的,优化后可以避免单独重采样导致的时间点错位问题,流程如下:
- 所有解析完成的DataFrame先将
DataSrvTime设为索引,按时间排序 - 取所有数据集的时间起止范围,生成统一间隔(如1秒)的全局时间索引,避免各表单独重采样出现时间轴不对齐的问题
- 每个数据集单独重采样到全局时间轴,数值字段取对应时间窗内的均值,非数值字段(如XData)可以取时间窗内的最近值
- 沿列方向拼接所有重采样后的数据集,统一做插值补全空缺,时间序列推荐使用
method="time"按时间距离加权插值,结果更准确
对应实现代码:
# 1. 设置时间索引并排序 df_ptu = df_ptu.set_index("DataSrvTime").sort_index() df_ams = df_ams.set_index("DataSrvTime").sort_index() df_gps = df_gps.set_index("DataSrvTime").sort_index() # 2. 生成全局统一1秒间隔时间轴 all_ts = pd.concat([df_ptu.index.to_series(), df_ams.index.to_series(), df_gps.index.to_series()]) ts_start = all_ts.min().floor("S") ts_end = all_ts.max().ceil("S") uniform_idx = pd.date_range(start=ts_start, end=ts_end, freq="S") # 3. 各表重采样到统一时间轴 resample_ptu = df_ptu.resample("S").mean().reindex(uniform_idx) # 非数值列XData取每秒最近的一条记录 resample_ams_num = df_ams[["MeasurementOffset", "GpsTO"]].resample("S").mean() resample_ams_str = df_ams[["XData"]].resample("S").nearest() resample_ams = pd.concat([resample_ams_num, resample_ams_str], axis=1).reindex(uniform_idx) resample_gps = df_gps.resample("S").mean().reindex(uniform_idx) # 4. 合并并插值 merged_df = pd.concat([resample_ptu, resample_ams, resample_gps], axis=1) # 可加limit参数限制最大连续插值步长,避免无效外推 merged_df[["SP", "T", "Hum", "Alt", "MeasurementOffset", "GpsTO"]] = merged_df[["SP", "T", "Hum", "Alt", "MeasurementOffset", "GpsTO"]].interpolate(method="time", limit=3)
如果传感器采样率远高于目标时间间隔,重采样取均值可以有效平滑噪声;如果采样率低于目标间隔,建议根据传感器精度调整插值方法和最大插值步长,避免引入失真数据。
内容的提问来源于stack exchange,提问作者Swawa
相关产品推荐
相关产品推荐

