做风电或负荷不确定性分析的朋友大概率都绕不开“场景削减”这一步。原本蒙特卡洛抽样生成几千个场景计算量还能接受一旦放进随机优化、时序生产模拟或者可靠性评估里几千个场景直接能把求解器拖到怀疑人生。K-means聚类是大家用得最多的削减手段但它有个天生缺陷需要预先指定簇数K而且对初始中心敏感遇到形状不规则、密度不均匀的数据分布时聚类结果经常不稳定噪声点还会把簇中心拉偏。DBSCAN密度聚类是另一个思路。它不需要预设簇数能自动发现任意形状的簇还能把游离的噪声点单独识别出来。把这套逻辑迁移到风电-负荷场景削减上意味着我们不需要反复试K值也不用担心场景分布呈现非凸形状时K-means表现糟糕同时那些极端但概率不高的小概率场景会被单独保留不至于被“平均”掉。这篇文章就围绕“基于DBSCAN密度聚类的风电-负荷场景削减方法”展开讲清楚这类方法的设计思路、参数选择逻辑、实际代码实现和我在调参过程中踩过的坑。1. 场景削减的问题定义与DBSCAN选型思路1.1 风电-负荷场景从哪来为什么非得削减先理一下场景削减到底在解决什么问题。风电出力和负荷需求本质上都是随机过程我们要评估系统在未来一段时间内的运行状态不能只看一条期望曲线必须考虑多种可能性的分布。通常做法是用蒙特卡洛抽样或者拉丁超立方抽样基于历史数据的概率分布模型生成大量场景每个场景是一条时序曲线代表一种可能的风电出力过程或者负荷变化过程。举个例子我们要做未来24小时的机组组合优化每个时刻风电出力是一个随机变量如果按每小时一个采样点24维随机向量的一次抽样就是一个场景。抽样1000次就是1000个场景每个场景24维。这个规模放进混合整数规划里优化变量和约束条件会被放大上千倍求解时间不是线性增长而是指数级恶化。更实际的问题在于大量场景之间存在高度相似性很多场景的曲线形状几乎重合把它们全部保留纯粹是计算资源的浪费。场景削减的核心目标就是从原始的大规模场景集中挑选一个具有代表性的子集同时为每个保留场景重新分配概率权重使得削减前后的场景集合在概率分布意义上尽可能接近。理想效果是用几十个场景就能近似代替原来上千个场景的随机特性。1.2 为什么K-means在场景削减中不够好用K-means在场景削减里确实是主流工具很多论文和工程代码都在用。基本流程是先把N个场景看作N个高维数据点每个点的坐标就是各时刻的数值维度等于时序长度然后跑K-means聚类把场景分成K簇每个簇中心作为代表场景簇内场景数占总场景数的比例作为该代表场景的概率。看起来简单直接但实际操作中问题很多。第一K值怎么定K-means要求用户提前给定KK太大则削减效果不明显K太小则损失过多分布信息。有人说用肘部法则或者轮廓系数来选K但风电-负荷场景数据往往高维且有大量重叠区域这些指标给出的“最优K”在后续优化模型里未必是最合适的。第二K-means的聚类结果依赖初始中心点选择同一个数据集跑两次可能得到不同结果这对需要可复现性的工程应用不够友好。第三K-means假设簇是凸的、大小相近的但风电场景中常常存在“一片密集区若干疏散区”的分布形态用K-means会把疏散区的场景强行划入邻近密集簇导致小概率极端场景被“吞噬”。1.3 DBSCAN能解决什么问题又有什么代价DBSCAN的核心理念是“物以类聚”一个簇被定义为一组密度相连的点集簇与簇之间被低密度区域隔开。它只需要两个参数邻域半径eps和最小样本数MinPts。算法会自动从数据中发现簇结构同时把那些落在低密度区域的点标记为噪声点。这个特性用在场景削减上有几个直接好处不需要预设簇数算法根据数据密度分布自行决定簇的数量和形状非凸形状的簇也能被完整识别出来噪声点被单独保留不会“绑架”簇中心。对于风电-负荷场景这种分布形态未知的数据DBSCAN提供了一种更保守也更能反映数据原始结构的聚类方式。代价也很明显。DBSCAN的参数eps和MinPts对结果影响很大调参需要经验算法的时间复杂度最坏情况是O(n^2)场景量级大时会比较慢当数据维度很高时距离度量会变得不那么可靠也就是所谓的“维度灾难”。所以在实际应用里我通常会把DBSCAN和PCA降维先用起来或者改用欧氏距离的近似计算。不过话说回来这些代价在“场景削减”这个任务里都可以通过工程手段缓解。毕竟我们要聚类的数据不是原始几千维的图像或文本而是一般不超过24到168维的时序曲线规模也就在几千条上下合理优化后计算完全可行。2. 数据预处理与相似性度量场景聚类的关键底层2.1 原始场景数据该做哪些预处理先泼一盆冷水聚类算法是个“输入垃圾输出也垃圾”的东西数据预处理不做干净后面调参再努力也白搭。风电-负荷场景数据在进入DBSCAN之前通常要先解决两个问题一是量纲差异二是时序对齐。量纲差异是新手最容易忽略的一环。风电出力数值可能在0到装机容量之间波动比如0到1500MW负荷数值则可能在几百到几千MW之间。如果不做归一化两个维度的数值范围差了一个量级距离计算会完全被数值大的维度主导聚类结果相当于只考虑了负荷信息风电维度的贡献被淹没了。我常用的方式是对每个场景的各维度做Z-score标准化也就是去均值除以标准差让每个维度的数值都在零附近波动。如果后续要保留原始曲线的形状特征也可以用最小最大值归一到0到1之间。时序对齐在风电-负荷场景里一般问题不大因为采样步长和预测时域通常是统一的比如每15分钟一个点未来4小时就是16维。但如果你用的是不同来源的数据比如风功率预测系统输出的分辨率和负荷预测系统不一致那就必须先统一插值到相同的时间分辨率上否则两个序列没法对齐比较。2.2 怎么定义两个场景之间的距离DBSCAN的聚类结果完全建立在“距离”的基础上距离度量的选择直接决定聚类效果。对风电-负荷场景来说最常见的做法是把场景当作高维空间中的点两个场景之间的距离就是两条时序曲线之间的欧氏距离。形式化地说如果场景A是向量(a_1, a_2, ..., a_T)场景B是向量(b_1, b_2, ..., b_T)它们之间的欧氏距离就是每个维度差的平方和再开根号。欧氏距离直观、计算快、效果稳定是默认首选。但它对时间轴上的“错位”非常敏感两条形状完全相同但整体平移了一个时间步的曲线欧氏距离会很大。这在风电场景里是有实际意义的——同样是晚高峰负荷爬坡发生在17:00还是18:00对系统调度的影响完全不同所以距离大一点反而合理。如果更关注曲线的整体形状趋势而不关注绝对幅值可以考虑动态时间规整DTW距离它能容忍时间轴上的非线性对齐。但DTW的缺点是计算复杂度高对几千个场景两两计算距离矩阵会非常耗时个人不太建议在大规模场景削减中直接使用。我在实际项目里更常用的一种做法是把风电场景和负荷场景分开计算距离然后加权合并为总距离。比如总距离 α × 风电场场景距离 β × 负荷场景距离α和β根据系统里风电和负荷的不确定性重要性来设定。这样聚类时能同时兼顾两类变量的分布特性而不是把风电和负荷拼接成一个长向量后直接算距离——拼接方式下高维度的部分会主导距离值未必是我们想要的。2.3 高维数据的降维处理风电-负荷场景的维度通常是24维小时级、96维15分钟级甚至更高。DBSCAN依赖于距离的计算而高维空间中点与点之间的距离会趋于均匀导致密度差异不明显这就是“维度灾难”。一个可操作的缓解方案是先降维再聚类。我常用的降维方法有两种PCA主成分分析和t-SNE。PCA是线性降维速度快适合保留全局结构一般把24维降到2到5维就够了。t-SNE更擅长可视化能把高维结构映射到二维平面上人脸看着很舒服但它对距离的保持是局部性的降维后的坐标不适合直接用于距离计算。所以我通常的做法是用PCA做正式聚类前的降维用t-SNE做结果可视化来向团队解释聚类效果。需要特别提醒一下降维会丢失信息。如果原始场景本身差异就非常明显降维后聚类效果变化不大但如果场景本身就高度相似降维可能会抹掉细微差异导致所有场景被聚成一类。做降维后聚类前最好先用轮廓系数等指标评估一下聚类分离度别盲目为了计算速度牺牲信息。3. DBSCAN聚类核心逻辑与参数选择3.1 DBSCAN聚类过程拆解DBSCAN算法本身不复杂理解了三类点的概念就掌握了核心。算法把所有数据点分成三类核心点在eps半径内至少包含MinPts个点包含自身边界点在某个核心点的eps半径内但自身不满足核心点的条件噪声点既不是核心点也不是任何核心点的邻居算法从一个未访问的核心点出发递归地找到所有与其密度相连的点构成一个簇。重复这个过程直到所有核心点都被访问过。剩下的边界点会被归属到其邻近的核心点所在簇而噪声点则留在原地不归属任何簇。放在场景削减的情境里理解如果一个区域内的场景足够密集DBSCAN就会把它们归为一个簇说明这些场景代表的出力曲线形态高度相似如果一个场景周围没有足够多的相似场景它就会成为噪声点也就是小概率的极端场景单独保留处理。3.2 参数eps和MinPts的物理含义与选择实操DBSCAN唯一的两个参数都是人为设定的选择方法直接决定聚类结果。先说MinPts它代表一个核心点至少在邻域半径内需要包含的样本数。MinPts越大形成的簇越“健壮”但也会把所有点都变成噪声MinPts越小越容易把噪声也归为簇。一个经验法则是MinPts取数据维度的两倍或更大比如场景维度是24那么MinPts至少取48以上。不过这只是经验值实际中我会结合业务逻辑来定如果一个代表场景至少要由总场景数的1%支撑那么1000个场景时MinPts可以取10到15左右。eps的选择更讲究。eps太大几乎所有点都会被聚成一个簇削减效果变差eps太小大量点变成噪声代表性场景数量过多起不到削减作用。业界比较经典的做法是画k距离图对每个点计算到其第k近邻的距离把所有点的k距离排序后绘制曲线选取曲线拐点处的距离作为eps取值。这里的k就是MinPts取MinPts的近邻距离排序图找拐点。我在实际项目中用过这个方法效果不错但拐点有时候并不明显。还有更工程化的做法固定MinPts后在合理范围内遍历多个eps值用聚类得到的簇数量和噪声比例来辅助决策——簇数量太多说明eps偏小噪声比例太高也说明eps偏小簇数量太少说明eps偏大。通常我会接受聚类结果中噪声比例在5%到15%之间簇数量在10到30之间这样既保证了削减效果又不会丢失太多极端场景信息。3.3 聚类完毕后如何生成代表场景与重新分配概率DBSCAN聚类完成后每个非噪声场景都被赋予了一个簇标签。接下来的问题就是每个簇怎么生成一个代表场景每个代表场景的概率怎么算代表场景的生成有两种常用方式。第一种是取簇内所有场景的质心也就是各个场景向量求平均这也是K-means的做法。第二种是选取簇内距质心最近的场景作为代表场景这样能保证代表场景是一条真实可能发生的曲线而不是一条被“平滑”掉尖峰的人造曲线。在风电场景中平均曲线往往会抹平极端波动比如把一次完整的功率跌落过程平均成一条平缓的下滑曲线这在后续优化中会低估爬坡约束的紧张程度。如果你的下游优化模型对爬坡、尖峰这类极端特征敏感强烈建议用“最近邻代表场景”也就是选簇内离质心最近的真实场景作为该簇的典型场景。概率分配方面规则非常直接每个代表场景的概率等于该簇内场景数量除以场景总数。噪声场景单独保留每个噪声场景对应原始场景中的一个场景概率为1/N_总。这样所有保留场景代表场景加噪声场景的概率之和仍然等于1不需要额外归一化操作。值得一提的是有时候簇内场景数量很多但簇间差异很大此时可以额外做一步“二次削减”对DBSCAN得到的簇数量超过预期时可以先统计各簇概率筛掉概率过低的簇。但概率太低的簇往往对应极端场景这里是否需要保留完全取决于你的优化模型是否能容忍这些小概率极端场景被忽略。兼顾安全性和计算量时我倾向于保留概率低但物理意义明确的极端场景比如风电几乎为零的高温无风日不轻易剔除。4. 场景削减效果评价与对比实验设计4.1 用什么指标衡量削减质量场景削减不是“减得越少越好”关键是削减后的场景分布和削减前尽可能接近。我经常用两类指标来评估削减质量。第一类是分布距离指标最常用的是Wasserstein距离也叫推土机距离或EMD。它衡量两个概率分布之间需要多少“搬运成本”才能把一个分布变成另一个。Wasserstein距离越小说明削减前后的场景分布在概率意义下越接近。它的优势在于对分布之间的几何距离非常敏感比KL散度更适用于连续高维分布的比较而且计算相对稳定。第二类是下游模型关键指标比如削峰填谷后的系统总成本、弃风率、失负荷概率等。最终目的是让削减后的场景在优化模型中使用时输出结果和用原始场景接近。不同业务目标下的“效果”可能完全不同。比如你家系统对尖峰负荷特别敏感那削减后就必须把负荷峰值场景保得很准哪怕整体分布距离略大一点也可以接受。4.2 DBSCAN与K-means削减结果的对比维度和K-means做对比时我通常会设计一个标准的对比实验同一个原始场景集分别用K-means采用最优K值和DBSCAN采用调参后的eps、MinPts削减到相近数量的场景数量然后对比分布距离、下游模型误差、计算耗时三个维度。实际测试中DBSCAN的优势通常在“场景分布形状不规则”的数据集上体现得最明显。比如风电场景常存在两种主要天气模态大风过程和静稳天气过程。大风过程下出力曲线波动剧烈静稳天气下出力接近零且平稳。这两种模态分布密度不均匀形状差异很大。K-means在这种数据下经常会把部分大风场景划入静稳簇导致代表场景出现“中间态”——既不像大风也不像静稳实际上是现实中很少出现的形状。DBSCAN由于基于密度分割两个模态之间的低密度区域自然被看作类间分界聚类结果更贴近物理实际。当然K-means也有它的优势。它的计算效率显著更高当场景数量超过5000、维度超过96时DBSCAN的O(n^2)距离计算会很吃力而K-means则依然非常快速。此外K-means保底能给出一个稳定的簇划分DBSCAN在数据密度差异极端悬殊时会把低密度区域的场景全部判成噪声导致削减后代表性场景数量不可控。工程上务实一点的做法是先用K-means粗聚类再对每个簇内部做DBSCAN精聚类兼顾效率和准确性。4.3 一个具体的对比实验例子假设有原始场景数量S1000个每种场景是未来的24小时曲线风电和负荷各自24维。物理意义上想让削减后保留约20个场景。K-means直接设K20聚类后每个簇的中心即为代表场景簇内场景占比作为概率。这套流程非常快运行时间不到一秒。DBSCAN方案稍微费点心思。先对三维风电负荷拼接的数据48维做PCA降维到5维然后算欧氏距离的距离矩阵取MinPts10用k距离图找到拐点在eps0.82附近聚类得到18个簇和约8%的噪声点。最后取每簇内离质心最近的原始场景作为代表性场景加上部分噪声场景总共保留约24个场景概率按照簇容量和噪声场景占比重新分配。对比结果通常会发现DBSCAN方案的Wasserstein距离比K-means削减少10%到20%但保留场景个数略多。如果下游模型对场景数量有硬性要求可以设置一个阈值当DBSCAN结果中簇数量过于接近或超过硬件计算限制时取概率占比最高的前N个簇其余合并到一个“其余场景”簇中。但这样做会损失极端场景信息实操时要谨慎。5. 完整实现流程与代码框架5.1 整体流程梳理整个场景削减流程可以归纳为以下步骤场景生成通过蒙特卡洛抽样或风电/负荷预测误差模型抽样生成大规模原始场景集数据预处理对场景做缺失值补全、归一化或标准化降维可选对高维场景做PCA降维保留主要变化信息距离矩阵计算计算场景两两之间的欧氏距离DBSCAN聚类选定MinPts与eps执行聚类轮廓系数/簇级评估评估聚类质量必要时回到第5步调整参数代表场景生成对每个簇取簇心或最近真实场景重新分配概率计算每个簇和噪声场景的概率效果评估计算Wasserstein距离、对比下游模型误差判断是否满足削减目标5.2 DBSCAN聚类核心代码示例这里给出一个用Python实现的关键环节代码框架基于scikit-learn的DBSCAN模块加上手动的k距离图参数选择逻辑。import numpy as np import pandas as pd from sklearn.cluster import DBSCAN from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from scipy.spatial.distance import pdist, squareform import matplotlib.pyplot as plt # 1. 场景数据加载假设数据形状是 (n_scenarios, n_timesteps) # wind_scenarios 和 load_scenarios 分别是风速出力和负荷场景矩阵 wind_scenarios np.load(wind_scenarios.npy) # shape: (1000, 24) load_scenarios np.load(load_scenarios.npy) # shape: (1000, 24) # 2. 标准化 scaler StandardScaler() wind_scaled scaler.fit_transform(wind_scenarios) load_scaled scaler.fit_transform(load_scenarios) # 3. 拼接特征空间或分别计算距离后加权合并 features np.hstack([wind_scaled, load_scaled]) # (1000, 48) # 4. PCA降维 pca PCA(n_components5) features_reduced pca.fit_transform(features) # 5. 计算距离矩阵 dist_matrix squareform(pdist(features_reduced, metriceuclidean)) # 6. 生成k距离图确定eps min_samples 10 k_distances np.sort(dist_matrix, axis1)[:, min_samples] k_distances_sorted np.sort(k_distances) plt.plot(k_distances_sorted) plt.xlabel(Points sorted by distance) plt.ylabel(k-distance (k{}).format(min_samples)) plt.show()这段代码跑完后你需要盯着折线图找一个“肘部”位置也就是曲线从急剧上升转入平缓的转折点该点对应的纵坐标值就是合适的eps。确定eps之后就可以执行DBSCAN聚类# 7. DBSCAN聚类 eps 0.82 # 根据k距离图确定 clustering DBSCAN(epseps, min_samplesmin_samples, metriceuclidean) cluster_labels clustering.fit_predict(features_reduced) # 8. 检查聚类结果 unique_labels np.unique(cluster_labels) n_clusters len(unique_labels) - 1 # 减1是剔除噪声点标签-1 n_noise np.sum(cluster_labels -1) print(fNumber of clusters: {n_clusters}) print(fNumber of noise points: {n_noise} ({n_noise / len(cluster_labels) * 100:.2f}%))5.3 代表场景生成与概率计算聚类结束后生成代表场景和概率的代码如下# 9. 生成代表场景 representative_scenarios [] probabilities [] n_total len(cluster_labels) for label in unique_labels: if label -1: # 噪声点每个场景单独保留 noise_indices np.where(cluster_labels -1)[0] for idx in noise_indices: # 这里选择原始的未标准化场景作为代表场景 rep np.concatenate([wind_scenarios[idx], load_scenarios[idx]]) representative_scenarios.append(rep) probabilities.append(1 / n_total) else: # 非噪声簇先算簇心再选离簇心最近的场景作为代表场景 cluster_indices np.where(cluster_labels label)[0] cluster_center np.mean(features_reduced[cluster_indices], axis0) # 找到离簇心最近的场景索引 distances_to_center np.linalg.norm( features_reduced[cluster_indices] - cluster_center, axis1 ) nearest_idx cluster_indices[np.argmin(distances_to_center)] rep np.concatenate([wind_scenarios[nearest_idx], load_scenarios[nearest_idx]]) representative_scenarios.append(rep) probabilities.append(len(cluster_indices) / n_total) representative_scenarios np.array(representative_scenarios) probabilities np.array(probabilities) # 10. 概率归一化确保总和为1 probabilities probabilities / probabilities.sum()这里刻意选择了“距簇心最近的真实场景”而不是簇心本身作为代表场景目的是保留原始场景的物理可行性避免出现“平均后完全不符合物理规律”的伪场景。5.4 效果评估代码示例评估削减效果时通常采用分布距离加工程指标的方式from scipy.stats import wasserstein_distance # 原始场景集和削减后场景集按同维度评估 # 这里示例只对风电部分做评估 original_wind wind_scenarios # (1000, 24) reduced_wind representative_scenarios[:, :24] # (N_rep, 24) # 计算每个维度上的Wasserstein距离后取平均 wd_scores [] for t in range(24): wd wasserstein_distance(original_wind[:, t], reduced_wind[:, t]) wd_scores.append(wd) avg_wd np.mean(wd_scores) print(fAverage Wasserstein distance per timestep: {avg_wd:.4f})这个指标越小越好。实际项目中我还会加一个额外检查把削减前后的场景分别代入机组组合模型比较总运行成本和弃风率偏差。如果偏差在可接受范围比如1%以内就认为削减方案满足工程要求。6. 常见问题与实战调试经验6.1 eps调参困难怎么办调参是DBSCAN场景削减里最让人头疼的部分。k距离图的拐点有时不明显尤其当场景维度较高且数据本身层次不分明时。我的经验是不要死磕k距离图大胆去跑一组参数扫描实验。具体操作是设定MinPts为固定值比如5、10、20分别试eps从最小值到最大值按对数间隔取30个候选值对每个参数组合运行DBSCAN记录簇数量、噪声比例、轮廓系数然后把结果画成热力图。热力图上可以直观看到“簇数量突然变化”的参数区域那里的eps往往是更合理的选择。预算允许的话用交叉验证的方式来选择能让下游模型误差最小的参数组合这是最稳妥但耗时最长的方案。6.2 噪声点过多或者过少怎么处理噪声点过多意味着eps太小或者MinPts太大。可以先尝试按1.2到1.5倍的系数放大eps如果噪声还是多就要回头检查数据预处理有没有缺失值没有补全是不是标准化方式不合适有时候某个时间段的数据存在系统性偏差异常会导致大量场景在该维度上分得很散从而被标记为噪声。噪声点过少甚至为零说明eps偏大或者MinPts偏小所有点都被聚进了大簇中。这样的聚类没有意义代表场景数量太少削减过狠。此时需要缩小eps让簇边界收缩保留更多细粒度信息。实际操作中我一般希望噪声比例在5%到15%之间。如果你的业务场景对极端事件特别敏感可以把噪声比例放宽到20%甚至30%因为噪声点实际上代表的就是极端但真实的场景单独保留它们比被平均进某个簇要好得多。6.3 计算速度慢距离矩阵内存爆炸DBSCAN最直接的性能瓶颈是距离矩阵。n个场景就需要n×n的距离矩阵1000个场景是800万个元素64MB用float6410000个场景就是8亿个元素6.4GB内存直接爆炸。遇到大规模场景时我一般用以下策略组合启用n_jobs-1并行计算距离矩阵使用sklearn的NearestNeighbors替代全量距离矩阵用ball_tree或kd_tree索引加速近邻搜索先用K-means粗聚类把场景粗分到20到40个子集再在每个子集内部跑DBSCAN精聚类如果数据量确实大到万级建议直接用MiniBatchKMeans替代不要为了用DBSCAN硬撑6.4 聚类结果不稳定每次结果都变DBSCAN本身是确定性算法结果不稳定的原因主要有两个一是距离矩阵计算用到了浮点数精度问题二是使用了带随机性的数据预处理比如t-SNE降维。使用PCA就不会有这个问题。如果希望结果完全可复现在代码开头设置np.random.seed(42)还不够还要注意确保数据读入顺序一致。数据顺序不同距离矩阵一样DBSCAN聚类结果应该不变但如果你用了MiniBatchKMeans或者其他随机初始化算法就另当别论了。对DBSCAN而言只要预处理阶段不变结果就是确定的。6.5 场景削减后的代表场景“看起来不对”有次我把聚类结果可视化出来发现风电代表场景曲线出现了明显的“锯齿状”形态和实际风功率曲线很不像查了半天发现是标准化后数据没有反变换回去。标准化是为了聚类计算但生成代表场景时必须用原始量纲的数据否则代表场景会变成一个没有物理意义的数值序列。这个低级错误很常见值得专门提醒。7. 写在最后的一些体会DBSCAN这类密度聚类方法在场景削减中的应用说到底是在“保留分布特征”和“压缩计算规模”之间找一个平衡点。K-means胜在简单高效但它的簇结构假设和场景数据的真实分布之间往往存在偏差DBSCAN能更忠实地反映数据本身的疏密结构把决策权交给数据而不是交给预设的K值。我个人在实际项目中形成了一套相对固定的组合策略先用K-means做一次粗筛把明显相似的场景快速归并再用DBSCAN对粗筛后的簇内做精细的密度聚类识别出那些隐藏在主流分布内部的极端子簇最后用“簇内最近真实场景”作为代表场景避免平均化失真。这套组合在风电-负荷联合场景削减上表现很稳定比单独使用任何一种算法的鲁棒性都高得多。最后分享一个小技巧做场景削减之前先把原始场景集做一次二维t-SNE可视化人类肉眼比任何聚类指标都更擅长发现“这类数据到底有几团”。看清数据形态之后再决定用K-means还是DBSCAN往往能少走很多弯路。