Desarrollo, evaluación y puntuación de un modelo de previsión de ventas de hipermercado
En este tutorial se muestra un ejemplo completo de un flujo de trabajo de ciencia de datos de Synapse en Microsoft Fabric. En este escenario se crea un modelo de previsión que use datos históricos de ventas para predecir las ventas de diferentes categorías de productos en un hipermercado.
La previsión es un activo fundamental en las ventas. Combina datos históricos y métodos predictivos para proporcionar información sobre las tendencias futuras. La previsión puede analizar las ventas pasadas para identificar patrones y aprender del comportamiento del consumidor a fin de optimizar las estrategias de marketing, el inventario y la producción. Este enfoque proactivo mejora las capacidades de adaptación y respuesta, y el rendimiento general de las empresas en un marketplace dinámico.
En este tutorial se describen estos pasos:
- Carga de los datos
- Usar los análisis de datos exploratorios para comprender y procesar los datos
- Entrene un modelo de Machine Learning con un paquete de software de código abierto y realice un seguimiento de experimentos mediante MLflow y la característica de registro automático de Fabric.
- Guarde el modelo de Machine Learning final y realice predicciones.
- Mostrar el rendimiento del modelo con visualizaciones de Power BI
Requisitos previos
Obtenga una suscripción a Microsoft Fabric. También puede registrarse para obtener una evaluación gratuita de Microsoft Fabric.
Inicie sesión en Microsoft Fabric.
Use el conmutador de experiencia en el lado izquierdo de la página principal para cambiar a la experiencia de ciencia de datos de Synapse.
- Si es necesario, cree un almacén de lago de Microsoft Fabric como se describe en Creación de un almacén de lago en Microsoft Fabric.
Seguir en un cuaderno
Puede elegir una de estas opciones para seguir en un cuaderno:
- Abra y ejecute el cuaderno integrado en la experiencia de ciencia de datos de Synapse
- Cargue su cuaderno desde GitHub a la experiencia de ciencia de datos de Synapse
Abra el cuaderno integrado
El cuaderno de muestra Sales forecasting acompaña a este tutorial.
Para abrir el cuaderno de muestra integrado en el tutorial en la experiencia de ciencia de datos de Synapse:
Vaya a la página principal de ciencia de datos de Synapse.
Seleccione Utilizar una muestra.
Seleccione la muestra correspondiente:
- Desde la pestaña predeterminada Flujos de trabajo de un extremo a otro (Python), si la muestra es para un tutorial de Python.
- Desde la pestaña Flujos de trabajo de un extremo a otro (R), si la muestra es para un tutorial de R.
- En la pestaña Tutoriales rápidos, si la muestra es para un tutorial rápido.
Adjunte un almacén de lago al cuaderno antes de empezar a ejecutar código.
Importación del cuaderno desde GitHub
El cuaderno AIsample - Superstore Forecast.ipynb acompaña a este tutorial.
Para abrir el cuaderno complementario para este tutorial, siga las instrucciones en Preparación del sistema para los tutoriales de ciencia de datos para importar el cuaderno en el área de trabajo.
Si prefiere copiar y pegar el código de esta página, puede crear un cuaderno nuevo.
Asegúrese de adjuntar una instancia de LakeHouse al cuaderno antes de empezar a ejecutar código.
Paso 1: Carga de los datos
El conjunto de datos contiene 9995 instancias de ventas de varios productos. También incluye 21 atributos. La tabla siguiente procede del archivo Superstore.xlsx usado en este cuaderno.
Identificador de fila | Id. de pedido | Fecha pedido | Ship Date | Modo de envío | Id. de cliente | Nombre del cliente | Segmento | Country | Ciudad | State | Código postal | Region | Id. del producto | Category | Subcategoría | Nombre del producto | Ventas | Cantidad | Descuento | Beneficios |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
4 | US-2015-108966 | 11/10/2015 | 18/10/2015 | Clase estándar | SO-20335 | Sean O'Donnell | Consumidor | Estados Unidos | Fort Lauderdale | Florida | 33311 | South | FUR-TA-10000577 | Mobiliario | Tablas | Mesa rectangular delgada de la serie CR4500 de Bretford | 957,5775 | 5 | 0.45 | -383,0310 |
11 | CA-2014-115812 | 09/06/2014 | 09/06/2014 | Clase estándar | Clase estándar | Brosina Hoffman | Consumidor | Estados Unidos | Los Angeles | California | 90032 | West | FUR-TA-10001539 | Mobiliario | Tablas | Mesas de conferencias rectangulares de Chromcraft | 1706,184 | 9 | 0,2 | 85,3092 |
31 | US-2015-150630 | 17/09/2015 | 21/09/2015 | Clase estándar | TB-21520 | Tracy Blumstein | Consumidor | Estados Unidos | Filadelfia | Pensilvania | 19140 | East | OFF-EN-10001509 | Material de oficina | Sobres | Sobres con cierre de cuerda de poliéster | 3,264 | 2 | 0,2 | 1,1016 |
Defina estos parámetros para poder utilizar este cuaderno con diferentes conjuntos de datos:
IS_CUSTOM_DATA = False # If TRUE, the dataset has to be uploaded manually
IS_SAMPLE = False # If TRUE, use only rows of data for training; otherwise, use all data
SAMPLE_ROWS = 5000 # If IS_SAMPLE is True, use only this number of rows for training
DATA_ROOT = "/lakehouse/default"
DATA_FOLDER = "Files/salesforecast" # Folder with data files
DATA_FILE = "Superstore.xlsx" # Data file name
EXPERIMENT_NAME = "aisample-superstore-forecast" # MLflow experiment name
Descarga del conjunto de datos y carga en un almacén de lago de datos
El código siguiente descarga una versión disponible públicamente del conjunto de datos y, a continuación, la almacena en un almacén de lago de Fabric:
Importante
Asegúrese de agregar un almacén de lago al cuaderno antes de ejecutarlo. De lo contrario, recibirá un error.
import os, requests
if not IS_CUSTOM_DATA:
# Download data files into the lakehouse if they're not already there
remote_url = "https://synapseaisolutionsa.blob.core.windows.net/public/Forecast_Superstore_Sales"
file_list = ["Superstore.xlsx"]
download_path = "/lakehouse/default/Files/salesforecast/raw"
if not os.path.exists("/lakehouse/default"):
raise FileNotFoundError(
"Default lakehouse not found, please add a lakehouse and restart the session."
)
os.makedirs(download_path, exist_ok=True)
for fname in file_list:
if not os.path.exists(f"{download_path}/{fname}"):
r = requests.get(f"{remote_url}/{fname}", timeout=30)
with open(f"{download_path}/{fname}", "wb") as f:
f.write(r.content)
print("Downloaded demo data files into lakehouse.")
Configuración del seguimiento del experimento de MLflow
Microsoft Fabric captura automáticament los valores de los parámetros de entrada y las métricas de salida de un modelo de Machine Learning a medida que lo entrena. Esto amplía las funcionalidades de registro automático de MLflow. A continuación, la información se registra en el área de trabajo, donde puede acceder a ella y visualizarla con las API de MLflow o el experimento correspondiente en el área de trabajo. Para obtener más información sobre el registro automático, consulte Registro automático en Microsoft Fabric.
Para desactivar el registro automático de Microsoft Fabric en una sesión de cuaderno, llame a mlflow.autolog()
y establezca disable=True
:
# Set up MLflow for experiment tracking
import mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True) # Turn off MLflow autologging
Lectura de datos sin procesar desde el lago de datos
Leer los datos sin procesar del Archivos del lago de datos. Agregue más columnas para diferentes partes de fecha. La misma información se utiliza para crear una tabla diferencial con particiones. Debido a que los datos sin procesar se almacenan como un archivo de Excel, debe utilizar Pandas para leerlos:
import pandas as pd
df = pd.read_excel("/lakehouse/default/Files/salesforecast/raw/Superstore.xlsx")
Paso 2: Realización de un análisis exploratorio de los datos
Importación de bibliotecas
Antes de cualquier análisis, importe las bibliotecas necesarias:
# Importing required libraries
import warnings
import itertools
import numpy as np
import matplotlib.pyplot as plt
warnings.filterwarnings("ignore")
plt.style.use('fivethirtyeight')
import pandas as pd
import statsmodels.api as sm
import matplotlib
matplotlib.rcParams['axes.labelsize'] = 14
matplotlib.rcParams['xtick.labelsize'] = 12
matplotlib.rcParams['ytick.labelsize'] = 12
matplotlib.rcParams['text.color'] = 'k'
from sklearn.metrics import mean_squared_error,mean_absolute_percentage_error
Mostrar los datos sin procesar
Revise manualmente un subconjunto de los datos para comprender mejor el propio conjunto de datos y use la función display
para imprimir el DataFrame. Además, las vistas de Chart
pueden visualizar fácilmente subconjuntos del conjunto de datos.
display(df)
Este cuaderno se centra principalmente en la previsión de las ventas de la categoría Furniture
. Esto acelera el cálculo y ayuda a mostrar el rendimiento del modelo. Sin embargo, este cuaderno usa técnicas adaptables. Puede ampliar esas técnicas para predecir las ventas de otras categorías de productos.
# Select "Furniture" as the product category
furniture = df.loc[df['Category'] == 'Furniture']
print(furniture['Order Date'].min(), furniture['Order Date'].max())
Preprocesamiento de los datos
En los escenarios empresariales reales, a menudo es necesario predecir las ventas en tres categorías distintas:
- Una categoría de producto específica
- Una categoría de cliente específica
- Una combinación específica de categoría de productos y categoría de clientes
En primer lugar, anule las columnas innecesarias para preprocesar los datos. Algunas de las columnas (Row ID
, Order ID
, Customer ID
y Customer Name
) no son necesarias porque no tienen ningún impacto. Queremos predecir las ventas generales en el estado y la región de una categoría específica de un producto (Furniture
) así que podemos anular las columnas State
, Region
, Country
, City
y Postal Code
. Para predecir las ventas de una ubicación o categoría específicas, es posible que tenga que ajustar el paso de preprocesamiento en consecuencia.
# Data preprocessing
cols = ['Row ID', 'Order ID', 'Ship Date', 'Ship Mode', 'Customer ID', 'Customer Name',
'Segment', 'Country', 'City', 'State', 'Postal Code', 'Region', 'Product ID', 'Category',
'Sub-Category', 'Product Name', 'Quantity', 'Discount', 'Profit']
# Drop unnecessary columns
furniture.drop(cols, axis=1, inplace=True)
furniture = furniture.sort_values('Order Date')
furniture.isnull().sum()
El conjunto de datos se estructura a diario. Debemos crear un nuevo muestreo en la columna Order Date
, ya que queremos desarrollar un modelo para predecir las ventas mensualmente.
En primer lugar, agrupe la categoría Furniture
según Order Date
. A continuación, calcule la suma de la columna Sales
para cada grupo a fin de determinar las ventas totales de cada valor de Order Date
único. Cree un nuevo muestreo de la columna Sales
mediante la frecuencia MS
para agregar los datos por mes. Por último, calcule el valor medio de ventas de cada mes.
# Data preparation
furniture = furniture.groupby('Order Date')['Sales'].sum().reset_index()
furniture = furniture.set_index('Order Date')
furniture.index
y = furniture['Sales'].resample('MS').mean()
y = y.reset_index()
y['Order Date'] = pd.to_datetime(y['Order Date'])
y['Order Date'] = [i+pd.DateOffset(months=67) for i in y['Order Date']]
y = y.set_index(['Order Date'])
maximim_date = y.reset_index()['Order Date'].max()
Demuestre el impacto de Order Date
en Sales
de la categoría Furniture
:
# Impact of order date on the sales
y.plot(figsize=(12, 3))
plt.show()
Antes de realizar cualquier análisis estadístico, debe importar el módulo statsmodels
de Python. Proporciona clases y funciones para la estimación de numerosos modelos estadísticos. También proporciona clases y funciones para hacer pruebas estadísticas y exploración de datos estadísticos.
import statsmodels.api as sm
Realización de análisis estadísticos
Una serie temporal realiza un seguimiento de estos elementos de datos a intervalos establecidos para determinar la variación de esos elementos en el patrón de serie temporal:
Nivel: el componente fundamental que representa el valor medio correspondiente a un periodo de tiempo específico
Tendencia: describe si la serie temporal disminuye, se mantiene constante o aumenta con el tiempo
Temporalidad: describe la señal periódica en la serie temporal y busca apariciones cíclicas que afectan a los patrones de aumento o disminución de la serie temporal
Ruido/residual: hace referencia a las fluctuaciones aleatorias y la variabilidad en los datos de serie temporal que el modelo no puede explicar.
En este código, se observan estos elementos para el conjunto de datos después del procesamiento previo:
# Decompose the time series into its components by using statsmodels
result = sm.tsa.seasonal_decompose(y, model='additive')
# Labels and corresponding data for plotting
components = [('Seasonality', result.seasonal),
('Trend', result.trend),
('Residual', result.resid),
('Observed Data', y)]
# Create subplots in a grid
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(12, 7))
plt.subplots_adjust(hspace=0.8) # Adjust vertical space
axes = axes.ravel()
# Plot the components
for ax, (label, data) in zip(axes, components):
ax.plot(data, label=label, color='blue' if label != 'Observed Data' else 'purple')
ax.set_xlabel('Time')
ax.set_ylabel(label)
ax.set_xlabel('Time', fontsize=10)
ax.set_ylabel(label, fontsize=10)
ax.legend(fontsize=10)
plt.show()
Los trazados describen la temporalidad, las tendencias y el ruido en los datos de previsión. Puede capturar los patrones subyacentes y desarrollar modelos que realicen predicciones precisas y sean resistentes a las fluctuaciones aleatorias.
Paso 3: Entrenamiento y seguimiento del modelo
Ahora que tiene los datos disponibles, defina el modelo de previsión. En este cuaderno, aplique el modelo de pronóstico denominado media móvil integrada autorregresiva de temporada con factores exógenos (SARIMAX). SARIMAX combina componentes de regresión automática (AR) y media móvil (MA), diferenciación de temporada y predictores externos para realizar previsiones precisas y flexibles de los datos de serie temporal.
Use también MLflow y el registro automático de Fabric para realizar un seguimiento de los experimentos. Aquí cargará la tabla delta desde el almacén de lago. Puede usar otras tablas diferenciales que tengan en cuenta el almacén de lago como origen.
# Import required libraries for model evaluation
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error
Ajuste de hiperparámetros
SARIMAX tiene en cuenta los parámetros implicados en el modo de media móvil integrada autorregresiva (ARIMA) normal (p
, d
, q
) y también agrega los parámetros de temporalidad (P
, D
, Q
, s
). Estos argumentos para el modelo de SARIMAX se denominan order (p
, d
y q
) y seasonal order (P
, D
, Q
y s
), respectivamente. Por lo tanto, para entrenar el modelo, primero debemos ajustar siete parámetros.
Parámetros de order:
p
: el orden del componente de AR representa el número de observaciones pasadas de la serie temporal que se usan para predecir el valor actual.Normalmente, este parámetro debería ser un entero no negativo. Los valores comunes suelen estar en el intervalo de
0
a3
, aunque es posible alcanzar valores más altos en función de las características específicas de los datos. Un valor dep
más alto indica una memoria más larga de valores anteriores en el modelo.d
: el orden de diferenciación representa el número de veces que debe diferenciarse la serie temporal para lograr la estacionalidad.Este parámetro debe ser un entero no negativo. Los valores comunes están en el intervalo de
0
a2
. Un valor ded
de0
significa que la serie temporal ya es estacionaria. Los valores más altos indican el número de operaciones de diferenciación necesarias para que sea estacionaria.q
: el orden del componente de MA representa el número de términos de error de ruido blanco pasados que se usan para predecir el valor actual.Este parámetro debe ser un entero no negativo. Los valores comunes están en el intervalo de
0
a3
, pero puede que se necesiten unos valores más altos en el caso de determinadas series temporales. Un valor deq
más alto indica una mayor dependencia de los términos de error pasados para realizar predicciones.
Parámetros de seasonal order:
P
: el orden de temporada del componente de AR, similar ap
, pero para la parte de temporadaD
: el orden de temporada de diferenciación, similar ad
, pero para la parte de temporadaQ
: el orden de temporada del componente de MA, similar aq
, pero para la parte de temporadas
: el número de pasos de tiempo por ciclo de temporada (por ejemplo, 12 para datos mensuales con una temporalidad anual)
# Hyperparameter tuning
p = d = q = range(0, 2)
pdq = list(itertools.product(p, d, q))
seasonal_pdq = [(x[0], x[1], x[2], 12) for x in list(itertools.product(p, d, q))]
print('Examples of parameter combinations for Seasonal ARIMA...')
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[1]))
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[2]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[3]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[4]))
SARIMAX tiene otros parámetros:
enforce_stationarity
: si el modelo debe aplicar la estacionalidad o no en los datos de serie temporal antes de ajustar el modelo SARIMAX.Si
enforce_stationarity
se establece enTrue
(valor predeterminado), indica que el modelo SARIMAX debe aplicar la estacionalidad en los datos de serie temporal. En tal caso, el modelo SARIMAX aplica automáticamente la diferenciación a los datos para que sean fijos, según lo especificado por los órdenesd
yD
, antes de ajustar el modelo. Se trata de una práctica común, ya que muchos modelos de serie temporal, entre ellos SARIMAX, dan por hecho que los datos son fijos.En el caso de las series temporales que no son fijas (por ejemplo, muestra tendencias o temporalidad), se recomienda establecer
enforce_stationarity
enTrue
y permitir que el modelo SARIMAX controle la diferenciación para lograr la estacionalidad. En el caso de las series temporales fijas (por ejemplo, no tiene tendencias ni temporalidad), establezcaenforce_stationarity
enFalse
para evitar la diferenciación innecesaria.enforce_invertibility
: controla si el modelo debe aplicar la invertibilidad o no en los parámetros estimados durante el proceso de optimización.Si
enforce_invertibility
se establece enTrue
(valor predeterminado), indica que el modelo SARIMAX debe aplicar la invertibilidad en los parámetros estimados. La invertibilidad garantiza que el modelo esté bien definido y que los coeficientes estimados de AR y MA estén dentro del intervalo de estacionalidad.La obligatoriedad de la invertibilidad ayuda a asegurarse de que el modelo SARIMAX cumple los requisitos teóricos de un modelo de serie temporal estable. También ayuda a evitar problemas con la estimación y estabilidad del modelo.
El valor predeterminado es un modelo de AR(1)
Esto hace referencia a (1, 0, 0)
. Sin embargo, es habitual probar diferentes combinaciones de los parámetros de order y seasonal order, y evaluar el rendimiento del modelo para un conjunto de datos. Los valores adecuados pueden variar de una serie temporal a otra.
Determinar los valores óptimos a menudo implica analizar la función de autocorrelación (ACF) y la función de autocorrelación parcial (PACF) de los datos de la serie temporal. También suele implicar el uso de criterios de selección de modelos, como el criterio de información de Akaike (AIC) o el criterio de información bayesiano (BIC).
Ajuste de los hiperparámetros:
# Tune the hyperparameters to determine the best model
for param in pdq:
for param_seasonal in seasonal_pdq:
try:
mod = sm.tsa.statespace.SARIMAX(y,
order=param,
seasonal_order=param_seasonal,
enforce_stationarity=False,
enforce_invertibility=False)
results = mod.fit(disp=False)
print('ARIMA{}x{}12 - AIC:{}'.format(param, param_seasonal, results.aic))
except:
continue
Tras la evaluación de los resultados anteriores, puede determinar los valores de los parámetros de order y, a continuación, los de seasonal order. La opción es order=(0, 1, 1)
y seasonal_order=(0, 1, 1, 12)
, que ofrecen el AIC más bajo (por ejemplo, 279,58). Utilice estos valores para entrenar el modelo.
Entrenamiento del modelo
# Model training
mod = sm.tsa.statespace.SARIMAX(y,
order=(0, 1, 1),
seasonal_order=(0, 1, 1, 12),
enforce_stationarity=False,
enforce_invertibility=False)
results = mod.fit(disp=False)
print(results.summary().tables[1])
Este código visualiza una previsión de series temporales para los datos de ventas de muebles. Los resultados trazados muestran los datos observados y el pronóstico de un paso adelante, con una región sombreada para el intervalo de confianza.
# Plot the forecasting results
pred = results.get_prediction(start=maximim_date, end=maximim_date+pd.DateOffset(months=6), dynamic=False) # Forecast for the next 6 months (months=6)
pred_ci = pred.conf_int() # Extract the confidence intervals for the predictions
ax = y['2019':].plot(label='observed')
pred.predicted_mean.plot(ax=ax, label='One-step ahead forecast', alpha=.7, figsize=(12, 7))
ax.fill_between(pred_ci.index,
pred_ci.iloc[:, 0],
pred_ci.iloc[:, 1], color='k', alpha=.2)
ax.set_xlabel('Date')
ax.set_ylabel('Furniture Sales')
plt.legend()
plt.show()
# Validate the forecasted result
predictions = results.get_prediction(start=maximim_date-pd.DateOffset(months=6-1), dynamic=False)
# Forecast on the unseen future data
predictions_future = results.get_prediction(start=maximim_date+ pd.DateOffset(months=1),end=maximim_date+ pd.DateOffset(months=6),dynamic=False)
Use predictions
para evaluar el rendimiento del modelo comparándolo con los valores reales. El valor de predictions_future
indica la previsión futura.
# Log the model and parameters
model_name = f"{EXPERIMENT_NAME}-Sarimax"
with mlflow.start_run(run_name="Sarimax") as run:
mlflow.statsmodels.log_model(results,model_name,registered_model_name=model_name)
mlflow.log_params({"order":(0,1,1),"seasonal_order":(0, 1, 1, 12),'enforce_stationarity':False,'enforce_invertibility':False})
model_uri = f"runs:/{run.info.run_id}/{model_name}"
print("Model saved in run %s" % run.info.run_id)
print(f"Model URI: {model_uri}")
mlflow.end_run()
# Load the saved model
loaded_model = mlflow.statsmodels.load_model(model_uri)
Paso 4: Puntuación del modelo y guardado de las predicciones
Integre los valores reales con los valores previstos para crear el informe de Power BI. Almacene estos resultados en una tabla dentro del almacén de lago.
# Data preparation for Power BI visualization
Future = pd.DataFrame(predictions_future.predicted_mean).reset_index()
Future.columns = ['Date','Forecasted_Sales']
Future['Actual_Sales'] = np.NAN
Actual = pd.DataFrame(predictions.predicted_mean).reset_index()
Actual.columns = ['Date','Forecasted_Sales']
y_truth = y['2023-02-01':]
Actual['Actual_Sales'] = y_truth.values
final_data = pd.concat([Actual,Future])
# Calculate the mean absolute percentage error (MAPE) between 'Actual_Sales' and 'Forecasted_Sales'
final_data['MAPE'] = mean_absolute_percentage_error(Actual['Actual_Sales'], Actual['Forecasted_Sales']) * 100
final_data['Category'] = "Furniture"
final_data[final_data['Actual_Sales'].isnull()]
input_df = y.reset_index()
input_df.rename(columns = {'Order Date':'Date','Sales':'Actual_Sales'}, inplace=True)
input_df['Category'] = 'Furniture'
input_df['MAPE'] = np.NAN
input_df['Forecasted_Sales'] = np.NAN
# Write back the results into the lakehouse
final_data_2 = pd.concat([input_df,final_data[final_data['Actual_Sales'].isnull()]])
table_name = "Demand_Forecast_New_1"
spark.createDataFrame(final_data_2).write.mode("overwrite").format("delta").save(f"Tables/{table_name}")
print(f"Spark DataFrame saved to delta table: {table_name}")
Paso 5: Visualización en Power BI
En el informe de Power BI se muestra un error de porcentaje absoluto medio (MAPE) de 16,58. La métrica MAPE define la precisión de un método de pronóstico. Representa la precisión de las cantidades pronosticadas en comparación con las cantidades reales.
MAPE es una métrica sencilla. Un MAPE del 10 % representa que la desviación media entre los valores previstos y los valores reales es del 10 %, independientemente de si la desviación era positiva o negativa. Los estándares de valores MAPE deseables varían en todos los sectores.
La línea azul claro de este gráfico representa los valores reales de ventas. La línea azul oscuro representa los valores de ventas pronosticados. La comparación entre las ventas reales y previstas revela que el modelo predice eficazmente las ventas de la categoría Furniture
durante los primeros seis meses de 2023.
En función de esta observación, podemos tener confianza en las funcionalidades de previsión del modelo para las ventas generales en los últimos seis meses de 2023 y hasta 2024. Esta confianza puede hacer que tomen forma decisiones estratégicas sobre la gestión de inventarios, la adquisición de materias primas y otras consideraciones relacionadas con la empresa.