☰
变压器油色谱DGA数据建模实战:从数据清洗到故障诊断模型落地
2026/10/13 15:28:05 网站建设 项目流程

简介:这份变压器溶解气体数据集面向电力设备运维人员、故障诊断研究者及机器学习工程师,用于支撑变压器故障识别与智能监控模型的开发验证。数据覆盖中低温过热、高温过热、低能放电、高能放电、局部放电与正常状态六类典型工况,并围绕氢气、甲烷、乙烷、乙烯、乙炔等特征气体的浓度变化展开,便于读者结合比值法与判别函数法开展特征分析与算法对比。资源以rar压缩包形式提供,整体约6.97MB,上游未返回文件总数与类型明细,故不赘述具体构成。目前已有177人学习下载,适合作为故障诊断建模、数据分析和算法验证的实测样本。读者可据此构建分类模型、复现气体比值判据、验证特征工程效果,并对照不同故障类型的气体生成规律,加深对变压器运行状态与潜在风险的理解,为电力系统可靠性研究提供数据支撑。

1. 变压器溶解气体数据.rar:一份油色谱数据到手后,先别急着训练模型

拿到一个名为「变压器溶解气体数据.rar」的压缩包,很多人的第一反应是解压、读表、丢进模型跑一遍准确率。我见过太多这样的流程,最后卡在同一个地方:数据里混着不同电压等级、不同取样周期、不同故障类型的记录,标签还可能是「正常/注意/异常」这种粗粒度分级,模型学到的其实是取样批次的分布,而不是溶解气体和故障之间的物理关系。变压器油中溶解气体分析(DGA)本身是一套成熟的状态评估手段,核心逻辑是:绝缘油在过热或放电条件下裂解产生特征气体,不同故障类型对应不同的气体组合与产气速率。这份数据要解决的,就是把「气体浓度 → 故障类型/严重程度」这条映射做成可复现的建模流程。它适合两类人:一类是做电力设备状态监测、想用真实油色谱数据验证特征工程和分类模型的人;另一类是想把 DGA 从「看三比值表」升级到「批量筛查+趋势预警」的运维工程师。前提是你得先接受一件事——这份数据不是拿来直接喂给神经网络的,清洗和特征构造占掉七成工作量。

2. 解压之后先做数据体检:字段、量纲与标签分布

2.1 先确认压缩包里到底是什么结构

.rar本身只是容器,里面常见的是 CSV、Excel 或者多个按年份/站点拆分的子表。不要假设字段名统一,我一般先做一次目录扫描和编码探测,避免后面读表时中文列名乱码。

# 查看压缩包内文件清单,不解压 unrar l 变压器溶解气体数据.rar # 解压到独立目录,避免污染原始包 mkdir -p dga_raw && unrar x 变压器溶解气体数据.rar dga_raw/ # 查看文件类型与编码(Linux/macOS) file dga_raw/*

逻辑说明:unrar l只列清单,确认里面是单表还是多表;unrar x保留目录结构解压。参数上,如果压缩包有密码,-p后接密码,但多数公开数据集不带密码。解压后先别批量读,用file看编码,中文列名常见 GBK 和 UTF-8 混用,这一步能省掉后面反复调encoding的时间。

2.2 用 pandas 做一次字段体检

DGA 数据的典型字段包括:氢气 H2、甲烷 CH4、乙烷 C2H6、乙烯 C2H4、乙炔 C2H2、一氧化碳 CO、二氧化碳 CO2、总烃,以及取样日期、设备编号、电压等级、故障标签。单位常见 μL/L(即 ppm)。先做缺失率、量纲范围和标签分布三件事。

import pandas as pd import numpy as np df = pd.read_csv("dga_raw/dga.csv", encoding="gbk") # 1) 字段与缺失率 print(df.isna().mean().sort_values(ascending=False).head(10)) # 2) 量纲体检:气体浓度不应为负,总烃应约等于各烃类之和 gas_cols = ["H2", "CH4", "C2H6", "C2H4", "C2H2", "CO", "CO2"] print(df[gas_cols].describe().T[["min", "max", "mean"]]) # 3) 标签分布 if "fault_type" in df.columns: print(df["fault_type"].value_counts(dropna=False))

逻辑说明:缺失率排序能快速定位是「整列缺失」还是「零星缺失」;describe看最小值是否为负、最大值是否离谱(比如 CO2 出现 10 万级,可能是单位混用);标签分布决定后面要不要做重采样。参数上,encoding按上一步探测结果改,GBK 读不了就换utf-8-sig。如果总烃和各烃类之和对不上,说明有重复计数或单位不统一,必须先修。

2.3 标签粒度决定建模路线

很多 DGA 数据的标签是「正常 / 注意 / 异常」三级,也有的是具体故障类型(过热、局部放电、电弧放电)。三级标签适合做筛查模型,具体故障类型适合做诊断模型。如果标签里混着两种粒度,不要硬合并,先按粒度拆成两个子任务。常见做法是:先用三比值或大卫三角做一次规则基线,再用机器学习模型对比提升幅度,这样你能说清楚模型到底带来了多少增量。

3. 特征工程:从原始气体浓度到可解释的 DGA 特征

3.1 三比值法的编码逻辑与实现

三比值法是 DGA 里最经典的规则特征,用 C2H2/C2H4、CH4/H2、C2H4/C2H6 三个比值编码成整数组合,再查表对应故障类型。它的价值不在于多准,而在于可解释、可复现,适合作为基线特征。

def ratio_code(row): # 三比值编码,边界按常见工程阈值处理 r1 = row["C2H2"] / row["C2H4"] if row["C2H4"] > 0 else np.nan r2 = row["CH4"] / row["H2"] if row["H2"] > 0 else np.nan r3 = row["C2H4"] / row["C2H6"] if row["C2H6"] > 0 else np.nan def code(v, t1, t2): if pd.isna(v): return -1 if v < t1: return 0 elif v < t2: return 1 return 2 return pd.Series({ "code_r1": code(r1, 0.1, 3.0), "code_r2": code(r2, 0.1, 1.0), "code_r3": code(r3, 1.0, 3.0), }) df = df.join(df.apply(ratio_code, axis=1))

逻辑说明:三个比值分别对应不同故障的产气特征,编码后组合成 0-2 的整数。参数上,阈值t1/t2是工程经验值,不同标准略有差异,建议先按常见阈值跑通,再在验证集上微调。注意分母为 0 的情况,直接给-1表示无效,不要用 0 填充,否则会引入错误编码。

3.2 产气速率与趋势特征

单次取样只能看「当前状态」,加上时间维度才能看「发展趋势」。如果数据里有设备编号和取样日期,一定要构造产气速率特征:相邻两次取样的浓度差除以时间间隔。

df["sample_date"] = pd.to_datetime(df["sample_date"]) df = df.sort_values(["device_id", "sample_date"]) for col in gas_cols: df[f"{col}_rate"] = ( df.groupby("device_id")[col] .diff() / df.groupby("device_id")["sample_date"].diff().dt.days )

逻辑说明:diff()算相邻差值,除以天数得到每日产气速率。参数上,如果同一设备同一天有多条记录,先去重或取均值,否则速率会失真。产气速率对局部放电和电弧放电的区分度往往比绝对浓度更高,这是很多人忽略的一点。

3.3 特征归一化与共线性处理

气体浓度跨度大,CO2 可能到几千,C2H2 可能只有个位数,直接进模型会被大尺度特征主导。常见做法是对数变换后再标准化,同时检查总烃和各烃类的共线性。

from sklearn.preprocessing import StandardScaler feat_cols = gas_cols + ["code_r1", "code_r2", "code_r3"] df[feat_cols] = df[feat_cols].apply(lambda x: np.log1p(x.clip(lower=0))) scaler = StandardScaler() df[[c + "_z" for c in feat_cols]] = scaler.fit_transform(df[feat_cols])

逻辑说明:log1p压缩长尾,clip(lower=0)防止负值导致对数报错。标准化用fit_transform只在训练集上拟合,验证集和测试集要用训练集的均值方差,否则会数据泄漏。这一步是很多「离线准确率很高、上线就崩」的根源。

4. 建模与验证:别让随机划分骗了你

4.1 按设备划分而不是按样本随机划分

DGA 数据里同一台设备有多条记录,如果随机划分,同一设备的不同时间点会同时出现在训练集和测试集,模型相当于「见过这台设备」,准确率虚高。正确做法是按设备编号分组划分。

from sklearn.model_selection import GroupShuffleSplit gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42) train_idx, test_idx = next(gss.split(df, groups=df["device_id"])) train_df = df.iloc[train_idx] test_df = df.iloc[test_idx]

逻辑说明:groups传设备编号,保证同一设备只出现在一侧。参数上,test_size按数据量定,设备数少于 50 时建议用交叉验证而不是单次划分。这一步做完,准确率通常会掉几个点,但那个数字才是可信的。

4.2 基线模型与对比

先用逻辑回归或决策树做基线,再用随机森林或梯度提升对比。不要一上来就上深度学习,DGA 数据量通常不大,树模型更稳。

from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report X_train = train_df[[c + "_z" for c in feat_cols]] y_train = train_df["fault_type"] X_test = test_df[[c + "_z" for c in feat_cols]] y_test = test_df["fault_type"] lr = LogisticRegression(max_iter=1000, class_weight="balanced") lr.fit(X_train, y_train) print("LR:\n", classification_report(y_test, lr.predict(X_test))) rf = RandomForestClassifier(n_estimators=300, class_weight="balanced", random_state=42) rf.fit(X_train, y_train) print("RF:\n", classification_report(y_test, rf.predict(X_test)))

逻辑说明:class_weight="balanced"处理类别不均衡,DGA 数据里正常样本远多于故障样本。参数上,n_estimators300 起步,再大边际收益低;max_depth不设时树会深,建议用交叉验证调。看报告时重点看故障类的召回率,漏报比误报代价高。

4.3 用 SHAP 看模型到底学了什么

树模型可解释性可以用 SHAP 值看特征贡献,确认模型没有依赖设备编号或取样日期这类泄漏特征。

import shap explainer = shap.TreeExplainer(rf) shap_values = explainer.shap_values(X_test) shap.summary_plot(shap_values, X_test, plot_type="bar")

逻辑说明:TreeExplainer对树模型效率高,summary_plot按特征重要性排序。如果排在前面的不是气体浓度或比值特征,而是某个编码或日期衍生特征,就要回头查数据泄漏。这一步是上线前的最后一道保险。

5. 避坑与排查:DGA 数据建模最常见的五个翻车点

5.1 单位混用导致浓度量级错乱

现象:同一列气体浓度,部分记录是 μL/L,部分是 mg/L 或百分比,describe里最大值和最小值差几个数量级。原因:不同来源的数据表直接拼接,没有做单位归一。解决:先按设备或来源分组统计量纲,确认单位后统一换算到 μL/L,换算系数查标准,不要凭感觉乘。

5.2 标签泄漏:用未来数据预测过去

现象:离线准确率 0.98,上线后一塌糊涂。原因:特征里混入了取样日期之后的记录,或者用了全量数据做标准化。解决:按时间切分训练/测试,标准化只在训练集拟合,产气速率特征确认只用了历史记录。

5.3 三比值编码的边界陷阱

现象:模型对某些故障类型完全无召回。原因:三比值阈值设得太死,边界附近的样本被编码到错误区间。解决:把编码从硬阈值改成模糊隶属度,或者直接把原始比值作为连续特征输入模型,让模型自己学边界。

5.4 缺失值填充引入偏差

现象:填充后模型在缺失率高的设备上表现差。原因:用全局均值填充,忽略了设备差异。解决:按设备分组填充,或者把「是否缺失」作为一个二值特征加进去,让模型知道这条记录的信息完整度。

5.5 类别不均衡下的准确率幻觉

现象:准确率 0.95,但故障类召回率不到 0.3。原因:正常样本占绝大多数,模型全预测正常也能拿高准确率。解决:看混淆矩阵和每类召回率,用class_weight或重采样,评估指标换成宏平均 F1 或故障类召回率。

6. 把模型变成可复现的筛查流程:一个最小落地技巧

前面几章把数据体检、特征工程、建模验证和避坑都过了一遍,最后一章落到一个具体技巧:怎么把整个流程封装成一条命令能跑通的筛查脚本,方便后续换数据、换阈值、换模型时快速复现。我一般会写一个run_dga.py,把配置抽成字典,数据路径、特征列表、模型类型、评估指标都从配置读,这样下次拿到新的.rar只需要改配置,不用动代码。

# run_dga.py import yaml import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GroupShuffleSplit from sklearn.metrics import f1_score def load_config(path="config.yaml"): with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f) def main(): cfg = load_config() df = pd.read_csv(cfg["data_path"], encoding=cfg["encoding"]) # 特征与标签 feat_cols = cfg["feature_cols"] label_col = cfg["label_col"] group_col = cfg["group_col"] # 按设备分组划分 gss = GroupShuffleSplit(n_splits=1, test_size=cfg["test_size"], random_state=42) train_idx, test_idx = next(gss.split(df, groups=df[group_col])) train_df, test_df = df.iloc[train_idx], df.iloc[test_idx] model = RandomForestClassifier( n_estimators=cfg["n_estimators"], class_weight="balanced", random_state=42, ) model.fit(train_df[feat_cols], train_df[label_col]) pred = model.predict(test_df[feat_cols]) score = f1_score(test_df[label_col], pred, average="macro") print(f"macro F1: {score:.4f}") if __name__ == "__main__": main()

配套的config.yaml长这样:

data_path: "dga_raw/dga.csv" encoding: "gbk" feature_cols: - H2_z - CH4_z - C2H6_z - C2H4_z - C2H2_z - code_r1 - code_r2 - code_r3 label_col: "fault_type" group_col: "device_id" test_size: 0.2 n_estimators: 300

逻辑说明:配置和代码分离,换数据只改 YAML;GroupShuffleSplit保证设备不跨集;f1_score用宏平均,避免类别不均衡下的准确率幻觉。参数上,n_estimators和test_size是最常调的两个,前者影响训练时间,后者影响评估稳定性。这个脚本不追求一步到位,它的价值在于把「数据体检 → 特征 → 划分 → 模型 → 指标」这条链路固定下来,后面每次迭代只改一个环节,能清楚知道是数据变了还是模型变了。

我自己的习惯是:拿到任何一份 DGA 数据,先跑一遍这个脚本拿到基线 macro F1,再决定要不要加特征、换模型。如果基线已经够用,就不折腾;如果不够,至少知道差距在哪。血泪经验是,很多翻车不是因为模型不够强,而是因为划分方式错了、单位没统一、或者标签本身就有问题。把这三件事先做对,比换十个模型都管用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询