谱聚类与电气距离:电力系统分区从原理到工程实践
简介:本资源面向电力系统分析方向的研究生、科研人员及高级工程师,聚焦于利用谱聚类算法实现电网分区这一关键任务,解决大规模网络中基于电气耦合特性的自动区域划分问题。压缩包为纯MATLAB实现,共2个.m文件,总大小仅1KB,轻量但完整,分别封装了IEEE 30节点系统的数据建模、电气距离矩阵构建、归一化拉普拉斯矩阵求解、特征向量降维及K-means后聚类等核心流程,代码结构清晰、注释明确,便于理解算法原理与工程落地细节。已有501人学习下载,适用于教学演示、算法复现、课程设计及小规模电网分区方案快速验证。读者可直接运行获取分区结果,深入掌握电气距离作为相似性度量的物理意义、谱聚类在图结构数据上的优势,以及从阻抗矩阵到功能分区的完整技术链路。 做电网分析的人,尤其是搞新能源消纳、动态等值、黑启动分区恢复的,大概率都绕不开一个灵魂拷问:电网到底该按什么原则分区?调度规程里的区域划分是按行政和调度管辖关系定的,但从电气特性上看经常“不对味”。比如地理上紧挨着的两个片区,可能因为中间隔着几台大容量变压器或长线路,电气联系其实很弱;反倒是隔着几十公里的两个站点,通过密布的网架形成了强耦合。这时候靠人工经验画圈,费时费力不说,还容易带主观偏见。
我这两年做分区相关项目时,把重心放在了谱聚类算法上。它从图论切入,配合电气距离,能给出相对客观、可复现的分区结果。今天这篇就把我这套从原理到落地的完整思路拆开讲,包括电气距离矩阵怎么算、相似度矩阵怎么构造、特征分解后怎么聚类、以及工程上踩过的几个坑。内容针对从事电力系统规划、运行控制、故障分析的研究人员和工程师,对做图论应用、聚类算法的算法工程师也有参考价值。
1. 为什么电气距离是分区问题的“地基”
1.1 电气距离不是地理距离,而是耦合强度的度量
很多刚接触分区的人第一个误区,就是把“电气距离”想成变电站之间的直线距离或线路长度。实际上,电力系统分析里说的电气距离,衡量的是两个节点之间电气耦合的强弱——耦合越强,电气距离越小;耦合越弱,电气距离越大。
一个直观的理解方式:如果我在节点 i 注入一个单位电流,节点 j 的电压变化越大,说明两者的电气联系越紧密,它们之间的电气距离就越小。反过来,如果 i 点注入电流,j 点电压纹丝不动,那这俩节点基本就是“电气上不熟”,距离就大。
这种定义在物理上非常符合直觉。想想一个 500kV 主网架上的两个变电站,之间可能只隔了一条线路,阻抗很小,任何一个站发生短路故障,另一个站的电压跌落都很明显——它们之间电气距离小,应该分在同一个区域。而两个通过长链式线路连接的末端变电站,中间隔了好几级变电,一个点出问题另一个几乎没反应——电气距离大,通常属于不同区域。
1.2 电气距离的数学表达与计算方法
工程上最常用的电气距离定义,是基于节点阻抗矩阵 Z 的戴维南等效阻抗思路。设电力网络有 n 个节点,节点导纳矩阵为 Y(n×n),对 Y 求逆得到 Z。那么节点 i 和节点 j 之间的电气距离定义为:
d_ij = Z_ii + Z_jj − 2Z_ij
这实际上就是复平面上的一个“电阻值”概念。你可能觉得它跟数值天气预报里用相关距离算站点相似度很像——对,两者思路一致,都是把系统响应特性映射成距离度量。
这里有个工程细节值得注意:如果是全维导纳矩阵(包含所有负荷节点、发电机节点),算出来的阻抗矩阵阶数很高,直接对几千阶的矩阵求逆,计算代价不小。做分区时通常只关心某些关键节点(比如发电机节点),所以实际做法是:
- 只保留需要参与分区的节点集合(比如 10 台发电机的节点),其他节点通过Kron 约减消去;
- 对约减后的节点导纳矩阵求逆,得到约减阻抗矩阵 Z_reduced;
- 用约减矩阵计算目标节点之间的电气距离 d_ij。
Kron 约减的物理意义是把非目标节点的注入电流置零,只保留目标节点的等值网络。这样算出来的电气距离,反映的是在两个关注节点之间,经整个网络形成的等效阻抗,天然就把网架结构的所有路径都包含进去了。
1.3 电气距离矩阵的标准化处理
算出所有节点对的 d_ij 后,会得到一个对称矩阵 D。但直接用这个矩阵喂给聚类算法会有问题:不同系统标幺值差异大,距离量纲也没有归一化。我在实践中最常用的标准化方式是:
- min-max 归一化:把距离线性映射到 [0,1] 区间,公式是 d'_ij = (d_ij − min(D)) / (max(D) − min(D))。
- 倒数的相似度映射:把距离矩阵转成相似度矩阵,常用 W_ij = 1 / (1 + d'_ij) 或高斯核 W_ij = exp(−d_ij² / (2σ²)),σ 的选择直接影响聚类效果,后面专门讲。
这一步决定了后续谱聚类能不能分得开。电气距离如果没处理好,相似度矩阵可能分布很集中,拉普拉斯矩阵的特征值结构不明显,分区就会变成“硬切”。
2. 谱聚类原理:从图割问题到矩阵特征分解
2.1 谱聚类解决的是什么问题
经典的聚类方法如 K-means,直接在原始样本空间里找簇中心,适合球形分布的数据。但电力系统节点之间的关系是图结构——节点是顶点,电气联系是边的权重,节点之间的相似关系不是欧氏空间里的距离,而是图上的连接强度。K-means 直接聚类电气距离矩阵,效果经常不理想,因为它假设簇是凸的,而电网结构下的分组是非凸的、不规则的。
谱聚类高明的地方在于:它先把图割问题转化成矩阵特征分解问题。分区问题在图上等价于:找到一种切法,把图的顶点分成 k 组,使得组内边权重尽可能大(耦合紧密),组间边权重尽可能小(耦合松散)。
设图 G = (V, E),我们要把顶点集 V 分成 k 个子集。最直观的目标函数是 RatioCut:
RatioCut(A1, ..., Ak) = (1/2) Σ (W(Ai, Āi) / |Ai|)
其中 W(Ai, Āi) 是 Ai 到补集的所有边的权重和,|Ai| 是 Ai 的顶点数。
直接最小化 RatioCut 是 NP 难问题,但谱聚类做了一个关键松弛:把离散的划分指示变量放宽成连续实数值,结果发现最优解正好落在图拉普拉斯矩阵的特征向量上。这就是为什么谱聚类最后归结为“求特征向量,再对特征向量做 K-means”。
2.2 拉普拉斯矩阵的三种形态与选择
图拉普拉斯矩阵有三种常见形态,工程中选错会影响结果稳定性:
| 名称 | 公式 | 特点 |
|---|---|---|
| 非归一化拉普拉斯 | L = D − W | 直接,但容易受节点度差异影响 |
| 对称归一化拉普拉斯 | L_sym = D^(−1/2) L D^(−1/2) | 数值稳定,最常用 |
| 随机游走拉普拉斯 | L_rw = D^(−1) L | 与 Markov 过程相关,适合特定场景 |
我在电力系统分区里通常用对称归一化拉普拉斯 L_sym。原因是电网节点度数差异极大——枢纽节点的度远高于末端节点,非归一化拉普拉斯会偏向让大度节点自成一组,归一化后则更公平地对待每个节点。
L_sym 的特征值有个重要性质:都在 [0, 2] 区间内,且 0 特征值的重数等于图的连通分量数。如果做分区前发现特征值 0 的重数超过 1,说明图本身就不连通,这种时候要先检查网络拓扑是否完整,再考虑分区问题。
2.3 谱聚类标准流程
具体到电力系统,谱聚类的完整流程我总结如下:
- 构造加权图:把电网节点作为图的顶点,电气距离经相似度函数换算成边的权重 W_ij。
- 计算度矩阵 D:D_ii = Σ_j W_ij,度矩阵是对角阵。
- 构造拉普拉斯矩阵:L_sym = I − D^(−1/2) W D^(−1/2)。
- 特征分解:求出 L_sym 的前 k 个最小特征值对应的特征向量(注意,是最小特征值,不是最大)。
- 特征向量矩阵:把前 k 个特征向量按列拼成 n×k 矩阵 U,对 U 的每一行做归一化。
- K-means 聚类:把 U 的行向量作为新的样本点,做 K-means 得到 k 个簇,簇标签就是节点分区结果。
这里有个很多人会绕晕的点:为什么要对特征向量矩阵的行做归一化?因为 L_sym 的特征向量本身模长不统一,直接聚类某些节点会被“长度”主导而不是“方向”主导,归一化之后才真正对应到图上的子空间几何结构。
3. 电力系统分区的完整工程实现
3.1 数据准备与网络参数
先把家底摸清楚。做分区至少需要以下数据:
- 节点导纳矩阵 Y(或线路参数、变压器参数,自己组装 Y 矩阵);
- 节点类型信息(PQ 节点、PV 节点、平衡节点);
- 关注节点集合:比如参与分区的发电机节点,或者特定电压等级的变电站节点;
- 基准容量与基准电压:用于标幺化。
如果是从 BPA、PSASP、PSS/E 等工具导出数据,注意导纳矩阵的单位和正负号约定。我遇到过从 PSASP 导出的导纳矩阵虚部符号和 scipy 计算的约定相反,导致距离矩阵很离谱的情况。稳妥做法是用已知结果的简单系统(比如新英格兰 39 节点系统)先验证程序一遍。
3.2 电气距离矩阵计算:实操代码
下面给一个可直接运行的思路,用 Python 实现从导纳矩阵到电气距离矩阵的全过程:
import numpy as np from scipy.sparse import csc_matrix from scipy.sparse.linalg import spilu, LinearOperator, factorized def krons_reduce(Y_full, keep_nodes): """ Kron 约减:消去非关注节点 参数: Y_full: 全维节点导纳矩阵 (n*n) keep_nodes: 需要保留的节点索引列表 返回: Y_reduced: 约减后的导纳矩阵 (m*m) """ keep_nodes = np.asarray(keep_nodes) all_nodes = np.arange(Y_full.shape[0]) remove_nodes = np.setdiff1d(all_nodes, keep_nodes) # 分块 Y_kk = Y_full[np.ix_(keep_nodes, keep_nodes)] Y_kr = Y_full[np.ix_(keep_nodes, remove_nodes)] Y_rk = Y_full[np.ix_(remove_nodes, keep_nodes)] Y_rr = Y_full[np.ix_(remove_nodes, remove_nodes)] # Kron 约减公式: Y_reduced = Y_kk - Y_kr * inv(Y_rr) * Y_rk Y_reduced = Y_kk - Y_kr @ np.linalg.inv(Y_rr) @ Y_rk return Y_reduced def electrical_distance(Y_reduced): """ 由约减导纳矩阵计算电气距离矩阵 d_ij = Z_ii + Z_jj - 2*Z_ij """ Z = np.linalg.inv(Y_reduced) n = Z.shape[0] d = np.zeros((n, n)) # 复阻抗的实部代表有功耦合,工程上多取实部 Z_real = np.real(Z) for i in range(n): for j in range(n): d[i, j] = Z_real[i, i] + Z_real[j, j] - 2 * Z_real[i, j] # 保证对称性 d = (d + d.T) / 2 np.fill_diagonal(d, 0.0) return d注意电气距离里我取了阻抗的实部。对于以有功传输和无功电压支撑为主的电网,实部对应的电阻分量能反映有功耦合强弱,但这也不是绝对标准。纯无功耦合较强的场景,用复阻抗的模长更合适。我在项目里会分别跑实部和模长两组结果,观察分区差异,再结合动态仿真校核最终选哪组。
3.3 相似度矩阵构建:高斯核参数 σ 怎么定
算完电气距离 D 后,最常用的相似度函数是高斯核:
W_ij = exp(−d_ij² / (2σ²))
σ 是一个极其敏感的旋钮。σ 太小,相似度矩阵对角占优,几乎每个节点只和自己相似,整个图退化成孤立点,分区无意义;σ 太大,所有 W_ij 都接近 1,相似度矩阵近似全 1 矩阵,分区也分不出区别。
我工程上常用的 σ 确定方法有三种:
- 经验比例法:σ = α × mean(D),α 取 0.5~1.5,通过轮廓系数微调。
- 分位数法:取电气距离全体值的 50% 或 75% 分位数作为 σ,对异常值不敏感。
- 局部自适应法:每个节点有自己的 σ_i,取该节点到第 K 近邻的距离(比如 K=7),再构造 W_ij = exp(−d_ij² / (σ_i σ_j))。这种方法能兼顾局部密度差异,对电气距离分布不均匀的电网效果明显更好。
我在实际工作中,如果电网规模不大(几十个节点),就手动扫 σ 看拉普拉斯矩阵特征值谱间隙——谱间隙越明显,说明分区结构越清晰。大规模电网则固定用分位数法,减少调参工作量。
3.4 特征分解与 K-means 聚类
下面是谱聚类的核心代码,注意使用的是最小的 k 个特征值对应的特征向量,和很多降维场景用最大特征值相反:
from sklearn.cluster import KMeans def spectral_clustering(W, k): """ 谱聚类主流程 参数: W: 相似度矩阵 (n*n) k: 目标分区数 返回: labels: 每个节点的分区标签 (n,) evals: 特征值(从小到大) """ # 度矩阵 D D = np.diag(W.sum(axis=1)) D_inv_sqrt = np.diag(1.0 / np.sqrt(np.diag(D) + 1e-10)) # 对称归一化拉普拉斯 L_sym = I - D^-1/2 W D^-1/2 L_sym = np.eye(W.shape[0]) - D_inv_sqrt @ W @ D_inv_sqrt L_sym = (L_sym + L_sym.T) / 2 # 强制对称 # 特征分解,取最小的 k 个特征值 evals, evecs = np.linalg.eigh(L_sym) idx = np.argsort(evals)[:k] U = evecs[:, idx] # n*k 矩阵 # 行归一化,消除模长影响 U_normalized = U / np.linalg.norm(U, axis=1, keepdims=True) # K-means 聚类,k-means++ 初始化 + 多次尝试取最优 km = KMeans(n_clusters=k, init='k-means++', n_init=50, random_state=42) labels = km.fit_predict(U_normalized) return labels, evalsK-means 这里为什么是作用在特征向量矩阵 U 的行上?打个比方:每个节点原本是图上的一个点,特征向量给了它一个新坐标(k 维空间里的坐标),而这个新坐标恰好把原来的网络连接结构“摊平”了。在这种情况下,物理上紧耦合的节点在新坐标空间里距离很近,K-means 更容易把它们聚成一堆。
3.5 分区数 k 的确定:矩阵之外还要看物理
k 的选择直接决定分区粒度。纯靠数学指标容易选出“看起来最优但没物理意义”的结果。我的经验是综合考虑以下几方面:
- 特征值谱间隙(eigengap):把 L_sym 的特征值从小到大排序,找相邻特征值差值最大的位置。前面 k 个特征值都很小,第 k+1 个突然变大,说明图天然就分成 k 组。需要注意的是,实际电网数据往往没有特别明显的谱间隙,这时候要结合其他指标判断。
- 轮廓系数:算聚类结果的轮廓系数,取值 [-1,1],越大说明每个节点离自己簇中心越近、离其他簇中心越远。
- 模块度:Q = (1/2m) Σ_ij [A_ij − k_i k_j / (2m)] δ(c_i, c_j),其中 A_ij 是相似度权重,k_i 是节点 i 的度,m 是所有边的权重和。Q 值在 [−1,1],大于 0.3 通常认为有可解释的社区结构。
- 调度分区约束:分区边界最好落在变电站而不是线路中间,每个分区尽量有足够的有功/无功平衡能力,这些物理约束数学优化不好建,但人工经验能快速判断。
我在 39 节点系统上的实践是:特征值谱间隙提示 5 组,轮廓系数最优在 4 组,模块度在 5 组时最高。最后结合故障仿真,发现 5 组时联络线功率波动更小,最终定了 5 组。也就是说,计算只是辅助工具,最后拍板还是看动态行为能不能对上。
4. 工程实现中的关键细节:从踩坑到稳定复现
4.1 矩阵退化:相似度矩阵不连通的坑
谱聚类的最底层假设是图连通。如果图不连通,L_sym 的零特征值重数大于 1,前 k 个最小特征值会包含多个 0,特征向量空间其实是多个连通分量的直和,K-means 聚类结果会非常不稳定。
在实际电网里,这种情况少见,但确实遇到过:用高斯核且 σ 取太小时,相似度矩阵中大量元素接近 0,稀疏得只剩对角线。这时图在数值上等效于不连通。解决办法是:
- 提高 σ,让远距离节点之间也保留一点相似度权重;
- 在图论上做一个连通性前置检查,用 scipy.sparse.csgraph.connected_components 判断连通分量数,多于 1 则说明参数有问题;
- 或者给相似度矩阵加一个正数基底:W_new = W + ε·J,ε 取一个很小的数(如 1e-6),这在数值上强制全连通。
4.2 特征向量的符号不确定性与旋转问题
谱聚类的特征向量有两个经典问题:符号不确定和旋转不确定。同一个特征向量 v 和 −v 特征值相同,K-means 对坐标轴方向的符号变化不敏感(因为距离不变),所以符号问题不影响结果。但如果有特征值非常接近(退化),特征向量子空间可以旋转任意角度,这会导致多次运行结果不同。
我在实践中发现,电网如果存在近似对称的两条联络线,特征值就容易退化。解决办法有两个:
- 增大 (n_init):K-means 里设 n_init=100,多次随机初始化选最优,尽量避开退化方向;
- 对特征向量矩阵做 Procrustes 旋转对齐:多次运行结果做对齐后再投票,取众数作为最终分区。这在生产级代码里值得做。
4.3 特征向量取多少个:k 个还是更多
初学谱聚类的人容易误以为目标分区数是 k,就只取 k 个特征向量。这个做法在理想条件下是对的,但实际数据噪声较大,取 k 个信息量不够。工程上常见的变体是取 k 或者 k+1 个特征向量,甚至取前 10~20 个再通过 PCA 压缩到 k 维。原因是最小的几个特征向量已经包含了图的主要结构,但如果网络的模态比较“胖”(特征值下降很平缓),多取几个能保留更丰富的信息。
我自己的经验法则:先画特征值谱线,看前 k 个特征值和后面的差距。差距明显,取 k 个;差距模糊,取 k+5 个,然后用 PCA 降到 k 维,再做 K-means。效果往往比硬取 k 个稳定。
4.4 大规模电网的计算效率优化
几千节点的大电网直接 np.linalg.eigh 分解几千阶矩阵,内存和时间都扛不住。工程上我优化过几个方向:
- 稀疏特征分解:L_sym 本身是稀疏矩阵,用 scipy.sparse.linalg.eigsh 只求最小 k 个特征值(设置 which='SA'),比稠密分解快几个数量级。
- Kron 约减时用稀疏 LU 分解:约减公式里的 inv(Y_rr) 千万别直接求逆,用 factorized(Y_rr) 得到 LU 分解对象,然后用它对 Y_rk 逐列求解。这个优化在几千阶矩阵上能提速 50 倍以上。
- 相似度矩阵稀疏化:只保留每个节点的前 K 个最近邻相似度,其余置 0,从全连接图变成 K 近邻图,减小存储和计算量。
from scipy.sparse.linalg import eigsh # 稀疏特征分解示例 evals_small, evecs_small = eigsh(L_sym_sparse, k=k, which='SM')注意eigsh对对称矩阵要求是 float32/float64 类型,如果 L_sym 是复数形式要拆实部处理,否则会报错。这也是我为什么在电气距离步骤就取了阻抗实部的原因之一。
4.5 电气距离和相似度矩阵的“度”口径问题
进一步讲一个容易被忽略的细节:度矩阵 D_ii = Σ_j W_ij 是相似度矩阵的行和,它本身反映了节点与全网所有其他节点的“总耦合强度”。在电力系统里,一个枢纽节点通常电气距离都小,度就大;末端节点度就小。如果归一化拉普拉斯没做对,度大的节点在特征向量里会“压制”度小节点,分区的边界经常落在度小节点附近,不一定符合物理期望。
我在实际项目里有个习惯:对度矩阵做一次大值截断(如超过 99% 分位数就压到 99% 分位数),降低枢纽节点对特征向量空间的绝对主导。这样末端节点在分区时不容易被“边缘化”。这个方法不严谨但很有效,算是工程上的一点经验,分享出来供参考。
5. 分区结果的可解释性与物理校验
5.1 特征向量可视化:分区前先看图说话
特征分解后,有一个非常直观的检查手段:把第二小特征向量(Fiedler 向量)作为横轴,第三小特征向量作为纵轴画散点图。如果图结构有清晰的分区,散点会呈现出明显的簇状分布。这一步在投任何自动化聚类之前做,能让人对数据有个直觉。
我见过有同事直接跑 K-means 不看特征向量图,结果分区结果完全不符合物理直觉。后来一画图才发现,特征向量空间里有两个簇之间的“桥接节点”很多,K-means 把这些桥接节点随机分给两边,导致分区不稳定。这种情况下要么改变相似度参数,要么考虑模糊聚类(后面说)。
5.2 分区结果的量化评价指标
分区完成后我一般至少跑三个评价维度:
1. 电气耦合度
定义分区内部的平均电气距离与分区之间的平均电气距离的比值。比值越小,说明区内耦合越紧、区间耦合越松,分区效果越好。公式:
内部耦合系数 = mean{d_ij : i,j ∈ 同一分区, i≠j}外部耦合系数 = mean{d_ij : i ∈ 分区 A, j ∈ 分区 B, A≠B}
理想结果:内部耦合系数显著小于外部耦合系数。
2. 模块度
前面提过,模块度 Q 能反映社区结构强度。电力系统里我把边权重直接用相似度矩阵 W,这样分区质量跟电气距离直接挂钩。
3. 联络线潮流波动或短路电流水平
这是在动态仿真层面的最终校验。如果分区是要用于黑启动或主动解列,那么校验分区边界联络线在故障下的功率波动是否在可接受范围;如果是做无功电压分区,校验分区内无功备用量是否充足。这些物理校验往往比任何聚类指标都有说服力。
5.3 一个 39 节点系统的完整案例
新英格兰 39 节点系统是电力系统算法验证的“标配”,有 10 台发电机。用前面整套方法跑一遍:
- 参与分区的节点:10 台发电机的机端节点(PV 节点);
- 电气距离矩阵:对全网络先做 Kron 约减到 10 个机端节点,算 10×10 距离矩阵;
- 相似度矩阵:高斯核,σ 取距离矩阵 75% 分位数;
- 特征分解:取最小 5 个特征向量,做行归一化;
- K-means:5 组。
结果大致是:G1、G8、G9、G10 聚成一组(对应系统中部区域),G2、G3 一组,G4、G5 一组,G6、G7 一组,还有一组单节点。这和传统慢同调分析给出的区域划分基本一致,但谱聚类在边界节点上更清晰,因为它是根据整体耦合强度来划分的,不是靠单条线路的电气距离。
值得注意的是,单节点分区的出现不代表算法失败。如果某个发电机的电气距离对任何其他发电机都较大,说明它本身就是弱耦合区域,动态行为相对独立,这在规划中反而是重要的提示——该区域可能需要额外的支撑措施。
5.4 和传统慢同调分区、社团检测的对比
| 方法 | 基础理论 | 优点 | 局限 |
|---|---|---|---|
| 专家经验法 | 调度经验 | 直观,符合运行习惯 | 主观强,难以复现 |
| 慢同调法 | 线性化状态空间特征值 | 与动态稳定性关联紧 | 线性化假设,适用工况有限 |
| 社团检测(GN 等) | 图论模块度 | 社区结构效果直观 | 计算量随图规模增长快 |
| 谱聚类 | 图拉普拉斯特征分解 | 理论基础扎实,适合加权图,计算效率高 | 参数 σ 和 k 需要校验 |
谱聚类在理论上和慢同调法有相通之处——图拉普拉斯矩阵的谱结构和系统线性化动态矩阵的慢模态有对应关系,但谱聚类不依赖具体的潮流断面,只需要拓扑和参数,因此在“多工况平均意义”上的分区适应性更好。
6. 扩展玩法:模糊聚类和谱聚类组合,以及后续可以怎么用
6.1 硬分区的边界困境
标准谱聚类得到的是硬划分——每个节点非此即彼地属于某一个分区。这在大多数场景够用,但现实中部分节点处于两个区域的“夹缝”中:它跟 A 区耦合较强、跟 B 区耦合也不弱。硬划分会强行把它塞进某一个区域,丢失了这种模糊性信息。
比如黑启动分区恢复时,边界节点到底放在哪个区,直接影响恢复路径的选择和电源启动顺序。如果有一个“隶属度”概念——节点 80% 属于 A 区、20% 属于 B 区——调度员就能更精细地决策。
6.2 谱聚类 + 模糊 C 均值(FCM)的组合方案
解决思路很简单:把谱聚类最后一步的 K-means 换成模糊 C 均值(Fuzzy C-Means, FCM)。特征向量矩阵 U 照旧算,但最终每个节点不再得到一个硬标签,而是得到一组隶属度向量(和为 1)。
FCM 的目标函数是:
J_m = Σ_i Σ_c (u_ic)^m · ||x_i − v_c||²
其中 u_ic 是节点 i 对簇 c 的隶属度,m 是模糊指数(通常取 2),v_c 是簇中心。迭代更新隶属度和簇中心,直到收敛。
工程流程:
- 谱聚类到得到 U_normalized 为止;
- 输入给 FCM,设簇数 k = 5,模糊指数 m = 2;
- 迭代得到隶属度矩阵 U_fuzzy (n×k);
- 对每个节点,取最大隶属度对应的簇作为主分区,同时保留完整隶属度向量供后续分析。
代码上 scikit-learn 没有现成的 FCM,但可以用 scikit-fuzzy 库,或者自己十几行实现一遍,迭代公式不复杂。我一般自己写,因为可以方便地加入电力领域的约束(比如指定某些关键节点必须属于某个分区)。
6.3 模糊隶属度在运行方式变化中的应用
得到模糊隶属度后,有一个非常实用的用法:对不同运行方式做分区稳定性评估。
电力系统运行方式每天都变(高负荷、低谷、检修方式),拓扑和潮流不同,电气距离也随之变化。如果在每个方式下都跑一次硬分区,某节点在两个方式下可能被分到不同区域,这就给调度规则制定带来麻烦。而用模糊隶属度,可以统计每个节点隶属度向量的“方差”。方差大的节点等于在各运行方式下归属不稳定,属于边界节点。
对这些边界节点,分区方案设计时就应重点考虑其具备在多个区域间灵活切换的能力(比如配置更多联络开关、加装 FACTS 装置等)。这个应用场景我觉得很有价值,属于把算法结果真正转化为规划决策的桥梁。
6.4 后续还能扩展的方向
- 多属性谱聚类:把电气距离和地理距离、经济成本联合构造相似度矩阵,实现综合分区;
- 动态分区:结合实时量测数据,让相似度矩阵随运行状态变化,实现自适应动态分区;
- 与强化学习结合:用谱聚类结果作为强化学习的状态抽象,减少状态空间维数,加速区域电压控制策略的学习过程。
这些方向我都还在探索,目前从文献和初步实验看,谱聚类作为“从图结构到低维特征表示”的入口,潜力确实比传统硬聚类大得多。核心还是把电气距离这个物理度量做好了,后面的步骤才有意义。
写在最后
分区这件事做了两三年,我个人的体会是:算法只是把“隐蔽的结构”挖出来,但最终判断还要靠对物理系统的理解。谱聚类最打动我的一点是,它不靠人工圈定边界,而是从整体的耦合强度出发,让数据自己说话。每次跑完特征分解,把 Fiedler 向量画出来,看着那些节点在特征空间里自然聚拢,心里总有一种“原来电网是这么长在一起的”的感觉。
工具和代码流程上面都给了,建议你在自己熟悉的系统上先跑一遍,尤其是那个 σ 参数,多扫几个值看看分区结果变化,感受一下灵敏度。我在实际中已经吃过不少亏,希望你能避开这些坑,一步到位走出靠谱的分区结果。
本文还有配套的精品资源,点击获取
