Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Este tutorial apresenta um exemplo de ponta a ponta de um fluxo de trabalho de Ciência de Dados do Synapse no Microsoft Fabric. O cenário cria um modelo de previsão que usa dados históricos de vendas para prever vendas de categoria de produto em um superlocatário.
A previsão é um ativo crucial nas vendas. Ele combina dados históricos e métodos preditivos para fornecer insights sobre tendências futuras. A previsão pode analisar vendas passadas para identificar padrões. Ele também pode aprender com o comportamento do consumidor para otimizar estratégias de inventário, produção e marketing. Essa abordagem proativa aprimora a adaptabilidade, a capacidade de resposta e o desempenho geral dos negócios em um marketplace dinâmico.
Este tutorial aborda estas etapas:
- Carregar os dados
- Usar a análise de dados exploratória para entender e processar os dados
- Treinar um modelo de machine learning com um pacote de software livre
- Acompanhar experimentos com o MLflow e o recurso de registro automático do Fabric
- Salvar o modelo final de machine learning e fazer previsões
- Mostrar o desempenho do modelo com visualizações do Power BI
Pré-requisitos
Obtenha uma assinatura do Microsoft Fabric . Ou cadastre-se para uma avaliação gratuita do Microsoft Fabric.
Entre no Microsoft Fabric.
Alterne para o Fabric usando o alternador de experiências no canto inferior esquerdo da página inicial.
- Se necessário, crie um lakehouse do Microsoft Fabric, conforme descrito no recurso Criar um lakehouse no Microsoft Fabric .
Acompanhar em um notebook
Para acompanhar em um notebook, você tem estas opções:
- Abrir e executar o notebook interno na experiência de Ciência de Dados do Synapse
- Carregar seu notebook do GitHub para a experiência de Ciência de Dados do Synapse
Abrir o bloco de anotações interno
O notebook de Previsão de vendas de exemplo acompanha este tutorial.
Para abrir o bloco de anotações de exemplo para este tutorial, siga as instruções em Preparar seu sistema para tutoriais de ciência de dados.
Certifique-se de anexar um lakehouse ao notebook antes de começar a executar o código.
Importar o notebook do GitHub
O notebook AIsample – Superstore Forecast.ipynb acompanha este tutorial.
Para abrir o bloco de anotações que acompanha este tutorial, siga as instruções em Preparar seu sistema para tutoriais de ciência de dados para importar o bloco de anotações para sua área de trabalho.
Se você prefere copiar e colar o código desta página, pode criar um notebook.
Certifique-se de anexar um lakehouse ao notebook antes de começar a executar o código.
Etapa 1: Carregar os dados
O conjunto de dados tem 9.995 instâncias de vendas de vários produtos. Ele também inclui 21 atributos. O notebook usa um arquivo chamado Superstore.xlsx. Esse arquivo tem essa estrutura de tabela:
| ID de linha | ID do pedido | Data do pedido | Data do envio | Modo de Envio | ID do cliente | Nome do cliente | Segmento | País | Cidade | Estado | Código postal | Região | ID do produto | Categoria | Subcategoria | Nome do produto | Sales | Quantidade | Desconto | Lucro |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 4 | EUA-2015-108966 | 2015-10-11 | 2015-10-18 | Classe Standard | SO-20335 | Sean O'Donnell | Consumidor | Estados Unidos | Fort Lauderdale | Flórida | 33311 | Sul | FUR-TA-10000577 | Mobiliário | Tabelas | Mesa Retangular Slim da Série Bretford CR4500 | 957,5775 | 5 | 0.45 | -383.0310 |
| 11 | CA-2014-115812 | 2014-06-09 | 2014-06-09 | Classe Standard | Classe Standard | Brosina Hoffman | Consumidor | Estados Unidos | Los Angeles | Califórnia | 90032 | Oeste | FUR-TA-10001539 | Mobiliário | Tabelas | Mesas retangulares para conferência Chromcraft | 1706.184 | 9 | 0.2 | 85.3092 |
| 31 | EUA-2015-150630 | 2015-09-17 | 2015-09-21 | Classe Standard | TB-21520 | Tracy Blumstein | Consumidor | Estados Unidos | Filadélfia | Pensilvânia | 19140 | Leste | OFF-EN-10001509 | Material de escritório | Envelopes | Envelopes de amarração com cordão de polietileno | 3,264 | 2 | 0.2 | 1,1016 |
O snippet de código a seguir define parâmetros específicos, para que você possa usar este notebook com conjuntos de dados diferentes:
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
Baixar o conjunto de dados e carregar no lakehouse
O trecho de código a seguir baixa uma versão disponível publicamente do conjunto de dados e, em seguida, armazena esse conjunto de dados em um Fabric lakehouse.
Importante
Você deve adicionar um lakehouse ao notebook antes de executá-lo. Caso contrário, você receberá um erro.
import os, requests
if not IS_CUSTOM_DATA:
# Download data files into the lakehouse if they're not already there
remote_url = "https://synapseaisolutionsa.z13.web.core.windows.net/data/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.")
Configurar o acompanhamento de experimentos do MLflow
O Microsoft Fabric captura automaticamente os valores de parâmetro de entrada e as métricas de saída de um modelo de machine learning enquanto você o treina. Isso estende os recursos de registro automático do MLflow. Em seguida, as informações são registradas no workspace, onde você pode acessá-la e visualizá-la com as APIs do MLflow ou o experimento correspondente no workspace. Para obter mais informações sobre o autologging, visite o recurso Autologging em Microsoft Fabric.
Para desativar o registro automático do Microsoft Fabric em uma sessão de notebook, chame mlflow.autolog() e defina disable=True, conforme mostrado no seguinte snippet de código:
# Set up MLflow for experiment tracking
import mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True) # Turn off MLflow autologging
Ler dados brutos do lakehouse
O trecho de código a seguir lê dados brutos da seção Arquivos do lakehouse. Ele também adiciona mais colunas para diferentes partes de data. As mesmas informações criam uma tabela delta particionada. Como os dados brutos são armazenados como um arquivo do Excel, você deve usar pandas para lê-los.
import pandas as pd
df = pd.read_excel("/lakehouse/default/Files/salesforecast/raw/Superstore.xlsx")
Etapa 2: executar análise de dados exploratória
Importar bibliotecas
Importe as bibliotecas necessárias antes de iniciar a análise:
# 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
Exibir os dados brutos
Para entender melhor o próprio conjunto de dados, examine manualmente um subconjunto dos dados. Use a display função para imprimir o DataFrame. As Chart exibições podem visualizar facilmente subconjuntos do conjunto de dados:
display(df)
Este tutorial aborda um bloco de anotações que se concentra principalmente nas Furniture previsões de venda de categoria. Essa abordagem acelera a computação e ajuda a mostrar o desempenho do modelo. No entanto, este notebook usa técnicas adaptáveis. Você pode estender essas técnicas para prever as vendas de outras categorias de produtos. O snippet de código a seguir seleciona Furniture como a categoria do produto:
# Select "Furniture" as the product category
furniture = df.loc[df['Category'] == 'Furniture']
print(furniture['Order Date'].min(), furniture['Order Date'].max())
Pré-processar os dados
Cenários de negócios do mundo real geralmente precisam prever vendas em três categorias distintas:
- Categoria de produto específica
- Categoria de cliente específica
- Combinação específica de categoria de produto e categoria de cliente
O snippet de código a seguir descarta colunas desnecessárias para pré-processar os dados. Não precisamos de algumas das colunas (Row ID, Order IDeCustomer IDCustomer Name ) porque elas não têm relevância. Queremos prever as vendas gerais, em todo o estado e região, para uma categoria de produto específica (Furniture). Portanto, podemos remover as colunas State, Region, Country, City e Postal Code. Para prever vendas para um local ou categoria específico, talvez seja necessário ajustar a etapa de pré-processamento adequadamente.
# 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()
O conjunto de dados é estruturado diariamente. Devemos resamplar na Order Date coluna, pois queremos desenvolver um modelo para prever as vendas mensalmente.
Primeiro, agrupe a categoria Furniture por Order Date. Em seguida, calcule a soma da Sales coluna para cada grupo, para determinar o total de vendas para cada valor exclusivo Order Date . Resamplar a coluna Sales com a frequência MS, para agregar os dados por mês. Por fim, calcule o valor médio de vendas para cada mês. O snippet de código a seguir mostra estas etapas:
# 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()
No snippet de código a seguir, mostre o impacto de Order Date sobre Sales na categoria Furniture.
# Impact of order date on the sales
y.plot(figsize=(12, 3))
plt.show()
Antes de qualquer análise estatística, você deve importar o módulo statsmodels Python. Este módulo fornece classes e funções para estimar muitos modelos estatísticos. Ele também fornece classes e funções para realizar testes estatísticos e exploração de dados estatísticos. O snippet de código a seguir mostra esta etapa:
import statsmodels.api as sm
Executar análise estatística
Uma série temporal rastreia esses elementos de dados em intervalos definidos, para determinar a variação desses elementos no padrão de série temporal:
Nível: o componente fundamental que representa o valor médio para um período de tempo específico
Trend: descreve se a série temporal diminui, permanece constante ou aumenta ao longo do tempo
Sazonalidade : descreve o sinal periódico nas séries temporais e procura ocorrências cíclicas que afetam os padrões das séries temporais crescentes ou decrescentes.
Ruído/Residual: refere-se às flutuações aleatórias e à variabilidade nos dados de série temporal que não podem ser explicados pelo modelo.
O snippet de código a seguir mostra esses elementos para o conjunto de dados, após o pré-processamento:
# 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()
Os gráficos descrevem a sazonalidade, as tendências e o ruído nos dados de previsão. Você pode capturar os padrões subjacentes e desenvolver modelos que fazem previsões precisas que têm resiliência contra flutuações aleatórias.
Etapa 3: Treinar e acompanhar o modelo
Agora que você tem os dados disponíveis, defina o modelo de previsão. Neste notebook, aplique o modelo de previsão média móvel integrada autoregressiva sazonal com fatores exógenos (SARIMAX). O SARIMAX combina componentes de AR (autoregressivo) e média móvel (MA), diferenciação sazonal e previsores externos para fazer previsões precisas e flexíveis para dados de série temporal.
Você também usa o registro automático do MLflow e do Fabric para acompanhar os experimentos. Aqui, carregue a tabela delta do lakehouse. Você pode usar outras tabelas delta que consideram o lakehouse como a origem. O snippet de código a seguir importa as bibliotecas necessárias:
# Import required libraries for model evaluation
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error
Ajustar hiperparâmetros
O SARIMAX leva em consideração os parâmetros envolvidos no modelo ARIMA (média móvel integrada autoregressiva) regular (p, d, q) e adiciona os parâmetros de sazonalidade (P, D, Q, s). Esses argumentos do modelo SARIMAX são nomeados ordem (p, d, q) e ordem sazonal (P, D, Q, s), respectivamente. Portanto, para treinar o modelo, primeiro devemos ajustar sete parâmetros.
Os parâmetros de ordem:
p: a ordem do componente AR, que representa o número de observações passadas na série temporal usada para prever o valor atual.Normalmente, esse parâmetro deve ter um valor inteiro não negativo. Os valores comuns estão no intervalo de
0a3. No entanto, valores mais altos são possíveis, dependendo das características de dados específicas. Um valor depmais alto indica uma memória mais longa de valores passados no modelo.d: a ordem de diferenciação, que representa o número de vezes que a série temporal precisa ser diferenciada para alcançar a estacionariedade.Esse parâmetro deve ter um valor inteiro não negativo. Os valores comuns estão no intervalo de
0a2. Um valordde0significa que a série temporal já está estacionária. Valores maiores indicam que o número de operações de diferenciação necessárias para torná-lo estacionário é maior.q: a ordem do componente MA. Esse parâmetro representa o número de termos de erro de ruído branco usados para prever o valor atual.Esse parâmetro deve ter um valor inteiro não negativo. Os valores comuns estão no intervalo de
0até3, mas determinadas séries temporais podem exigir valores mais altos. Um valor deqmais alto indica uma dependência mais forte em termos de erro anteriores para fazer previsões.
Os parâmetros de ordem sazonal:
-
P: a ordem sazonal do componente AR, semelhante aopparâmetro, mas abrangendo a parte sazonal -
D: a ordem sazonal de diferenciação, semelhante aodparâmetro, mas abrangendo a parte sazonal -
Q: a ordem sazonal do componente de MA, semelhante aoqparâmetro, mas abrangendo a parte sazonal -
s: o número de etapas de tempo por ciclo sazonal (por exemplo, 12 para dados mensais com sazonalidade 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]))
O SARIMAX tem outros parâmetros:
enforce_stationarity: Se o modelo deve ou não impor a estacionariedade nos dados de série temporal, antes de ajustar o modelo SARIMAX.Um valor
enforce_stationaritydeTrue(o padrão) indica que o modelo SARIMAX deve impor estacionariedade nos dados da série temporal. Antes de ajustar o modelo, o modelo SARIMAX aplica automaticamente a diferenciação aos dados para torná-los estacionários, conforme especificado pelas ordensdeD. Essa é uma prática comum porque muitos modelos de série temporal, incluindo SARIMAX, pressupõem esses dados estacionários.Para uma série temporal não estacionária (por exemplo, uma série que exibe tendências ou sazonalidade), é uma boa prática definir
enforce_stationarityentreTrue, e permitir que o modelo SARIMAX lide com a diferença para alcançar a estacionaridade. Para uma série temporal estacionária (por exemplo, uma sem tendências ou sazonalidade), definaenforce_stationarityparaFalsepara evitar diferenciações desnecessárias.enforce_invertibility: controla se o modelo deve ou não impor a invertibilidade nos parâmetros estimados durante o processo de otimização.Um valor
enforce_invertibilitydeTrue(com o valor padrãoTrue) indica que o modelo SARIMAX deve impor a inversibilidade nos parâmetros estimados. A invertibilidade garante que exista um modelo bem definido e que os coeficientes de AR e MA estimados fiquem dentro do intervalo de estacionaridade.A imposição de invertibilidade ajuda a garantir que o modelo SARIMAX adere aos requisitos teóricos de um modelo de série temporal estável. Ele também ajuda a evitar problemas com a estimativa e estabilidade do modelo.
Um AR(1) modelo é o padrão. Isso se refere a (1, 0, 0). No entanto, é uma prática comum experimentar combinações diferentes dos parâmetros de ordem e parâmetros de ordem sazonal e avaliar o desempenho do modelo para um conjunto de dados. Os valores apropriados podem variar de uma série temporal para outra.
A determinação dos valores ideais geralmente envolve a análise da ACF (função de autocorrelação) e da PACF (função de autocorrelação parcial) dos dados da série temporal. Ele também geralmente envolve o uso de critérios de seleção de modelo - por exemplo, o critério de informações do Akaike (AIC) ou o critério de informações bayesianas (BIC).
Ajuste os hiperparâmetros, conforme mostrado no seguinte snippet de código:
# 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
Após a avaliação dos resultados anteriores, você pode determinar os valores para os parâmetros de ordem e os parâmetros de ordem sazonal. A opção é order=(0, 1, 1) e seasonal_order=(0, 1, 1, 12), que oferecem o AIC mais baixo (por exemplo, 279,58). Use esses valores para treinar o modelo. O snippet de código a seguir mostra esta etapa:
Treinar o 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])
Esse código visualiza uma previsão de série temporal para dados de vendas de móveis. Os resultados plotados mostram os dados observados e a previsão de um passo à frente, com uma região sombreada para intervalo de confiança. Os snippets de código a seguir mostram a visualização:
# 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)
O snippet de código a seguir usa predictions para avaliar o desempenho do modelo, contrastando-o com os valores reais. O valor predictions_future indica previsão 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)
Etapa 4: Pontuar o modelo e salvar as previsões
O snippet de código a seguir integra os valores reais com os valores previstos para criar um relatório do Power BI. Além disso, armazena esses resultados em uma tabela dentro do lakehouse.
# 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}")
Etapa 5: Visualizar no Power BI
O relatório do Power BI mostra um MAPE (erro percentual absoluto médio) de 16,58. A métrica MAPE define a precisão de um método de previsão. Representa a precisão das quantidades previstas, em comparação com as quantidades reais.
MAPE é uma métrica simples. Um MAPE de 10% representa que o desvio médio entre os valores previstos e os valores reais é de 10%, independentemente de o desvio ser positivo ou negativo. Os padrões de valores MAPE desejáveis variam entre os setores.
A linha azul claro neste grafo representa os valores reais de vendas. A linha azul escuro representa os valores de vendas previstos. A comparação de vendas reais e previstas revela que o modelo prevê efetivamente as vendas para a categoria Furniture nos primeiros seis meses de 2023.
Com base nessa observação, podemos ter confiança nos recursos de previsão do modelo para as vendas gerais nos últimos seis meses de 2023 e estendendo-se até 2024. Essa confiança pode informar decisões estratégicas sobre gerenciamento de estoque, aquisição de matérias-primas e outras considerações relacionadas aos negócios.