编辑
2025-11-26
C#
00

目录

项目概述
环境准备
完整代码实现
1. 定义数据模型
2. 主程序实现
MLContext.Forecasting.ForecastBySsa 方法的所有参数:
必需参数
可选但重要的参数
置信区间相关参数
模型评估
总结

准确预测电力消耗对于电力系统的规划和运营至关重要。本文将详细介绍如何使用 ML.NET 构建时序预测模型,以预测全局有功功率(Global_active_power)的变化。

项目概述

  • 目标:预测未来24小时的电力消耗
  • 技术栈:ML.NET、C#
  • 算法:单变量时序分析(SSA)
  • 数据源:家庭用电量数据集

环境准备

  1. 创建新的 C# 控制台应用程序
  2. 安装必要的 NuGet 包:
XML
<PackageReference Include="Microsoft.ML" Version="2.0.0" /> <PackageReference Include="Microsoft.ML.TimeSeries" Version="2.0.0" /> <PackageReference Include="CsvHelper" Version="30.0.1" />

image.png

完整代码实现

1. 定义数据模型

C#
// 原始数据模型 public class PowerConsumptionRawData { [LoadColumn(0)] public string Date { get; set; } [LoadColumn(1)] public string Time { get; set; } [LoadColumn(2)] public float Global_active_power { get; set; } }
C#
public class PowerConsumptionData { public DateTime Timestamp { get; set; } public float Global_active_power { get; set; } }
C#
public class PowerPrediction { public float[] ForecastedPower { get; set; } public float[] LowerBoundPower { get; set; } public float[] UpperBoundPower { get; set; } }

2. 主程序实现

C#
using Microsoft.ML; using Microsoft.ML.Transforms.TimeSeries; using System.Globalization; namespace App11 { internal class Program { static void Main(string[] args) { // 初始化 ML.NET 上下文 MLContext mlContext = new MLContext(seed: 0); // 加载数据 // 加载原始数据 IDataView rawDataView = mlContext.Data.LoadFromTextFile<PowerConsumptionRawData>( path: "household_power_consumption.txt", hasHeader: true, separatorChar: ';' ); // 转换数据:合并日期时间并处理格式 var transformedData = mlContext.Data.CreateEnumerable<PowerConsumptionRawData>(rawDataView, reuseRowObject: false) .Select(row => new PowerConsumptionData { Timestamp = ParseDateTime(row.Date + " " + row.Time), Global_active_power = row.Global_active_power }) .OrderBy(x => x.Timestamp) .ToList(); // 将处理后的数据转换回 IDataView IDataView dataView = mlContext.Data.LoadFromEnumerable(transformedData); // 定义预测管道 var pipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "ForecastedPower", inputColumnName: nameof(PowerConsumptionData.Global_active_power), windowSize: 24, // 24小时窗口 seriesLength: 72, // 使用3天的数据进行分析 trainSize: 8760, // 使用一年的数据训练 horizon: 24, // 预测未来24小时 confidenceLevel: 0.95f, confidenceLowerBoundColumn: "LowerBoundPower", confidenceUpperBoundColumn: "UpperBoundPower" ); // 训练模型 var model = pipeline.Fit(dataView); Console.WriteLine("模型训练完成!"); // 评估模型 // 评估模型 IDataView predictions = model.Transform(dataView); // 获取预测值和实际值 var forecastingEngine = model.CreateTimeSeriesEngine<PowerConsumptionData, PowerPrediction>(mlContext); var forecast = forecastingEngine.Predict(); // 手动计算评估指标 IEnumerable<float> actualValues = mlContext.Data.CreateEnumerable<PowerConsumptionData>(dataView,true) .Select(x => x.Global_active_power); IEnumerable<float> predictedValues = mlContext.Data.CreateEnumerable<PowerPrediction>(predictions, true) .Select(x => x.ForecastedPower[0]); // 首先打印数据数量 Console.WriteLine($"实际值数量: {actualValues.Count()}"); Console.WriteLine($"预测值数量: {predictedValues.Count()}"); // 检查是否有无效值 var hasInvalidActual = actualValues.Any(x => float.IsNaN(x) || float.IsInfinity(x)); var hasInvalidPredicted = predictedValues.Any(x => float.IsNaN(x) || float.IsInfinity(x)); Console.WriteLine($"实际值中包含无效值: {hasInvalidActual}"); Console.WriteLine($"预测值中包含无效值: {hasInvalidPredicted}"); // 计算差异时过滤掉无效值 var metrics = actualValues.Zip(predictedValues, (actual, predicted) => new { Actual = actual, Predicted = predicted }) .Where(pair => !float.IsNaN(pair.Actual) && !float.IsInfinity(pair.Actual) && !float.IsNaN(pair.Predicted) && !float.IsInfinity(pair.Predicted)) .Select(pair => (double)pair.Actual - (double)pair.Predicted) .ToList(); // 计算评估指标 double mse = metrics.Select(x => x * x).Average(); double rmse = Math.Sqrt(mse); double mae = metrics.Select(x => Math.Abs(x)).Average(); // 输出评估指标 Console.WriteLine($"均方误差 (MSE): {mse:F3}"); Console.WriteLine($"均方根误差 (RMSE): {rmse:F3}"); Console.WriteLine($"平均绝对误差 (MAE): {mae:F3}"); // 保存模型 string modelPath = "PowerPredictionModel.zip"; mlContext.Model.Save(model, dataView.Schema, modelPath); // 加载模型并预测 var loadedModel = mlContext.Model.Load(modelPath, out var modelInputSchema); var forecastEngine = loadedModel.CreateTimeSeriesEngine<PowerConsumptionData, PowerPrediction>(mlContext); var fforecast = forecastEngine.Predict(); // 输出预测结果 Console.WriteLine("\n未来24小时的电力消耗预测:"); for (int i = 0; i < fforecast.ForecastedPower.Length; i++) { Console.WriteLine($"第 {i + 1} 小时: {fforecast.ForecastedPower[i]:F3} kW " + $"(置信区间: {fforecast.LowerBoundPower[i]:F3} - {fforecast.UpperBoundPower[i]:F3} kW)"); } } static DateTime ParseDateTime(string dateString) { string[] formats = { "d/M/yyyy H:mm:ss", "dd/MM/yyyy H:mm:ss" }; // 支持多种格式 DateTime date; DateTime.TryParseExact(dateString, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out date); return date; } } }

image.png

MLContext.Forecasting.ForecastBySsa 方法的所有参数:

必需参数

C#
outputColumnName: string // 预测结果输出列的名称 // 例如: "ForecastedPower" inputColumnName: string // 输入数据列的名称,用于预测的源数据列 // 例如: nameof(PowerConsumptionData.Global_active_power) windowSize: int // SSA(奇异谱分析)的窗口大小 // - 必须大于0且小于seriesLength // - 影响模型捕捉的季节性模式 // - 推荐设置为预期周期长度的1/2到1/3

可选但重要的参数

C#
seriesLength: int // 用于训练的时间序列片段长度 // - 默认值:windowSize * 2 // - 必须大于windowSize // - 建议值:windowSize的2-3倍 trainSize: int // 用于训练的数据点数量 // - 默认值:整个数据集大小 // - 确定模型训练使用的历史数据量 horizon: int // 预测的未来时间点数量 // - 默认值:1 // - 指定要预测多少个未来时间点

置信区间相关参数

C#
confidenceLevel: float // 预测的置信水平 // - 取值范围:0到1之间 // - 常用值:0.95(95%置信度) // - 默认值:0.95 confidenceLowerBoundColumn: string // 置信区间下界的输出列名 // - 可选参数 // - 例如: "LowerBoundPower" confidenceUpperBoundColumn: string // 置信区间上界的输出列名 // - 可选参数 // - 例如: "UpperBoundPower"

最佳实践

C#
// 对于每小时数据的典型设置 var pipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "Forecast", inputColumnName: "Value", windowSize: 24, // 一天 seriesLength: 72, // 三天 trainSize: 8760, // 一年 horizon: 24, // 预测一天 confidenceLevel: 0.95f ); // 对于每日数据的典型设置 var pipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "Forecast", inputColumnName: "Value", windowSize: 7, // 一周 seriesLength: 21, // 三周 trainSize: 365, // 一年 horizon: 7, // 预测一周 confidenceLevel: 0.95f );

这些参数的正确设置对模型的预测性能至关重要,建议根据实际数据特征和业务需求进行调整和实验。

模型评估

使用两个主要指标评估模型性能:

  • 平均绝对误差 (MAE)
    • MAE 直接反映预测值与实际值的平均偏差
    • 数值越小表示预测越准确
    • 单位与原始数据相同,便于理解
  • 均方根误差 (RMSE)
    • RMSE 对大误差更敏感
    • 通过平方放大了大误差的影响
    • 最终开方使单位与原始数据相同

总结

本文展示了如何使用 ML.NET 构建电力消耗预测模型的完整过程。通过合理配置和训练,可以得到一个可靠的预测模型,帮助优化电力系统运营。这个方法不仅适用于家庭用电预测,还可以扩展到工业用电预测、智能电网管理等领域。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!