使用 ML.NET 進行電力消耗時序預測:基于家庭用電數(shù)據(jù)的實戰(zhàn)分析
準確預測電力消耗對于電力系統(tǒng)的規(guī)劃和運營至關(guān)重要。本文將詳細介紹如何使用 ML.NET 構(gòu)建時序預測模型,以預測全局有功功率(Global_active_power)的變化。
項目概述
- 目標:預測未來24小時的電力消耗
- 技術(shù)棧:ML.NET、C#
- 算法:單變量時序分析(SSA)
- 數(shù)據(jù)源:家庭用電量數(shù)據(jù)集
環(huán)境準備
- 創(chuàng)建新的 C# 控制臺應(yīng)用程序
- 安裝必要的 NuGet 包:
<PackageReference Include="Microsoft.ML" Version="2.0.0" />
<PackageReference Include="Microsoft.ML.TimeSeries" Version="2.0.0" />
<PackageReference Include="CsvHelper" Version="30.0.1" />
完整代碼實現(xiàn)
1. 定義數(shù)據(jù)模型
// 原始數(shù)據(jù)模型
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; }
}
public class PowerConsumptionData
{
public DateTime Timestamp { get; set; }
public float Global_active_power { get; set; }
}
public class PowerPrediction
{
public float[] ForecastedPower { get; set; }
public float[] LowerBoundPower { get; set; }
public float[] UpperBoundPower { get; set; }
}
2. 主程序?qū)崿F(xiàn)
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);
// 加載數(shù)據(jù)
// 加載原始數(shù)據(jù)
IDataView rawDataView = mlContext.Data.LoadFromTextFile<PowerConsumptionRawData>(
path: "household_power_consumption.txt",
hasHeader: true,
separatorChar: ';'
);
// 轉(zhuǎn)換數(shù)據(jù):合并日期時間并處理格式
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();
// 將處理后的數(shù)據(jù)轉(zhuǎn)換回 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天的數(shù)據(jù)進行分析
trainSize: 8760, // 使用一年的數(shù)據(jù)訓練
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]);
// 首先打印數(shù)據(jù)數(shù)量
Console.WriteLine($"實際值數(shù)量: {actualValues.Count()}");
Console.WriteLine($"預測值數(shù)量: {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();
// 輸出預測結(jié)果
Console.WriteLine("\n未來24小時的電力消耗預測:");
for (int i = 0; i < fforecast.ForecastedPower.Length; i++)
{
Console.WriteLine($"第 {i + 1} 小時: {fforecast.ForecastedPower[i]:F3} kW " +
$"(置信區(qū)間: {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;
}
}
}
`MLContext.Forecasting.ForecastBySsa` 方法的所有參數(shù):
必需參數(shù)
outputColumnName: string
// 預測結(jié)果輸出列的名稱
// 例如: "ForecastedPower"
inputColumnName: string
// 輸入數(shù)據(jù)列的名稱,用于預測的源數(shù)據(jù)列
// 例如: nameof(PowerConsumptionData.Global_active_power)
windowSize: int
// SSA(奇異譜分析)的窗口大小
// - 必須大于0且小于seriesLength
// - 影響模型捕捉的季節(jié)性模式
// - 推薦設(shè)置為預期周期長度的1/2到1/3
可選但重要的參數(shù)
seriesLength: int
// 用于訓練的時間序列片段長度
// - 默認值:windowSize * 2
// - 必須大于windowSize
// - 建議值:windowSize的2-3倍
trainSize: int
// 用于訓練的數(shù)據(jù)點數(shù)量
// - 默認值:整個數(shù)據(jù)集大小
// - 確定模型訓練使用的歷史數(shù)據(jù)量
horizon: int
// 預測的未來時間點數(shù)量
// - 默認值:1
// - 指定要預測多少個未來時間點
置信區(qū)間相關(guān)參數(shù)
confidenceLevel: float
// 預測的置信水平
// - 取值范圍:0到1之間
// - 常用值:0.95(95%置信度)
// - 默認值:0.95
confidenceLowerBoundColumn: string
// 置信區(qū)間下界的輸出列名
// - 可選參數(shù)
// - 例如: "LowerBoundPower"
confidenceUpperBoundColumn: string
// 置信區(qū)間上界的輸出列名
// - 可選參數(shù)
// - 例如: "UpperBoundPower"
最佳實踐
// 對于每小時數(shù)據(jù)的典型設(shè)置
var pipeline = mlContext.Forecasting.ForecastBySsa(
outputColumnName: "Forecast",
inputColumnName: "Value",
windowSize: 24, // 一天
seriesLength: 72, // 三天
trainSize: 8760, // 一年
horizon: 24, // 預測一天
confidenceLevel: 0.95f
);
// 對于每日數(shù)據(jù)的典型設(shè)置
var pipeline = mlContext.Forecasting.ForecastBySsa(
outputColumnName: "Forecast",
inputColumnName: "Value",
windowSize: 7, // 一周
seriesLength: 21, // 三周
trainSize: 365, // 一年
horizon: 7, // 預測一周
confidenceLevel: 0.95f
);
這些參數(shù)的正確設(shè)置對模型的預測性能至關(guān)重要,建議根據(jù)實際數(shù)據(jù)特征和業(yè)務(wù)需求進行調(diào)整和實驗。
模型評估
使用兩個主要指標評估模型性能:
- 平均絕對誤差 (MAE)
a.MAE 直接反映預測值與實際值的平均偏差
b.數(shù)值越小表示預測越準確
c.單位與原始數(shù)據(jù)相同,便于理解
- 均方根誤差 (RMSE)
- RMSE 對大誤差更敏感
- 通過平方放大了大誤差的影響
- 最終開方使單位與原始數(shù)據(jù)相同
總結(jié)
本文展示了如何使用 ML.NET 構(gòu)建電力消耗預測模型的完整過程。通過合理配置和訓練,可以得到一個可靠的預測模型,幫助優(yōu)化電力系統(tǒng)運營。這個方法不僅適用于家庭用電預測,還可以擴展到工業(yè)用電預測、智能電網(wǎng)管理等領(lǐng)域。