ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于PSO优化模糊C均值聚类的电力用户用电行为分析

2026/10/2 11:31:24 拓冰建站 浏览量
基于PSO优化模糊C均值聚类的电力用户用电行为分析 电力用户聚类这个方向这几年在电力数据分析圈子里一直热度不减。智能电表一天能采集90多个负荷点一个台区几千户居民一个月下来就是上百万条数据光靠人工查曲线根本不现实。所以大家普遍的做法是先做特征提取再上聚类算法把用户自动分成几类后面接的是分时电价设计、需求响应潜力评估、故障用电行为识别这些具体业务。我这次要聊的项目就是这类分析里一个比较经典的组合——用粒子群算法PSO去优化模糊C均值聚类FCM在Matlab里跑通居民用电行为分类。核心要解决的问题很明确普通FCM聚类对初始聚类中心特别敏感同一个数据集随机初始化跑几次结果可能都不一样而粒子群算法的全局搜索能力正好能补上这一块。这个项目不挑基础做电力数据分析的、做课题的研究生、想玩聚类算法和群智能算法结合的工程师都可以拿来作参考。1. 项目整体思路为什么居民用电分析要“PSOFCM”组合1.1 电力用户聚类的业务背景与数据形态先说一下业务背景。居民用户和工商业用户的用电行为差异很大工商业用户生产计划性强负荷曲线规律明显居民用户则是典型的“生活规律驱动”早晚上下班、做饭、观影、夜间空调这些行为都会体现在日负荷曲线上。过去电网侧对居民用户的管理相对粗放基本就是“一口价”或者简单的阶梯电价。现在讲究的是精准服务那就得知道每个用户的大致行为画像。智能电表采集的数据一般15分钟一个点一天96个点一条日负荷曲线就是一个96维的向量。一个小区几千户一个月下来就是几十万条96维数据。如果把每周7天的曲线做平均得到“典型日负荷曲线”就能减少随机波动的影响。数据形态清楚了分析思路也简单了把用户按负荷曲线特征聚类每一类代表一种用电行为模式比如“晚高峰型”“双峰型”“全天平稳型”这类标签直接对接后续的差异化电价、需求响应邀约等业务。1.2 FCM聚类的优势与痛点做用户聚类为什么不用最常见的K-means因为K-means是硬聚类一个样本只能属于一个类别。但居民的用电行为往往是重叠的比如一个用户平时白天上班、晚上用电可周末可能全天宅家他的行为既像“上班族”又有“全天用电”的影子硬切一刀不太合理。模糊C均值聚类FCM用“隶属度”替代“硬标签”允许一个用户同时以不同概率属于多个类这点和用电行为天然契合。但FCM有个硬伤就是目标函数是非凸的。FCM本质上是通过交替迭代求隶属度矩阵和聚类中心这个方法本身是迭代下降的但只能保证收敛到目标函数的局部极小点。初始聚类中心选得不好迭代就陷到不好的局部极值区聚类结果就很拉胯。我拿同一组数据随机初始化跑10次FCM目标函数值能差出不少聚类中心偏移也很明显。所以在实际项目中就得想办法把FCM从“看运气”变成“稳定复现”。1.3 PSO为什么适合优化FCM粒子群算法PSO是一种群体智能全局搜索算法核心逻辑是模拟鸟群觅食一群粒子在解空间里飞每个粒子记住自己历史上最好位置个体最优整个群体记住全局最好位置全局最优靠这两个信息不断调整飞行速度和方向。PSO不需要目标函数的梯度信息适合处理FCM这种非凸、不连续的优化问题它可以跳出局部极小点在更大的解空间里找更好的聚类中心组合。整个技术路线就是原始负荷曲线先做归一化按业务需求提取特征然后设计PSO的粒子编码方案让粒子代表一组聚类中心经过PSO搜索之后把最优中心交给FCM做最后的迭代收敛得到隶属度矩阵和分类结果。后面再对每一类用户做典型负荷曲线分析输出行为画像。这个路线在Matlab里闭环跑通逻辑很顺。2. FCM聚类算法拆解模糊划分与迭代收敛2.1 模糊聚类和硬聚类的区别为什么更适合用电数据硬聚类K-means的每一步迭代里每个样本根据距离被明确分配到最近的簇归属是0或1。模糊聚类则引入了隶属度矩阵U元素u_ik表示第k个样本属于第i类的程度取值范围[0,1]并且对同一个样本它所有隶属度之和为1。生活化地说硬聚类像把一群学生按成绩分成“好、中、差”三档每个学生只能进一个档模糊聚类则是允许一个学生“数学好、英语菜”他同时以0.7的隶属度属于“理科强”类以0.3的隶属度属于“偏科”类。居民用电也一样晚高峰型用户可能同时具备夜间用电特征模糊隶属度能把这个“骑墙”状态表达出来。2.2 FCM的目标函数与迭代公式FCM的优化目标函数是J_m(U,V) Σ(i1 to c) Σ(k1 to N) u_ik^m · ||x_k - v_i||²其中c是聚类数N是样本数m是模糊指数通常取2v_i是第i类的聚类中心||x_k - v_i||是样本到中心的欧氏距离。目标函数直观理解就是让每个样本到各个聚类中心的加权距离之和尽量小权重就是隶属度的m次方。m越大隶属度越“软”类别之间的界限越模糊。在约束条件Σ(i1 to c) u_ik 1下通过拉格朗日乘子法可以推出两个交替迭代公式。隶属度更新公式u_ik 1 / Σ(j1 to c) ( ||x_k - v_i|| / ||x_k - v_j|| )^(2/(m-1))聚类中心更新公式v_i Σ(k1 to N) u_ik^m · x_k / Σ(k1 to N) u_ik^m这两个公式的代码实现并不复杂下面是Matlab核心迭代代码function [center, U, obj] fcm_iter(data, c, m, center_init, max_iter, epsilon) % data: N*dN个样本d维特征 % center_init: c*d初始聚类中心 N size(data, 1); center center_init; for t 1:max_iter % 计算样本到各中心的距离平方 dist pdist2(data, center).^2; % N*c dist(dist eps) eps; % 防止除零 % 更新隶属度 invDist 1 ./ dist.^(1/(m-1)); U invDist ./ sum(invDist, 2); % N*c每行和为1 % 更新聚类中心 Um U.^m; center_new (Um * data) ./ sum(Um, 1); obj sum(sum(Um .* dist)); if norm(center_new - center, fro) epsilon center center_new; break; end center center_new; end end这段代码里有个细节我吃过亏距离为0的时候1/distance会变成无穷大隶属度更新直接NaN。所以要加一个eps下界保护。另外pdist2是Matlab自带的距离计算函数比自己写两层for循环快非常多数据量到几万行的时候感受尤其明显。2.3 模糊指数m和聚类数c怎么选m是FCM里最敏感的参数。理论上m取1时退化为硬聚类m趋向无穷大时所有隶属度趋近1/c等于不聚类。Bezdek的经验推荐是m2这是经过大量实验验证的默认值绝大多数论文和工程实践也都在用。你要是想更精细可以在1.5到2.5之间做网格搜索用聚类有效性指标去挑但大多数场景下m2已经足够。聚类数c的选择常规做法是遍历c2到c10对每个c跑一次完整的PSO-FCM流程再算聚类有效性指标选最优c。常用的指标是轮廓系数Silhouette Coefficient和戴维斯-布尔丁指数DBI一个越大越好一个越小越好。另外Xie-Beni指数XB指数在模糊聚类里也用得比较多它同时考虑了类内紧致度和类间分离度设计自适应度函数时很方便。3. PSO粒子群算法与FCM的融合设计细节3.1 PSO的核心更新逻辑与参数PSO里每个粒子代表解空间里的一个候选解。粒子i在第t次迭代的位置是X_i(t)速度是V_i(t)它经历过的历史最优位置是P_i(t)群体全局最优位置是G(t)。速度更新公式V_i(t1) w·V_i(t) c1·r1·(P_i(t) - X_i(t)) c2·r2·(G(t) - X_i(t))位置更新公式X_i(t1) X_i(t) V_i(t1)各项参数的作用w是惯性权重控制粒子的“惯性”w大时粒子全局探索能力强w小时局部开发能力强c1和c2是学习因子c1把粒子拉向自己的历史最优c2把粒子拉向群体最优通常都取2r1和r2是[0,1]的随机数用来保持搜索的随机性。一个非常实用的改进是让w线性递减。比如从0.9逐步降到0.4前期粒子飞得野能覆盖更大的解空间后期慢慢收敛精细搜索最优区域。这个改进实现成本极低但效果立刻不一样我跑实验时对比过固定w和线性递减w后者的目标函数值最终稳定得多。3.2 粒子编码怎么把聚类中心装进高维向量PSO直接处理的是向量而聚类中心是一个c行d列的矩阵。粒子编码的核心就是把这个矩阵拉平成一维向量。假设聚类数c4特征维度d5那么每个粒子的维度就是D4×520。前5个元素是第一个聚类中心第6到10个元素是第二个中心依次类推。解码的时候用reshape函数就可以恢复成c×d矩阵center_matrix reshape(pop(i, :), c, d);编码方式听起来简单但实际写代码时非常容易出维度错位。我建议在初始化粒子群的时候就定义一个明确的结构粒子群矩阵pop尺寸为pop_size×D每一行是一个粒子。初始化时随机选c个样本作为初始聚类中心填进对应位置这样保证粒子起点不会太离谱收敛速度也快一些。3.3 适应度函数的两种设计路线PSO优化FCM核心是适应度函数怎么定义。这里有两种路线。路线一是直接用FCM的目标函数J_m作为适应度越小越好。每个粒子的位置解码成聚类中心后算一遍所有样本到中心的加权距离和。这种方法计算量小但粒子位置直接当作中心的搜索方式和FCM自带的迭代收敛机制是脱节的搜索效率一般。路线二是在评价粒子时嵌入FCM的若干次迭代。也就是说粒子解码出一组初始聚类中心后先跑5到10步FCM迭代让中心往局部最优方向稍微收一下再计算目标函数或有效性指标作为适应度。这样PSO负责全局翻山越岭FCM负责局部快速爬坡两者优势互补这也是我最终采用的设计。实测下来同样的迭代次数路线二的目标函数下降速度和最终稳定性都明显好于路线一。如果想顺便解决聚类数c的自动选择问题可以把Xie-Beni指数嵌进适应度函数让粒子不仅要找好的中心还要往“类内紧凑、类间分离”的方向进化。3.4 PSO-FCM混合算法的完整流程整个算法的流程可以分为以下几步第一步读入数据做归一化设定c和m初始化PSO参数。第二步随机初始化粒子群每个粒子的位置来自对数据集中随机c个样本的选取速度随机小值。第三步进入PSO迭代每个粒子解码聚类中心跑几步FCM迭代计算适应度更新个体最优和全局最优按速度和位置公式更新粒子。第四步迭代结束把全局最优位置解码成聚类中心作为FCM的初始中心跑完整FCM迭代直到收敛。第五步输出隶属度矩阵U、聚类中心V以及每个用户的模糊分类标签。伪代码流程很清楚输入负荷特征矩阵X聚类数c模糊指数m 输出最优聚类中心V隶属度矩阵U 1. X归一化 2. 初始化粒子群pop、速度vel参数w、c1、c2 3. for t 1 to max_iter for each particle p center reshape(pop(p, :), c, d) [center, ~, ~] fcm_iter(X, c, m, center, 5, 1e-3) fitness(p) fcm_objective(X, center, m) update pbest, gbest end update w w_max - (w_max - w_min) * t / max_iter update vel, pop end 4. [V, U, obj] fcm_iter(X, c, m, gbest_center, full_iter, epsilon) 5. return V, U这个过程跑下来既保证了全局寻优能力又利用FCM的迭代算法做了精细收敛是工程上比较稳妥的组合方案。4. Matlab代码实现与参数配置要点4.1 数据结构设计与数据预处理Matlab里做这个项目数据组织方式直接决定代码效率。我的习惯是所有样本都放一个矩阵里行是样本列是特征。比如从日负荷曲线提取8个特征那么数据矩阵就是N×8。用cell数组存每户的原始曲线用数值矩阵存特征两者分开管理清晰很多。数据预处理有两个关键动作。第一个是归一化。负荷数据量纲差异很大比如最大负荷几千瓦谷时功率几乎为零直接丢进聚类算法距离计算基本被最大负荷那几个维度主导。最小值最大值归一化是最常用的data_norm (data - min(data, [], 1)) ./ (max(data, [], 1) - min(data, [], 1) eps);注意min和max函数带维度参数不然默认对整个矩阵取标量这个坑我踩过好几次。第二个是特征提取。96个原始点全部送进去不是不可以但维度高、计算慢、噪声大。业务上常用特征包括日负荷率平均负荷除以最大负荷、峰谷差率、峰值出现时刻、峰时电量占比8点到20点电量占全天比例、谷时电量占比、最大负荷、最小负荷、负荷波动方差等。取8到10个特征既能保留行为差异又能让PSO的粒子维度大幅下降。4.2 PSO-FCM核心代码框架粒子群主循环的实现框架如下pop_size 30; max_iter 100; w_max 0.9; w_min 0.4; c1 2; c2 2; D c * d; % 初始化 pop zeros(pop_size, D); vel zeros(pop_size, D); for p 1:pop_size idx randperm(N, c); pop(p, :) reshape(data(idx, :), 1, D); end vel -0.1 0.2 * rand(pop_size, D); pbest pop; pbest_fit inf(pop_size, 1); gbest pop(1, :); gbest_fit inf; for t 1:max_iter for p 1:pop_size center reshape(pop(p, :), c, d); [center, ~] fcm_iter(data, c, m, center, 5, 1e-3); fit fcm_objective(data, center, m); if fit pbest_fit(p) pbest_fit(p) fit; pbest(p, :) reshape(center, 1, D); end if fit gbest_fit gbest_fit fit; gbest reshape(center, 1, D); end end w w_max - (w_max - w_min) * t / max_iter; % 速度更新加边界限制 vel w * vel c1 * rand(pop_size, D) .* (pbest - pop) ... c2 * rand(pop_size, D) .* (repmat(gbest, pop_size, 1) - pop); pop pop vel; end % 最终FCM收敛 [best_center, U, obj_history] fcm_iter(data, c, m, reshape(gbest, c, d), 200, 1e-5);fcm_objective这个函数就是算一下J_m值。注意PSO迭代时用5步快速FCM最终阶段用200步完整收敛这种“先粗后细”的分阶段设计既省时间又保精度。粒子速度还要做边界限制超过范围就给随机重置不然粒子很容易飞出可行域。4.3 参数配置经验表参数设置没有绝对标准但一套靠谱的起点能帮你少走很多弯路。下面是经过多组数据验证的推荐配置。参数名称推荐取值说明pop_size20~40太大计算成本高太小容易早熟max_iter100~200配合线性递减惯性权重c1、c22.0PSO经典配置按需微调w范围0.9到0.4线性递减平衡探索与收敛模糊指数m2.0Bezdek经典经验值快速FCM迭代步数5~10步只做局部微调不做完整收敛最终FCM迭代次数100~300充分收敛epsilon1e-5收敛阈值参数调完之后我一般会固定随机种子rng(2024)确保实验可复现。这个细节特别重要不然你换台电脑跑结果就变了写论文时没法解释。5. 仿真实验与结果解读5.1 合成数据构造与实验设置为了演示完整的分析流程我构造了一批带标签的合成日负荷数据。假设有三类典型居民用电模式A类是“双峰型”早8点和晚7点各出现一次用电高峰对应上班族早晚用电特征B类是“晚高峰型”白天用电很少晚上6点以后快速上升对应白天在外的年轻住户C类是“平稳型”全天用电波动小可能对应老人长期在家或者电器常年待机。以96点日负荷曲线为基底分别给三类模式加上随机幅值的噪声生成900个样本每类300个。然后对每条曲线提取8个特征日最大负荷、日平均负荷、日负荷率、峰谷差率、晚峰功率占比18点到22点电量占比、早峰功率占比6点到10点、峰值时刻、负荷标准差。这样测试数据就是900×8的矩阵标签已知可以验证PSO-FCM能不能把三类分开。聚类数这里直接设c3重点对比PSO-FCM和标准FCM在同样数据上的表现。5.2 聚类的评价指标与对比结果评价指标主要看轮廓系数和DBI。轮廓系数越大越好DBI越小越好。另外因为我用的是带标签的合成数据还可以直接算聚类准确率用匈牙利算法做标签匹配之后对一下。算法目标函数值J轮廓系数DBI准确率FCM随机初始化0.4310.610.5282.1%PSO-FCM0.4020.670.4191.3%同样是合成数据PSO-FCM的目标函数值更低说明聚类中心确实找到了更优的位置。轮廓系数提高到了0.67DBI降到0.41分类准确率从82%提升到91%。这就是PSO提供好的初始中心之后FCM能收敛到更优极值的直观证据。5.3 典型负荷曲线与用电行为画像聚类完成后把每一类所有样本的日负荷曲线取平均就能画出典型模式曲线。三类结果和合成数据的预设非常吻合第一类是早、晚两个高峰的双峰型峰谷差明显日负荷率在0.4左右第二类是仅晚高峰白天几乎是一条平线晚上负荷陡增第三类全天波动很小日负荷率超过0.7峰谷差率很低。聚类中心对应到业务侧可以翻译成清晰的行为画像。双峰型用户适合推广分时电价他们有弹性负荷可以调节晚高峰型用户是晚间的负荷尖峰来源理论上可以通过需求响应引导到低谷时段平稳型用户用电规律性强不太适合做负荷调节。有了这些画像后续做套餐推荐、负荷预测特征工程、台区负载预警都有了抓手。6. 常见问题与排错记录6.1 归一化不当导致的聚类失效这是最容易踩的坑。某次实验我忘做归一化直接把原始负荷数据丢进去结果聚类出来的几类几乎只是按“用电量大小”分层大用户一类、小用户一类行为模式完全被量纲淹没了。正确做法是按特征维度归一化到[0,1]如果有极端值就用稳健归一化比如除以中位数或使用log1p变换。归一化之后聚类才能反映“形态”差异而不是“大小”差异。6.2 粒子维度错位和矩阵索引问题粒子维度Dc×d这个值算错会导致reshape维度不匹配报错或结果错乱。我建议在代码里加一个断言检查assert(size(pop, 2) c * d, 粒子维度与聚类中心和特征维度不匹配);另外Matlab的矩阵索引是列优先reshape大向量时按列填充。所以初始化粒子和解码中心时一定要确认reshape的方向一致不然聚类中心的数据顺序会错位。这个小问题能让你debug一整天。6.3 收敛慢或陷入局部最优的排查方向如果PSO迭代几十轮适应度几乎不动先检查是不是粒子边界约束太紧或者惯性权重衰减太快。w从0.9线性递减到0.4如果max_iter设了50步粒子后期基本没有探索能力。这种情况下适当增加max_iter或者在速度更新时加入小幅随机扰动都能缓解。还有粒子数太少也容易早熟pop_size低于20很容易陷入局部最优。6.4 数据量大时的计算性能优化当样本数达到十万级以上每轮PSO都要对每个粒子调FCM快速迭代计算量就上来了。实测下来粒子数30、迭代100次、每个粒子内嵌5步FCM在几百维数据上勉强能接受再大就明显吃力。两条优化路线一是先用MiniBatch思路每轮随机取一部分样本算适应度用近似值引导PSO方向二是先做PCA降维把特征压到5维以内。这两招叠加计算时间能缩到原来的四分之一。说到这顺便提一下Matlab 2021a之后的版本在矩阵运算上做了很多优化同样的代码在新版本里跑得快不少建议写完代码顺手在最新版R2021a之前的版本上回归测试一遍避免版本兼容问题。最后说一个我个人的实操体会在做这类PSO-FCM项目时别急着上复杂变体。先把最基础的PSO和标准FCM按上述方式接起来跑通全流程再看效果决定要不要加改进点。很多问题的根源其实只是初始中心太差或者数据处理不当基础版本解决不了再考虑更复杂的设计。这个框架后续要扩展也很方便比如把适应度函数换成Xie-Beni指标做自适应选聚类数或者把PSO换成其他群智能算法做对比代码的模块化设计已经替你留好了位置。