Prévia do material em texto
<p>30/04/2023, 23:11 Jupyter Notebook FUNDAÇÃO EDSON QUEIROZ UNIVERSIDADE DE FORTALEZA ENSINANDO E APRENDENDO UNIVERSIDADE DE FORTALEZA MBA em Ciência de Dados Prof. Caio Ponte Discente: Sabrina Rodrigues de Sousa Matrícula:2129475 Trabalho de Conclusão de curso Machine learning 1. Introdução Nesta tarefa, primeiro iremos identificar qual são os produtos que representam as maiores vendas da empresa e a partir dessa informação, criar um modelo de Machine Learning que faça a previsão de vendas de cada produto, podendo assim ser aplicados para os produtos mais vendidos. Por meio do resultado das previsões, a empresa conseguirar ter uma estimativa de quantos produtos irá vender e conseguirá se preparar com relação ao estoque do seu produto, não deixando-os faltar nem sobrar demasiadamente. 2. Dados e ferramentas Os dados usados foram extraidos das saidas de produtos de uma empresa de venda de equipamentos e veículos pesados. Os arquivos, ques estão no formato CSV,contemplam as saidas dentre os anos 2010 2023. 2.1 Sobre os arquivos utilizados Notas de saida -(notas_saidas.csv): Dataframe com os dados de saida de produtos, com informações como data, filial, natureza_da_operacao, entre outros dados 1/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30- Jupyter Notebook Os dois arquivos foram disponibilizados pela empresa. 3 Carga e Análise exploratória 3.1.1 Importando Módulos In [51]: !pip install plotly Requirement already satisfied: plotly in ckages (5.13.1) Requirement already satisfied: tenacity>=6.2.0 in c:\users\sabri\anaconda3\li b\site-packages (from plotly) (8.2.2) 2/31</p><p>30/04/2023, 23:11 Jupyter Notebook In [52]: #Importação das Bibliotecas necessárias para trabalho import pandas as pd import numpy as np import re import matplotlib.pyplot as plt import matplotlib.dates as mdates import seaborn as sns #from import LinearRegression #from sklearn.metrics import mean_square_error #from import LinearRegression from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.tree import cisionTreeRegressor, plot_tree from sklearn.metrics import mean_absolute_error, from sklearn.ensemble import AdaBoostRegressor, from math import ceil from statsmodels.tsa.seasonal import seasonal_decompose from statsmodels.tsa.stattools import adfuller from statsmodels.graphics.tsaplots import plot_acf,plot_pacf from statsmodels.tsa.statespace.sarimax import SARIMAX from statsmodels.tsa.arima.model import ARIMA from statsmodels.tsa.arima_model import ARMA ! pip install pmdarima from pmdarima import auto_arima pd.options.plotting.backend "plotly" %matplotlib inline 3/31</p><p>30/04/2023, 23:11 - Notebook Requirement already satisfied: pmdarima in c:\users\sabri\anaconda3\lib\site- packages (2.0.3) Requirement already satisfied: numpy>=1.21.2 in \site-packages (from pmdarima) (1.23.5) Requirement already satisfied: scikit-learn>=0.22 in \lib\site-packages (from pmdarima) (1.1.2) Requirement already satisfied: pandas>=0.19 in ite-packages - (from pmdarima) (1.2.4) Requirement already satisfied: statsmodels>=0.13.2 in c:\users\sabri\anaconda 3\lib\site-packages (from pmdarima) (0.13.5) Requirement already satisfied: in c:\users\sabri \anaconda3\lib\site-packages (from pmdarima) (52.0.0.post20210125) Requirement already satisfied: scipy>=1.3.2 in c:\users\sabri\anaconda3\lib\s ite-packages (from pmdarima) (1.9.3) Requirement already satisfied: joblib>=0.11 in ite-packages (from pmdarima) (1.0.1) Requirement already satisfied: urllib3 in ackages (from pmdarima) (1.26.4) Requirement already satisfied: c:\users\s abri\anaconda3\lib\site-packages (from pmdarima) (0.29.23) Requirement already satisfied: python-dateutil>=2.7.3 in (from pandas>=0.19->pmdarima) (2.8.1) Requirement already satisfied: pytz>=2017.3 in ite-packages (from pandas>=0.19->pmdarima) (2021.1) Requirement already satisfied: six>=1.5 in :\users\sabri\anaconda3\lib\site- packages (from (1.15.0) Requirement already satisfied: threadpoolctl>=2.0.0 in c:\users\sabri\anacond a3\lib\site-packages (from scikit-learn>=0.22->pmdarima) (2.1.0) Requirement already satisfied: packaging>=21.3 in c:\users\sabri\anaconda3\li b\site-packages (from statsmodels>=0.13.2->pmdarima) (23.0) Requirement already satisfied: patsy>=0.5.2 in :\users\sabri\anaconda3\lib\s ite-packages (from statsmodels>=0.13.2->pmdarima) (0.5.3) 3.1.2 Arquitetura dos dados 4/31</p><p>30/04/2023, 23:11 Notebook In [53]: from PIL import Image %matplotlib inline im = Image.oper im. show() im estado Código UF da loja filial Descrição do tipo de destinação do produto Código da forma de pagamento do produto dt emissao Data da emissão de saída do produto - Peso bruto Peso líquido Valor final total de venda, incluindo outros produtos e descontos vr mercadoria Valor bruto da venda, sem desconto para cliente. Valor de tributação da venda Valor restante após a tributação Código do produto produto_qtd Quantidade de saídas de produto Valor unitário do produto Valor do desconto unitário produto Valor de acréscimo unitário do produto produtovrtotal Valor total vendido do produto Descrição do tipo unitário do produto Peso líquido do produto Peso bruto do produto produto custo Valor de compra do produto (total) 3.1.3 Importando os dados Os dados em formato de CSV são importados em data frames In [54]: df_notas_saidas = In [55]: 3.1.4 Avaliando os dados 5/31</p><p>30/04/2023, 23:11 - Jupyter Notebook In [56] : df_notas_saidas.head() Out [56]: filial estado natureza_da_operacao cod_condicao_pagamento dt_emissao peso_bruto peso VENDA MERC. SUBST. 0 1 CE 99 2018-05-18 0.0 TRIBUTARIA OPERACAO EM 1 1 CE 3 2016-07-27 0.0 GARANTIA VENDA MERC. SUBST. 2 1 CE 10 2016-07-27 0.0 TRIBUTARIA VENDA MERC. SUBST. 3 1 CE 5 2014-01-24 0.0 TRIBUTARIA VENDA MERC. SUBST. 4 1 CE 10 2016-07-27 0.0 TRIBUTARIA Agora que tivemos o primeiro contato com os dados, devemos levar em consideração um fato relevantes sobre os dados. Os dados de saidas dos produtos dentro da empresa podem ser ocasionados por diversos fatores, mas para o intuito do estudo, só será levado em consideração a venda de peças, desconsiderando outras saidas e vendas futuras. 6/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30 - Jupyter Notebook In [57]: #demonstrando os tipos de saidas oferecidas pelos dataset unique() 7/31</p><p>30/04/2023, 23:11 Notebook Out[57]: array(['VENDA MERC. SUBST. TRIBUTARIA', EM GARANTIA', 'VENDAS DE MERCADORIA', OU FEIRA', SUBSTITUICAO TRIB. REMESSA REC.P/DEMONSTR', 'DEVOLUCAO DE COMPRA', 'VENDA MERC. 'VENDA CAMINHOES TRANSF.MERC.P/CONSUMO INTERNO', 'REME P/IND CONTA E ORD TERCEIR', PARA COMERCIALIZACAO', 'NOTA FISCAL COMPLEMENTAR', 'VENDA TRATOR NOVA', 'VENDA DE 'VENDAS DE MERCADORI/VENDAS DE MERCA', 'REMESSA MERCADORIA CONSERTO', 'REMESSA PARA DEMONSTRACAO', 'VENDA DE IMPLEMENTO', 'RETORNO DEMONSTRACAO', 'VENDAS DE MERCADORI/VENDA MERC. SUB', REMESSAO PARA 'SIMPLES REMESSA', 'VENDA MERC. SUBST. 'REMESSA P/INDUST.POR ENCOMENDA', 'VENDA MERC.SUBST. TRIBUTARIA', GARANTIA FABRICA', 'VENDA DE VEICULO USADO', RETORNO DE RECEB. PARA CONSERT', DE MERCADORIA DEPOSITADA', SIMPLES REMESSA GARANTIA', 'OUTRAS 'REMESSA PARA DEPÓSITO FECHADO', 'SAIDA AJUSTE INVENTARIO', OUTRAS SAIDAS AJUSTE DE INVENT', 'LANC. EFET. DEC. CUPOM FISCAL', 'VENDA MERC. SUBST.TRIBUTARI/VENDA M', 'VENDA MERC. SUBST. TRIBUTAR/VENDA M', 'VENDA DE MERCAD. C/SUBST.TRIBU', 'NOTA FISCAL COMPLEMENTAR CAMIN', DE VALOR DE SERV TRAN', 'NOTA FISCAL COMPLENTAR PECAS', 'VENDA PARA ENTREGA FUTURA', 'DOC.AJUSTE ESTOQUE', EXTERNA REVISAO', 'REMESSA MERC P CONTA E ORDEM T', 'TRANSF . IMOBILIZADO', 'VENDA DE ONIBUS NOVOS', 'VENDA DE MAQUINAS USADAS S.T', 'VENDA MERC. ORIG. FAT.ENT.FUTU', 'REMESSA DE SUCATA', 'SAIDA DE MERCADORIA OBSOLETA', 'REMESSA BEM EM COMODATO', 'VENDAS DE CARROCERIA NOVA', 'VENDA EM CONSIGNAÇÃO', 'REVISAO ENTREGA', RETORNO BEM REC POR COMODATO', 'SIMPLES REMESSA EM GARANTIA', GARANTIA VOLKS 'CONSUMO INTERNO', EM GARANTI/OPERACA EM GAR', 'TRANSF . MAT.CONSUMO', 'NOTA COMPLEMENTAR ICMS', 'VENDA CAMINHOES NOVOS SUBST. T', 'VENDA DE IMPLEMENTO SUBST.TRIB', MAT.CONSUMO' OPERACAO EM GARANTI/OPERACAO E', 'DEV DE BEM DO ATIVO IMOB TERCE', 'VENDA PECAS REDE VW', 'RESSARCIMENTO ICMS - ST', 'DEVOLUCAO DE COMPRA 'VENDA MERC. SUBST. TRIBUTAR/VE', 'NOTA FISCAL COMPLEMENTAR ONIBU', 'SAIDA EM BONIFICACAO OU BRINDE', 'VENDAS DE ATIVO 'VENDA MERC.SUBST. TRIBUTARI/VE', 'VENDA FUTURA', 'VENDA DE CAMINHOES NOVOS', DEV. IMOBILIZADO TERC PARA COMERCIALIZACAO', 'VENDA DE MAQUINAS', 'NOTA FISCAL COMPLENTAR', INTEGRAÇÃO AO ATIVO PERMANENTE', 'VENDA 'RETORNO REMESSA CONSIG SIMBOLI', 'VENDA CAMINHOES ST REMETIDA P', 'VENDA PECAS REDE MASSEY', 'VENDA CAMINHOES REMETIDA P IND', RETORNO DE MERC RECEB 'SERVICOS 'VENDA 'VENDA DE 'VENDA TRATORES NOVOS', 'VENDA CAMINHOES 'VENDA DE CARROCERIA NOVA', 'VENDA DE ONINUS NOVOS', 'VENDA MERC. SUBST. TRIBUTAR/SE' 'VENDA MERC. SUBST. 'NOTA CORRECAO DE DADOS', 'VENDA TRATORES VEICULO.P/ENTREGA FUTURA', RETORNO BEM COMODATO E CORRECAO DE DADOS', DEVOL.COMPRA ATIVO MAT.CONSU/TR', DO ATIVO IMOBILIZAD', 'VENDA COHEITADEIRA NOVA', 'VENDA COLHEITADEIRA NOVA', 'VENDAS DE EQUIPAMENTO', 8/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30-Jupyter - Notebook 'VENDA VEIC.PARA ENTREGA FUTURA', 'NOTA FISCAL COMPLEMENTAR CAMINHOES', (INTERNO SINC) SAIDA CUSTO', 'DEVOLUCAO SUBST. TRIBUTARIA', SUBSTITUICAO TRIB/TRANSF. S', 'REMESSA PARA GARANTIA', 'REMESSA DE BATERIAS', / DEVOL. C/C', 'REMESSA PARA LOCAÇÃO', 'VENDA A VISTA P ENTREGA FUTURA', 'REMESSA EM CONSIGNAÇÃO', 'VENDA DE EMPILHADEIRA', 'RETORNO GARANTIA FABRICA', 'OPERAÇÃO EM GARANTIA', 'VENDA VISTA P/ ENTREGA FUTURA', 'VENDA DE TRATOR USADO', 'COMPRA DE EMPILHADEIRAS 'REMESSA BEM EM COM. E 'ALUGUEL DE VEICUL. S/CONDUTOR', 'VENDA DE dtype=object) In [58]: #Filtrando somente os tipos de natureza da operação para o estudo. palavras = [ DE MERCADORIA', 'VENDA MERC. 'VENDAS DE MERCADORI/VENDAS DE MERCA', 'VENDA DE IMPLEMENTO', DE MERCADORI/VENDA MERC. SUB', 'VENDA MERC. SUBST. EFET. DEC. CUPOM MERC. SUBST.TRIBUTARI/VENDA M', 'VENDA MERC. SUBST. TRIBUTAR/VENDA M', 'VENDA DE MERCAD. C/SUBST.TRIBU', 'NOTA FISCAL COMPLENTAR PECAS', 'VENDA DE IMPLEMENTO SUBST.TRIB', 'VENDA PECAS REDE VW', 'VENDA MERC. SUBST. TRIBUTAR/VE', , MERC. SUBST. 'VENDAS PARA 'VENDA DE MAQUINAS', 'NOTA FISCAL COMPLENTAR', 'VENDA MERC.SUBST.TRIBUT 'VENDA PECAS REDE MASSEY', 'SERVICOS 'VENDA DE 'VENDA DE CARROCERIA NOVA', 'VENDA MERC. SUBST. TRIBUTAR/SE', 'VENDA MERC. SUBST. DE EQUIPAMENTO', 'VENDA DE SERVICO'] busca = join(palavras) df_notas_saidas = 9/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30- Jupyter Notebook In df_notas_saidas.head() Out [59]: filial estado natureza_da_operacao cod_condicao_pagamento dt_emissao peso_bruto peso VENDAS DE 7 1 CE 90 2017-09-04 0.0 MERCADORIA VENDAS DE 18 1 CE 3 2017-09-04 48.0 MERCADORIA VENDAS DE 28 1 CE 26 2017-09-04 0.0 MERCADORIA VENDAS DE 36 1 CE 26 2017-09-04 0.0 MERCADORIA VENDAS DE 77 5 PI 6 2016-07-27 0.0 MERCADORIA Com o dataset filtrado, podemos iniciar nossa primeira análise dos dados In [60]: # Shape dos dados df_notas_saidas.shap Out [60]: (194080, 21) n [61]: # Tipos de Dados df_notas_saidas.dtypes Out[61]: filial int64 estado object natureza_da_operacao object cod_condicao_pagamento int64 dt_emissao object peso_bruto float64 peso_liquido float64 vr_total_da_nota float64 vr_mercadoria float64 vr_tributado float64 vr_nao_tributado float64 produto_cod object produto_qtd float64 produto_vr_unitario float64 produto_vr_desconto float64 produto_vr_acrescimo float64 produto_vr_total float64 produto_unidade object produto_peso_liquido float64 produto_peso_bruto float64 produto_custo float64 dtype: object 10/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30-Jupyter Notebook In [62]: # Verificando valores missing df_notas_saidas.replace({" print(df_notas_saidas.isna().sum() filial 0 estado 0 natureza_da_operacao 0 cod_condicao_pagamento 0 dt_emissao 0 peso_bruto 0 peso_liquido 0 vr_total_da_nota 0 vr_mercadoria 0 vr_tributado 0 vr_nao_tributado 0 produto_cod 2 produto_qtd 0 produto_vr_unitario 0 produto_vr_desconto 0 produto_vr_acrescimo 0 produto_vr_total 0 produto_unidade 270 produto_peso_liquido 0 produto_peso_bruto 0 produto_custo 0 dtype: int64 Observa-se que há dados faltantes em duas como o número de linhas faltantes é considerado pequeno diante do nosso dataser, opta-se por retira-las. In [63]: # Removendo as Linhas com valores missing df_notas_saidas.dropna(inplace = True) 11/31</p><p>30/04/2023, 23:11 - Notebook In [64]: filial 0 estado 0 natureza_da_operacao 0 cod_condicao_pagamento 0 dt_emissao 0 peso_bruto 0 peso_liquido 0 vr_total_da_nota 0 vr_mercadoria 0 vr_tributado 0 vr_nao_tributado 0 produto_cod 0 produto_qtd 0 produto_vr_unitario 0 produto_vr_desconto 0 produto_vr_acrescimo 0 produto_vr_total 0 produto_unidade 0 produto_peso_liquido 0 produto_peso_bruto 0 produto_custo 0 dtype: int64 In [65]: # Verificando Valores Únicos df_notas_saidas.nunique( Out filial 5 estado 26 natureza_da_operacao 26 cod_condicao_pagamento 65 dt_emissao 3055 peso_bruto 4471 peso_liquido 4010 vr_total_da_nota 23567 vr_mercadoria 23794 vr_tributado 1967 vr_nao_tributado 23567 14227 produto_qtd 217 produto_vr_unitario 24880 produto_vr_desconto 7118 produto_vr_acrescimo 6 produto_vr_total 32384 produto_unidade 28 produto_peso_liquido 2696 produto_peso_bruto 2958 produto_custo 61995 dtype: int64 para facilitar a análise em período mensal , criamos uma colunas de data mes ano 12/31</p><p>30/04/2023, 23:11 Notebook In [66]: #garanto que as colunas então com type certo = # alterar o dia para sempre ser o primeiro df_notas_saidas['data_mes_ano'] #crio uma coluna mes_ano = 100*x In [67]: #Range min de data Out [67]: array([189912, 201007, 201008, 201009, 201010, 201011, 201012, 201101, 201102, 201103, 201104, 201105, 201106, 201107, 201108, 201109, 201110, 201111, 201112, 201201, 201202, 201203, 201204, 201205, 201206, 201207, 201208, 201209, 201210, 201211, 201212, 201301, 201302, 201303, 201304, 201305, 201306, 201307, 201308, 201309, 201310, 201311, 201312, 201401, 201402, 201403, 201404, 201405, 201406, 201407, 201408, 201409, 201410, 201411, 201412, 201501, 201502, 201503, 201504, 201505, 201506, 201507, 201508, 201509, 201510, 201511, 201512, 201601, 201602, 201603, 201604, 201605, 201606, 201607, 201608, 201609, 201610, 201611, 201612, 201701, 201702, 201703, 201704, 201705, 201706, 201707, 201708, 201709, 201710, 201711, 201712, 201801, 201802, 201803, 201804, 201805, 201806, 201807, 201808, 201809, 201810, 201811, 201812, 201901, 201902, 201903, 201904, 201905, 201906, 201907, 201908, 201909, 201910, 201911, 201912, 202001, 202002, 202003, 202004, 202005, 202006, 202007, 202008, 202009, 202010, 202011, 202012, 202101, 202102, 202103, 202104, 202105, 202106, 202107, 202108, 202109, 202110, 202111, 202112, 202201, 202202, 202203, 202204, 202205, 202206, 202207, 202208, 202209, 202210, 202211, 202212, 202301, 202302, 202303], dtype=int64) Observa-se a incidência de um mês/ano que não faz parte de um periodo correto dos dados, portanto iremos retira-lo 13/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30-Jupyter Notebook In [68]: from datetime import datetime # filtrar os dados com base na data df_notas_saidas = > datetime Out [68]: array([201007, 201008, 201009, 201010, 201011, 201012, 201101, 201102, 201103, 201104, 201105, 201106, 201107, 201108, 201109, 201110, 201111, 201112, 201201, 201202, 201203, 201204, 201205, 201206, 201207, 201208, 201209, 201210, 201211, 201212, 201301, 201302, 201303, 201304, 201305, 201306, 201307, 201308, 201309, 201310, 201311, 201312, 201401, 201402, 201403, 201404, 201405, 201406, 201407, 201408, 201409, 201410, 201411, 201412, 201501, 201502, 201503, 201504, 201505, 201506, 201507, 201508, 201509, 201510, 201511, 201512, 201601, 201602, 201603, 201604, 201605, 201606, 201607, 201608, 201609, 201610, 201611, 201612, 201701, 201702, 201703, 201704, 201705, 201706, 201707, 201708, 201709, 201710, 201711, 201712, 201801, 201802, 201803, 201804, 201805, 201806, 201807, 201808, 201809, 201810, 201811, 201812, 201901, 201902, 201903, 201904, 201905, 201906, 201907, 201908, 201909, 201910, 201911, 201912, 202001, 202002, 202003, 202004, 202005, 202006, 202007, 202008, 202009, 202010, 202011, 202012, 202101, 202102, 202103, 202104, 202105, 202106, 202107, 202108, 202109, 202110, 202111, 202112, 202201, 202202, 202203, 202204, 202205, 202206, 202207, 202208, 202209, 202210, 202211, 202212, 202301, 202302, 202303], dtype=int64) Para o nosso estudo, onde iremos prever a quantidade de produtos vendidos por cada produto separadamente, é impotante saber quais são esses produtos para escolhermos um. Como o dataset tem vários produtos que podem ter sido descontinuados, ou que já não são mais tão solicitados, buscamos os produtos que mais venderam no ano passado (2022) 14/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30- - Jupyter Notebook In [69]: df_notas_filtradas ( # Saber qual produto vendeu mais df_sum =df_notas_filtradas.groupby df_sum 0 G052823Q9 7452.000 1 2RG609273 6342.000 2 G052822Q9 5540.000 3 N0209057 4191.000 4 000142 3459.000 ... ... ... 4665 2V3121405C 1.000 4666 2V3129367 1.000 4667 142@ 0.760 4668 201988 0.500 4669 7325@ 0.006 4670 rows 2 columns Para entendermos um pouco mais sobre a proporção de vendas desses principais produtos em relação ao total de vendas, analisaremos acurva ABC de vendas do ano de 2022. In [70]: df_sum_venda ([ ['produto_cod']) df_sum_venda Out[70]: produto_cod produto_vr_total 0 0522157 4876813.45 1 0512112 3942501.50 2 N0017618 3752000.00 3 0512111 2953714.70 4 N0018460 2311200.00 ... ... ... 4665 88H1015 1.12 4666 15@ 1.12 4667 TE3607077@007 1.00 4668 7325@ 0.42 4669 14@ 0.25 4670 rows 2 columns 15/31</p><p>In [71] : df_vendas = df_sum_venda.copy( df_vendas.inplace=True = df_vendas['valor_acumulado'] df_vendas df_vendas.inplace=True In : def : if percentual_acumulado <= 0.7: return 'A' elif percentual_acumulado <= 0.9: return 'B' else: return 'C' = df_vendas.inplace=True fig plt. bar(df_vendas.head(130) ], df_vendas.head(130) plt.axhline(y=0.7, color='gray', , linestyle='--') acumulado das ABC de vendas de produtos') plt.show() 0.4 0.3 0.2 0.1 produto_cod 3.1.5 Definindo o produto a ser estudado Como objeto de estudo, escolhemos o produto que mais teve vendas no ano de 2022 16/31</p><p>30/04/2023, 23:11 - Jupyter Notebook In : df_notas = ( 'G05282 df_notas Out [73]: filial estado natureza_da_operacao cod_condicao_pagamento dt_emissao peso_bru VENDAS DE 182971 3 CE 49 2022-09-01 MERCADORIA VENDA MERC. 182982 3 CE 3 2022-09-14 SUBST.TRIBUTARIA VENDA MERC. 183630 3 CE 90 2022-09-16 SUBST.TRIBUTARIA VENDA MERC. 183794 3 CE 3 2022-09-20 SUBST.TRIBUTARIA VENDA MERC. 188461 3 CE 90 2022-09-28 ( SUBST.TRIBUTARIA ... VENDAMERC. 1482585 3 CE 22 2023-01-31 ( SUBST.TRIBUTARIA Como o primeiro lugar tem um range de vendas de soomente um ano, ele não será um bom objeto de estudo, passaremos então para o segundo colocado In [74] : df_notas1 Out [74] : filial estado natureza_da_operacao cod_condicao_pagamento dt_emissao peso_bru VENDAS DE 8242 1 CE 99 2018-08-31 MERCADORIA VENDA MERC. 60510 3 CE 3 2019-10-18 SUBST.TRIBUTARIA VENDAS DE 78368 1 CE 3 2017-11-28 MERCADORIA VENDA MERC. 87249 3 CE 62 2017-07-12 SUBST.TRIBUTARIA VENDA MERC. SUBST. 109993 1 CE 6 2018-02-20 ( TRIBUTAR/VENDA M ... VENDAS DE 1469235 1 CE 6 2022-05-12 ( MERCADORIA Para iniciarmos nosso estudo, utilizaremos somente os dados da quantidade dos produtos e o valor de venda deles como informações para previsão de quantidade de vendas futuras.Assim, iremos retirar os outros dados. 17/31</p><p>30/04/2023, 23:11 - Jupyter Notebook In [75]: #dropando colunas desnecessárias Setting WithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: (https://panda sus-a-copy) In [76]: df_notas1 Out [76]: dt_emissao produto_qtd produto_vr_total 8242 2018-08-31 120.0 33.60 2018-08-01 60510 2019-10-18 212.0 86.92 2019-10-01 78368 2017-11-28 100.0 23.00 2017-11-01 87249 2017-07-12 336.0 117.60 2017-07-01 109993 2018-02-20 96.0 33.60 2018-02-01 1469235 2022-05-12 120.0 58.80 2022-05-01 1469243 2022-09-20 230.0 2022-09-01 1469249 2022-12-01 325.0 214.50 2022-12-01 1469252 2022-12-09 133.0 87.78 2022-12-01 1486815 2023-02-07 250.0 165.00 2023-02-01 173 rows columns In [77]: df_notas1.info() <class Int64Index: 173 entries, 8242 to 1486815 Data columns (total 4 columns) : # Column Non-Null Count Dtype 0 dt_emissao 173 non-null datetime64[ns] 1 produto_qtd 173 non-null float64 2 produto_vr_total 173 non-null float64 3 data_mes_ano 173 non-null datetime64[ns] dtypes: datetime64[ns](2), float64(2) memory usage: 6.8 KB 18/31</p><p>30/04/2023, 23:11 Notebook In [78]: #ordenando os dados por data de emissão , ascending=True) df_notas1 Out [78]: dt_emissao produto_vr_total data_mes_ano 426708 2010-08-11 70.0 11.90 2010-08-01 743638 2010-08-30 112.0 19.04 2010-08-01 427220 2010-09-01 112.0 19.04 2010-09-01 427238 2010-09-14 130.0 22.10 2010-09-01 427241 2010-09-17 240.0 40.80 2010-09-01 ... ... ... ... ... 1296887 2023-02-28 64.0 42.24 2023-02-01 1329027 2023-03-02 224.0 147.84 2023-03-01 906270 2023-03-02 112.0 73.92 2023-03-01 1329072 2023-03-06 96.0 76.80 2023-03-01 1357589 2023-03-07 73.92 2023-03-01 173 rows 4 columns 19/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30- Notebook In [79]: = for sbplt, y in enumerate(years): data = valor = == y]['produto_vr_total quantidade = == plt. subplot(len(years), 1, sbplt+1) plt.plot(data,valor, 'k-') plt.gca().twinx().plot(data, quantidade, '--y') if sbplt > 9: break plt.show() 20/31</p><p>30/04/2023, 23:11 - Jupyter Notebook 40 200 30 150 20 100 2010-08-15 2010-09-01 2010-09-15 2010-10-01 2010-10-15 2010-11-01 2010-11-15 2010-12-01 2010-12-15 80 400 60 40 200 20 2011-02 2011-03 2011-04 2011-05 2011-06 2011-07 40 - 200 30 150 2012-03-01 2012-03-15 2012-04-01 2012-04-15 2012-05-01 2012-05-15 2012-06-01 2012-06-15 1050 520 1000 500 - 950 2013-08-29 2013-09-01 2013-09-05 2013-09-09 2013-09-13 2013-09-17 2013-09-21 2013-09-25 1000 200 100 500 2017-07 2017-08 2017-09 2017-10 2017-11 2017-12 60 200 40 100 2018-02 2018-03 2018-04 2018-05 2018-06 2018-07 2018-08 2018-09 2018-10 2018-11 100 - 300 200 50 100 2019-01 2019-03 2019-05 2019-07 2019-09 2019-11 2020-01 300 100 80 200 60 40 100 2020-01 2020-03 2020-05 2020-07 2020-09 2020-11 2021-01 100 200 80 150 60 40 100 2021-01 2021-03 2021-05 2021-07 2021-09 2021-11 2022-01 300 400 200 200 100 - 0 - 2022-01 2022-03 2022-05 2022-07 2022-09 2022-11 2023-01 150 200 100 100 50 2023-01-01 2023-01-08 2023-01-15 2023-01-22 2023-02-01 2023-02-08 2023-02-15 2023-02-22 2023-03-01 2023-03-08 Observando os dados, aparentemente os dados não apresentam sazonalidade, nem tendência. 21/31</p><p>30/04/2023, 23:11 - Jupyter Notebook Como os produtos não apresentam vendas diariamente de forma assídua, preferi trata-los de forma mensal.Assim nossa previsão será de vendas mensais do produto In [80]: #Dropando data de emissão e deixando somente a data como mês e ano. In [81]: df Out [81]: produto_qtd produto_vr_total data_mes_ano 426708 70.0 11.90 2010-08-01 743638 112.0 19.04 2010-08-01 427220 112.0 19.04 2010-09-01 427238 130.0 22.10 2010-09-01 427241 240.0 40.80 2010-09-01 1296887 64.0 42.24 2023-02-01 1329027 224.0 147.84 2023-03-01 906270 112.0 73.92 2023-03-01 1329072 96.0 76.80 2023-03-01 1357589 112.0 73.92 2023-03-01 173 rows 3 columns In [82]: # Sumarizar as vendas por mês df_sum =df.groupby FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. In [83]: #Ordenando o dataset por data - In [84]: #definindo a data como index. = True) 22/31</p><p>30/04/2023, 23:11 - Notebook In df_sum Out [85]: produto_qtd produto_vr_total data_mes_ano 2010-08-01 182.0 30.94 2010-09-01 482.0 81.94 2010-10-01 112.0 19.04 2010-11-01 224.0 38.08 2010-12-01 255.0 43.35 ... ... ... 2022-11-01 226.0 131.08 2022-12-01 814.0 552.92 2023-01-01 544.0 372.48 2023-02-01 974.0 644.04 Esse vai ser o nosso dataset final de estudo. A partir dele iremos criar novas previsões. In [86]: df_sum.describe() Out [86]: produto_qtd produto_vr_total count 76.000000 76.000000 mean 419.065789 166.716974 std 407.839751 196.699602 min 96.000000 19.040000 25% 170.250000 45.037500 50% 255.500000 102.385000 75% 533.500000 204.520000 max 2000.000000 1020.000000 Aparentemente não tem valores estranhos (negativos, por exemplo) In df_sum.index[-1] Out [87]: Timestamp('2023-03-01 00:00:00' ) 23/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30- - Jupyter Notebook In [88]: sns.set() 2000 1750 1500 1250 1000 750 500 250 In [89]: sns.set() 1000 800 600 400 200 0 Existe alguns outliers, então vaos verificar-los 24/31</p><p>30/04/2023, 23:11 Jupyter Notebook In [90]: filtro = df sum['produto_qtd ] > 1000 - df_filtrado = df_sum[filtro] df_filtrado Out [90] : produto_qtd produto_vr_total data_mes_ano 2011-05-01 1300.0 276.00 2011-07-01 1690.0 287.30 2013-09-01 2000.0 1020.00 2013-10-01 2000.0 1020.00 2017-06-01 1144.0 263.12 2020-08-01 1228.0 495.04 Os dados aparentam representar uma observação real e significativa, é importante mantê-lo nos dados. In [91] : produtos ao longo dos meses') 1500 A 1000 1.11 Para comprovar a não estacionariedade ou a estacionariedade das séries faremos o teste de hipótese de Dickey-Fuller Aumentado 25/31</p><p>30/04/2023, 23:11 In [92]: # Teste de Dickey Fuller result = adfuller print Statistic: % result[0]) %f' % result[1]) print('Critical Values : ') for key, value in result : % (key, value) ) if else: print é Estacionário ') ADF Statistic: -4.367047 p-value: : 0.000339 Critical Values : 1%: -3.522 5%: -2.901 10%: -2.588 É Estacionário! Olhando para o valor temos a comprovação matemática de que a série é estacionaria. 26/31</p><p>30/04/2023, 23:11 Trabalho_sabrina_rodrigues_tcc_2023_04_30 - Jupyter Notebook In [93] : #Fazendo a decomposição da série array = = fig = results.plot() fig.set_size_inches(13, 10) Observed 2000 1000 0 10 20 30 40 50 60 70 750 500 250 0 10 20 30 40 50 60 70 200 0 -200 0 10 20 30 40 50 60 70 1000 0 0 10 20 30 40 50 60 70 Podemos observar os resíduos ficaram bem dispersos, mas como o objetivo é apenas modelar a série temporal para fins de previsão, a grande dispersão dos resíduos pode não ser um problema desde que o modelo preveja com precisão as observações futuras. Vamos fazer os gráficos de média móvel de cada coluna do dataset e observar como está a distribuição anual da série e de cada produto 27/31</p><p>30/04/2023, 23:11 - Jupyter Notebook In [94] = () # plotar o gráfico plt.plot(df_sum.index, label='Valores') plt.plot(df_sum.index, df_sum['MediaMovel'], label='Média Móvel') plt.legend( plt.show() 2000 Valores Média Móvel 1750 1500 1250 1000 750 500 250 2010 2012 2014 2016 2018 2020 2022 4 Aplicação do modelo 4.1 Separando a base em treino (80%) e teste (20%) In [95]: # dividindo o conjunto de dados em treinamento e teste train_size = int * 0.8) train_data, test_data = df_sum.iloc[:train_size], df_sum.iloc[train_size: ] # verificando a forma dos conjuntos de treinamento e teste print de treinamento: train_data.shape) print de , test_data.shape) Dados de treinamento: (60, 3) Dados de teste: (16, 3) 4.2 Descobrir a ordem do nosso modelo e qual é o melhor tipo a ser usado Para descobrir a ordem do nosso modelo e qual é o melhor tipo a ser usado (AR,MA,ARMA,ARIMA,SARIMA) vamos fazer um processo interativo para descobrir os coeficientes 28/31</p><p>30/04/2023, 23:11 Notebook In [96]: # ajustando o modelo ARIMAX com Auto-ARIMA model = Performing stepwise search to minimize aic ARIMA(2,0,2) (0,0,0) : AIC=inf, Time=0.08 sec ARIMA(0,0,0) (0,0,0) [0] : AIC=940.654, Time=0.01 sec ARIMA(1,0,0) (0,0,0) [0] : AIC=899.358, Time=0.01 sec ARIMA(0,0,1) (0,0,0) [0] : AIC=918.089, Time=0.02 sec ARIMA(2,0,0) (0,0,0) [0] : AIC=900.361, Time=0.01 sec ARIMA(1,0,1) (0,0,0) [0] : AIC=900.523, Time=0.03 sec ARIMA(2,0,1) (0,0,0) [0] : AIC=901.539, Time=0.05 sec ARIMA(1,0,0) (0,0,0) [0] intercept : AIC=891.235, Time=0.01 sec ARIMA(0,0,0) (0,0,0) [0] intercept : AIC=903.094, Time=0.01 sec intercept : AIC=893.216, Time=0.02 sec [0] intercept : AIC=893.245, Time=0.03 sec [0] intercept : AIC=894.392, Time=0.03 sec intercept : AIC=894.943, Time=0.03 sec Best model: intercept Total fit time: 0.338 seconds In [97]: # imprimindo a informação do modelo Model: SARIMAX(1, 0, 0) Log Likelihood -442. 617 Date: Sun, 30 Apr 2023 AIC 891. 235 Time: 23:09:40 BIC 897. 518 Sample: 0 HQIC 893. 692 - 60 Covariance Type: opg === coef std err Z P> Z [0.025 0.9 75] intercept 228.9024 107.013 2.139 0.032 19.162 438. 643 ar.L1 0.4491 0.090 4.970 0.000 0.272 0. 29/31</p><p>30/04/2023, 23:11 - Jupyter Notebook 4.3 Fazendo previsões com o modelo para conjunto de teste In # fazendo previsões com o modelo para o conjunto de teste predictions = exogenous=test_data[['pr # calculando o RMSE para avaliar a precisão das previsões rmse = predictions)) print ('RMSE ', , rmse) RMSE: 257.4561617639131 834: ValueWarning: No supported index is available. Prediction results will be given with an int egen index beginning at In : plt.figure(figsize=(12,6)) plt.plot(df_sum.index, label='Histórico de plt.plot(test_data.index, predictions, plt.legend(loc='upper left') plt.show() Vendas diárias 2000 Histórico de vendas Previsões 1750 1500 1250 1000 750 500 250 2010 2012 2014 2016 2018 2020 2022 Data Pelo gráfico acima, vemos que o modelo falhou totalmente em prever o comportamento da série 30/31</p><p>30/04/2023, 23:11 rabalho_sabrina_rodrigues_tcc_2023_04_30 Jupyter Notebook In [100]: # ajustando o modelo para todo conjunto de dados model_final = model_final_fit = model_final.fit() # fazendo previsões 7 meses future_data = future_predictions = exog=fut # imprimindo as previsões t(future_predictions) 76 392.742330 77 283.541429 78 204.703532 79 147.786291 80 106.694728 81 77.028559 82 55.610985 Name: predicted_mean dtype: float64 471: ValueWarning: A date index has been provided, but it has no associated frequency informatio n and so will be ignored when e.g. forecasting. 471: ValueWarning: A date index has been provided, but it has no associated frequency informatio n and so will be ignored when e.g. forecasting. 834: ValueWarning: No supported index is available. Prediction results will be given with an int index beginning at 5 Conclusões parciais In 31/31</p>