Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Obtenga información sobre cómo predecir la demanda de un servicio de alquiler de bicicletas mediante el análisis de series temporales univariante en los datos almacenados en una base de datos de SQL Server con ML.NET.
En este tutorial, aprenderá a:
- Comprender el problema
- Carga de datos desde una base de datos
- Creación de un modelo de previsión
- Evaluación del modelo de previsión
- Guardar un modelo de previsión
- Uso de un modelo de previsión
Prerrequisitos
- Visual Studio 2022 o posterior con la carga de trabajo Desarrollo de escritorio de .NET instalada.
Resumen del ejemplo de previsión de series temporales
Este ejemplo es una aplicación de consola de C# que prevé la demanda de alquileres de bicicletas mediante un algoritmo de análisis de series temporales univariante conocido como Análisis de espectro singular. El código de este ejemplo se puede encontrar en el repositorio dotnet/machinelearning-samples en GitHub.
Comprender el problema
Para ejecutar una operación eficaz, la administración del inventario desempeña un papel clave. Tener demasiados productos en existencias significa que los productos sin vender sentados en los estantes no generan ingresos. Tener demasiado poco producto conduce a la pérdida de ventas y clientes que compran de competidores. Por lo tanto, la pregunta constante es, ¿cuál es la cantidad óptima de inventario que se debe mantener a mano? El análisis de series temporales ayuda a proporcionar una respuesta a estas preguntas examinando los datos históricos, identificando patrones y usando esta información para predecir valores en algún momento en el futuro.
La técnica para analizar los datos usados en este tutorial es un análisis de series temporales univariante. El análisis de series temporales univariante examina una única observación numérica durante un período de tiempo a intervalos específicos, como las ventas mensuales.
El algoritmo usado en este tutorial es Singular Spectrum Analysis(SSA). SSA funciona mediante la descomposición de una serie temporal en un conjunto de componentes principales. Estos componentes se pueden interpretar como las partes de una señal que corresponden a tendencias, ruido, estacionalidad y muchos otros factores. A continuación, estos componentes se reconstruyen y se usan para predecir valores algún tiempo en el futuro.
Creación de una aplicación de consola
Cree una aplicación de consola de C# denominada "BikeDemandForecasting". Haga clic en el botón Siguiente .
Elija .NET 8 como marco de trabajo que se va a usar. Haga clic en el botón Crear.
Instalar el paquete NuGet de la versión Microsoft.ML
Nota:
En este ejemplo se usa la versión estable más reciente de los paquetes NuGet mencionados a menos que se indique lo contrario.
- En el Explorador de soluciones, haga clic con el botón derecho en el proyecto y seleccione Administrar paquetes NuGet.
- Elija "nuget.org" como origen del paquete, seleccione la pestaña Examinar y busque Microsoft.ML.
- Active la casilla Incluir versión preliminar .
- Seleccione el botón Instalar .
- Seleccione el botón Aceptar en el cuadro de diálogo Vista previa de cambios y, a continuación, seleccione el botón Acepto en el cuadro de diálogo Aceptación de licencia si está de acuerdo con los términos de licencia de los paquetes enumerados.
- Repita estos pasos para System.Data.SqlClient y Microsoft.ML.TimeSeries.
Preparación y comprensión de los datos
- Cree un directorio denominado Data.
- Descargue el archivo de base de datos DailyDemand.mdf y guárdelo en el directorio Data.
Nota:
Los datos usados en este tutorial proceden del conjunto de datos de uso compartido de bicicletas de UCI. Hadi Fanaee-T y João Gama, "Etiquetado de eventos combinando detectores de conjuntos y conocimientos de fondo", Progreso en inteligencia artificial (2013): pp. 1-15, Springer Berlin Heidelberg, Web Link.
El conjunto de datos original contiene varias columnas correspondientes a la estacionalidad y el tiempo. Por motivos de brevedad y porque el algoritmo usado en este tutorial solo requiere los valores de una sola columna numérica, el conjunto de datos original se ha condensado para incluir solo las columnas siguientes:
- dteday: fecha de la observación.
- year: el año codificado de la observación (0=2011, 1=2012).
- cnt: el número total de alquileres de bicicletas para ese día.
El conjunto de datos original se asigna a una tabla de base de datos con el esquema siguiente en una base de datos de SQL Server.
CREATE TABLE [Rentals] (
[RentalDate] DATE NOT NULL,
[Year] INT NOT NULL,
[TotalRentals] INT NOT NULL
);
A continuación se muestra un ejemplo de los datos:
| RentalDate | Año | TotalRentals |
|---|---|---|
| 1/1/2011 | 0 | 985 |
| 1/2/2011 | 0 | 801 |
| 1/3/2011 | 0 | 1349 |
Creación de clases de entrada y salida
Abra Program.cs archivo y reemplace las directivas existentes
usingpor lo siguiente:using Microsoft.ML; using Microsoft.ML.Data; using Microsoft.ML.Transforms.TimeSeries; using System.Data.SqlClient;Crear
ModelInputclase. Debajo de laProgramclase , agregue el código siguiente.public class ModelInput { public DateTime RentalDate { get; set; } public float Year { get; set; } public float TotalRentals { get; set; } }La
ModelInputclase contiene las columnas siguientes:- RentalDate: fecha de la observación.
- Año: año codificado de la observación (0=2011, 1=2012).
- TotalRentals: el número total de alquileres de bicicletas para ese día.
Cree la clase
ModelOutputdebajo de la claseModelInputrecién creada.public class ModelOutput { public float[] ForecastedRentals { get; set; } public float[] LowerBoundRentals { get; set; } public float[] UpperBoundRentals { get; set; } }La
ModelOutputclase contiene las columnas siguientes:- ForecastedRentals: los valores previstos para el período previsto.
- LowerBoundRentals: los valores mínimos previstos para el período previsto.
- UpperBoundRentals: los valores máximos previstos para el período previsto.
Definición de rutas de acceso e inicialización de variables
Debajo de las
usingdirectivas se definen variables para almacenar la ubicación de los datos, la cadena de conexión y dónde guardar el modelo entrenado.string rootDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../")); string dbFilePath = Path.Combine(rootDir, "Data", "DailyDemand.mdf"); string modelPath = Path.Combine(rootDir, "MLModel.zip"); var connectionString = $"Data Source=(LocalDB)\\MSSQLLocalDB;AttachDbFilename={dbFilePath};Integrated Security=True;Connect Timeout=30;";Inicialice la
mlContextvariable con una nueva instancia deMLContextagregando la siguiente línea después de definir las rutas de acceso.MLContext mlContext = new MLContext();La
MLContextclase es un punto de partida para todas las operaciones de ML.NET e inicializar mlContext crea un nuevo entorno de ML.NET que se puede compartir entre los objetos de flujo de trabajo de creación de modelos. Es similar, conceptualmente, aDBContexten Entity Framework.
Carga de los datos
Cree
DatabaseLoaderque cargue registros de tipoModelInput.DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<ModelInput>();Defina la consulta para cargar los datos de la base de datos.
string query = "SELECT RentalDate, CAST(Year as REAL) as Year, CAST(TotalRentals as REAL) as TotalRentals FROM Rentals";ML.NET algoritmos esperan que los datos sean de tipo
Single. Por lo tanto, los valores numéricos procedentes de la base de datos que no son de tipoReal, un valor de punto flotante de precisión única, deben convertirse enReal.Las
Yearcolumnas yTotalRentalson tipos enteros en la base de datos. Con laCASTfunción integrada, ambas se convierten enReal.Cree un
DatabaseSourcepara conectarse a la base de datos y ejecutar la consulta.DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, query);Cargue los datos en un
IDataView.IDataView dataView = loader.Load(dbSource);El conjunto de datos contiene dos años de datos. Solo se usan datos del primer año para el entrenamiento, el segundo año se mantiene para comparar los valores reales con la previsión generada por el modelo. Filtre los datos mediante la
FilterRowsByColumntransformación.IDataView firstYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", upperBound: 1); IDataView secondYearData = mlContext.Data.FilterRowsByColumn(dataView, "Year", lowerBound: 1);Para el primer año, solo se seleccionan los valores de la
Yearcolumna menor que 1 estableciendo elupperBoundparámetro en 1. Por el contrario, para el segundo año, los valores mayores o iguales a 1 se seleccionan estableciendo ellowerBoundparámetro en 1.
Definir la canalización de análisis de series temporales
Defina una canalización que use SsaForecastingEstimator para predecir los valores de un conjunto de datos de serie temporal.
var forecastingPipeline = mlContext.Forecasting.ForecastBySsa( outputColumnName: "ForecastedRentals", inputColumnName: "TotalRentals", windowSize: 7, seriesLength: 30, trainSize: 365, horizon: 7, confidenceLevel: 0.95f, confidenceLowerBoundColumn: "LowerBoundRentals", confidenceUpperBoundColumn: "UpperBoundRentals");forecastingPipelinetoma 365 puntos de datos para el primer año y muestra o divide el conjunto de datos de serie temporal en intervalos de 30 días (mensuales), según lo especificado por el parámetroseriesLength. Cada uno de estos ejemplos se analiza a través de una ventana semanal o de 7 días. Al determinar cuál es el valor previsto para los próximos períodos, los valores de los siete días anteriores se usan para realizar una predicción. El modelo se establece para predecir siete períodos en el futuro según lo definido por elhorizonparámetro . Dado que una previsión es una estimación informada, no siempre es 100% precisa. Por lo tanto, es bueno conocer el intervalo de valores en los escenarios mejor y peor, tal como se define en los límites superior e inferior. En este caso, el nivel de confianza de los límites inferior y superior se establece en 95%. El nivel de confianza se puede aumentar o disminuir en consecuencia. Cuanto mayor sea el valor, más amplio será el intervalo entre los límites superior e inferior para lograr el nivel de confianza deseado.Use el
Fitmétodo para entrenar el modelo y ajustar los datos a la instancia de definidaforecastingPipelineanteriormente.SsaForecastingTransformer forecaster = forecastingPipeline.Fit(firstYearData);
Evaluación del modelo
Evalúe el rendimiento del modelo mediante la previsión de los datos del próximo año y su comparación con los valores reales.
Cree un nuevo método de utilidad llamado
Evaluateen la parte inferior del archivo Program.cs .Evaluate(IDataView testData, ITransformer model, MLContext mlContext) { }Dentro del
Evaluatemétodo , previsión de los datos del segundo año mediante elTransformmétodo con el modelo entrenado.IDataView predictions = model.Transform(testData);Obtenga los valores reales de los datos mediante el
CreateEnumerablemétodo .IEnumerable<float> actual = mlContext.Data.CreateEnumerable<ModelInput>(testData, true) .Select(observed => observed.TotalRentals);Obtenga los valores de previsión mediante el
CreateEnumerablemétodo .IEnumerable<float> forecast = mlContext.Data.CreateEnumerable<ModelOutput>(predictions, true) .Select(prediction => prediction.ForecastedRentals[0]);Calcule la diferencia entre los valores reales y de previsión, comúnmente denominado error.
var metrics = actual.Zip(forecast, (actualValue, forecastValue) => actualValue - forecastValue);Mida el rendimiento calculando los valores de error absoluto medio y error cuadrático medio.
var MAE = metrics.Average(error => Math.Abs(error)); // Mean Absolute Error var RMSE = Math.Sqrt(metrics.Average(error => Math.Pow(error, 2))); // Root Mean Squared ErrorPara evaluar el rendimiento, se usan las siguientes métricas:
- Error absoluto medio: mide la proximidad de las predicciones con el valor real. Este valor oscila entre 0 e infinito. Cuanto más cerca de 0, mejor será la calidad del modelo.
- Error cuadrático medio raíz: resume el error en el modelo. Este valor oscila entre 0 e infinito. Cuanto más cerca de 0, mejor será la calidad del modelo.
Muestra las métricas en la consola.
Console.WriteLine("Evaluation Metrics"); Console.WriteLine("---------------------"); Console.WriteLine($"Mean Absolute Error: {MAE:F3}"); Console.WriteLine($"Root Mean Squared Error: {RMSE:F3}\n");Llame al
Evaluatemétodo siguiente llamando alFit()método .Evaluate(secondYearData, forecaster, mlContext);
Guardar el modelo
Si está satisfecho con el modelo, guárdelo para usarlo más adelante en otras aplicaciones.
Debajo del
Evaluate()método, cree unTimeSeriesPredictionEngine.TimeSeriesPredictionEnginees un método de conveniencia para realizar predicciones únicas.var forecastEngine = forecaster.CreateTimeSeriesEngine<ModelInput, ModelOutput>(mlContext);Guarde el modelo en un archivo llamado
MLModel.zipsegún lo especificado por la variable definidamodelPathanteriormente. Use elCheckpointmétodo para guardar el modelo.forecastEngine.CheckPoint(mlContext, modelPath);
Uso del modelo para predecir la demanda
Debajo del
Evaluatemétodo , cree un nuevo método de utilidad denominadoForecast.void Forecast(IDataView testData, int horizon, TimeSeriesPredictionEngine<ModelInput, ModelOutput> forecaster, MLContext mlContext) { }Dentro del
Forecastmétodo , use elPredictmétodo para predecir alquileres durante los próximos siete días.ModelOutput forecast = forecaster.Predict();Alinee los valores reales y de previsión durante siete períodos.
IEnumerable<string> forecastOutput = mlContext.Data.CreateEnumerable<ModelInput>(testData, reuseRowObject: false) .Take(horizon) .Select((ModelInput rental, int index) => { string rentalDate = rental.RentalDate.ToShortDateString(); float actualRentals = rental.TotalRentals; float lowerEstimate = Math.Max(0, forecast.LowerBoundRentals[index]); float estimate = forecast.ForecastedRentals[index]; float upperEstimate = forecast.UpperBoundRentals[index]; return $"Date: {rentalDate}\n" + $"Actual Rentals: {actualRentals}\n" + $"Lower Estimate: {lowerEstimate}\n" + $"Forecast: {estimate}\n" + $"Upper Estimate: {upperEstimate}\n"; });Recorrer el resultado del pronóstico y mostrarlo en la consola.
Console.WriteLine("Rental Forecast"); Console.WriteLine("---------------------"); foreach (var prediction in forecastOutput) { Console.WriteLine(prediction); }
Ejecutar la aplicación
A continuación, al llamar al
Checkpoint()método, se llama alForecastmétodo .Forecast(secondYearData, 7, forecastEngine, mlContext);Ejecute la aplicación. La salida similar a la siguiente debería aparecer en la consola. Por motivos de brevedad, el resultado se ha condensado.
Evaluation Metrics --------------------- Mean Absolute Error: 726.416 Root Mean Squared Error: 987.658 Rental Forecast --------------------- Date: 1/1/2012 Actual Rentals: 2294 Lower Estimate: 1197.842 Forecast: 2334.443 Upper Estimate: 3471.044 Date: 1/2/2012 Actual Rentals: 1951 Lower Estimate: 1148.412 Forecast: 2360.861 Upper Estimate: 3573.309
La inspección de los valores reales y previstos muestra las siguientes relaciones:
Aunque los valores previstos no predicen el número exacto de alquileres, proporcionan un intervalo de valores más estrecho que permite que una operación optimice su uso de recursos.
¡Felicidades! Ahora ha construido correctamente un modelo de aprendizaje automático de series temporales para pronosticar la demanda de alquiler de bicicletas.
Puede encontrar el código fuente de este tutorial en el repositorio dotnet/machinelearning-samples .