Dans ce blog, nous utiliserons l'apprentissage en profondeur pour prédire les ventes de collations personnelles par les mères. Ma mère, qui est gestionnaire, est toujours troublée par les décisions concernant les dépenses telles que «la gestion des stocks, le nombre d'employés, les investissements en capital, l'expansion des affaires». .. .. Par conséquent, j'ai pensé que si je pouvais faire des prévisions de ventes très précises, je serais en mesure de réduire autant que possible cette difficulté. Cela fait un mois que j'ai commencé à étudier l'apprentissage automatique, et je viens de me souvenir que je voulais créer un modèle avec des données réelles. Je suis un peu inquiet si je peux le faire, mais ** j'aimerais relever le défi tout en revoyant le passé! !! !! ** De plus, j'espère que ce sera un article de référence pour ceux qui étudient l'apprentissage automatique à partir de maintenant.
Il existe de nombreux types d'algorithmes d'apprentissage automatique, mais le processus de création de modèle sous-jacent était le même pour tous. Le flux simple de l'apprentissage automatique est le suivant. Dans ce blog également, nous allons construire un modèle tout en gardant ce flux à l'esprit.
** 1. Collecte de données 2. Prétraitement des données (supprimer les doublons et les données manquantes pour améliorer l'exactitude des données) 3. Apprenez les données à l'aide de techniques d'apprentissage automatique 4. Test des performances avec les données de test **
Ce «modèle de construction de prévisions de ventes de collations» correspond à l'analyse des données de séries chronologiques. Les données chronologiques font référence aux données qui changent avec le temps. L'analyse des données de séries chronologiques peut également être appliquée à la prévision des ventes de l'entreprise et des ventes de produits, elle est donc considérée comme une technologie d'analyse très importante sur la scène commerciale. Dans ce blog, nous envisagerons d'utiliser les algorithmes ** RNN (Recurrent Neural Network) ** et ** LSTM (Long-short-term-memory) ** qui appliquent la méthode d'apprentissage en profondeur. RNN(Recurrent Neural Network) RNN est l'un des algorithmes d'apprentissage automatique qui analysent les données de séries chronologiques par apprentissage en profondeur. Dans la couche intermédiaire, RNN est caractérisé par la mise en boucle automatique des données au point de temps précédent comme entrée actuelle. Cela permet aux RNN de communiquer des informations tout en préservant le contexte des données dans la couche intermédiaire. Et cette propriété a permis de ** former des données avec la notion de temps **. (Extrait de https://qiita.com/KojiOhki/items/89cd7b69a8a6239d67ca)
RNN a permis d'analyser des données de séries chronologiques grâce à l'apprentissage en profondeur, mais les performances ne sont pas si élevées. La cause est que la fonction d'activation est multipliée plusieurs fois par la structure en boucle de RNN. Au fil du temps, la fonction d'activation itérative est multipliée, ce qui entraîne une ** disparition du gradient ** ou une ** explosion du gradient ** où la valeur du gradient converge et la quantité de calcul augmente de façon exponentielle. En conséquence, un traitement adéquat des données devient difficile. Aussi, pour ces raisons, nous pouvons voir que RNN n'est pas adapté à la formation de données chronologiques à long terme. Le modèle d'apprentissage en profondeur qui résout cet inconvénient est LSTM (Long-short-term-momory), qui sera présenté ensuite.
LSTM(Long-short-term-memory) Dans le modèle LSTM, en remplaçant les cellules de la couche intermédiaire par des blocs LSTM, l'inconvénient de RNN de "ne pas apprendre tout en conservant la mémoire à long terme" est surmonté. La configuration de base du bloc LETM est la suivante.
・ CEC: une unité qui stocke les données passées -Porte d'entrée: Une porte qui ajuste le poids d'entrée de l'unité précédente -Porte de sortie: Une porte qui ajuste le poids de sortie de l'unité précédente ・ Porte Oblivion: Une porte qui ajuste la quantité de contenu du CEC contenant des informations passées.
(Extrait de https://sagantaf.hatenablog.com/entry/2019/06/04/225239)
Dans LSTM, la fonction de porte mentionnée ci-dessus vous permet de supprimer ou d'ajouter des informations en fonction de l'état de la cellule. En ajustant les poids d'entrée / sortie et en ajustant les données dans la cellule, les problèmes de disparition de gradient et d'explosion de gradient, qui étaient les inconvénients du RNN, ont été résolus. Par conséquent, il peut être appliqué à l'analyse de données de séries chronologiques à long terme.
L'explication ci-dessus est l'histoire théorique de RNN et LSTM. Il existe un total de 82 données sur les ventes de cette collation pendant 7 ans. Étant donné que la longueur correspond à des données à moyen et long terme, je voudrais faire des prédictions en utilisant les modèles RNN et LSTM et adopter un modèle avec de bons résultats. Construisons maintenant le modèle.
OS: Windows10
environnement python: Jupyter Notebook
Forecast-
|-Forecast.py(fichier python)
|-sales_data-
|-Divers fichiers CSV
Le flux de construction du modèle est le flux suivant introduit précédemment. ** 1. Collecte de données 2. Prétraitement des données (supprimer les doublons et les données manquantes pour améliorer l'exactitude des données) 3. Apprenez les données à l'aide de techniques d'apprentissage automatique 4. Test des performances avec les données de test **
Tout d'abord, importez les modules requis. Écrivez le code suivant dans l'environnement d'exécution.
Forecast.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import SimpleRNN
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
Le premier est la collecte de données. Après une demande désespérée, j'ai obtenu des données sur les ventes de collations gérées par ma mère. Le format des données Excel 2013-2019 qui résume les ventes mensuelles est ajusté et sorti au format CSV.
Record mensuel de ventes de collations de 2013 à 2019.
sales
Nombre de données 8.400000e+01
Moyenne 7.692972e+05
Écart type 1.001658e+05
Valeur minimale 5.382170e+05
1/4 minutes 7.006952e+05
Valeur médiane 7.594070e+05
3/4 minutes 8.311492e+05
Valeur maximale 1.035008e+06
Il semble que les ventes ont tendance à augmenter au fil des années.
2019 :801197 yens
2018 :822819 yens
2017 :732294 yens
2016 :755799 yens
2015 :771255 yens
2014 :761587 yens
2013 :740128 yens
Les ventes les plus élevées ont été enregistrées en décembre, puis en avril. Il semble que cela soit fortement lié au fait que de nombreuses buvettes à la fin de l'année et des beuveries au début de l'année sont organisées. J'espère pouvoir prédire ces tendances.
janvier:758305 yens
février:701562 yens
Mars:750777 yens
avril:805094 yens
Mai:785633 yens
juin:778146 yens
juillet:752226 yens
août:763773 yens
septembre:689561 yens
octobre:765723 yens
novembre:779661 yens
décembre:901100 yens
Cela signifie une tendance à long terme des données. Dans ce thème, nous montrerons si les ventes de collations augmentent ou diminuent à long terme.
Pour les données avec des fluctuations périodiques, la valeur des données se répète en hausse et en baisse avec le temps. En particulier, les fluctuations périodiques sur une année sont appelées fluctuations saisonnières. Concernant ce thème, nous avons constaté que les ventes moyennes en décembre et avril, lorsqu'il y a beaucoup de buveurs, sont élevées. Il y a peut-être des fluctuations périodiques saisonnières.
trend_seasonal.py
#Prise en compte des tendances des ventes et de la saisonnalité tout au long de l'année
fig = sm.tsa.seasonal_decompose(df_sales_concat, freq=12).plot()
plt.show()
Comme prévu, il y a eu une tendance à la hausse des ventes. Il y avait aussi une fluctuation périodique des ventes en hausse en avril et en décembre. Ce serait bien si nous pouvions prédire de tels contenus avec un modèle d'apprentissage automatique.
L'autodistribution des séries chronologiques fait référence à *** la co-distribution des mêmes données chronologiques entre différents moments ***. L'auto-co-distribution d'ordre k se réfère à la co-distribution avec des données séparées par k points. La vue de cette auto-covariance en fonction de *** k est appelée fonction d'autocorrélation ***. La représentation graphique *** de cette fonction est appelée le cholérogramme ***.
corr.py
#Calcul du cholérogramme du coefficient d'autocorrélation
df_sales_concat_acf = sm.tsa.stattools.acf(df_sales_concat, nlags=12)
print(df_sales_concat_acf)
sm.graphics.tsa.plot_acf(df_sales_concat, lags=12)
fig = sm.graphics.tsa.plot_acf(df_sales_concat, lags=12)
À partir du cholérogramme, nous pouvons voir que le coefficient d'autocorrélation augmente lorsque k = 12. Comme ce sont les données qui enregistrent les ventes mensuelles, vous pouvez voir qu'il existe une corrélation entre certaines données et les données d'il y a un an.
Les données réellement utilisées sont publiées dans le lien Google Sheets ci-dessous. https://docs.google.com/spreadsheets/d/1-eOPORhaGfSCdXCScSsBsM586yXkt3e_xbOlG2K6zN8/edit?usp=sharing
Forecast.py
#Lisez le fichier CSV au format DataFrame.
df_2019 = pd.read_csv('./sales_data/2019_sales.csv')
df_2018 = pd.read_csv('./sales_data/2018_sales.csv')
df_2017 = pd.read_csv('./sales_data/2017_sales.csv')
df_2016 = pd.read_csv('./sales_data/2016_sales.csv')
df_2015 = pd.read_csv('./sales_data/2015_sales.csv')
df_2014 = pd.read_csv('./sales_data/2014_sales.csv')
df_2013 = pd.read_csv('./sales_data/2013_sales.csv')
#Combinez les DataFrames chargés en un seul DataFrame.
df_sales_concat = pd.concat([df_2013, df_2014, df_2015,df_2016,df_2017,df_2018,df_2019], axis=0)
#Créez un index pour le FrameData que vous souhaitez utiliser.
index = pd.date_range("2013-01", "2019-12-31", freq='M')
df_sales_concat.index = index
#Supprimez les colonnes DataFrame inutiles.
del df_sales_concat['month']
#Stockez uniquement les données de ventes réelles utilisées dans la création du modèle dans la variable du jeu de données.
dataset = df_sales_concat.values
dataset = dataset.astype('float32')
Vient ensuite le prétraitement des données. Plus précisément, nous créerons un jeu de données à utiliser pour la construction du modèle.
Forecast.py
#Divisez en données d'entraînement et en données de test. Le ratio est de 2:1=entraînement:C'est un test.
train_size = int(len(dataset) * 0.67)
train, test = dataset[0:train_size, :], dataset[train_size:len(dataset), :]
#Mise à l'échelle des données.
#Je crée une instance pour la normalisation des données basée sur les données de formation.
scaler = MinMaxScaler(feature_range=(0, 1))
scaler_train = scaler.fit(train)
train_scale = scaler_train.transform(train)
test_scale = scaler_train.transform(test)
#Créer un jeu de données
look_back =1
train_X, train_Y = create_dataset(train_scale, look_back)
test_X, test_Y = create_dataset(test_scale, look_back)
#Création d'un jeu de données original pour l'évaluation
train_X_original, train_Y_original = create_dataset(train, look_back)
test_X_original, test_Y_original = create_dataset(test, look_back)
#Mise en forme des données
train_X = train_X.reshape(train_X.shape[0], train_X.shape[1], 1)
test_X = test_X.reshape(test_X.shape[0], test_X.shape[1], 1)
Forecast.py
lstm_model = Sequential()
lstm_model.add(LSTM(64, return_sequences=True, input_shape=(look_back, 1)))
lstm_model.add(LSTM(32))
lstm_model.add(Dense(1))
lstm_model.compile(loss='mean_squared_error', optimizer='adam')
###Apprentissage
lstm_model.fit(train_X, train_Y, epochs=100, batch_size=64, verbose=2)
Forecast.py
rnn_model = Sequential()
rnn_model.add(SimpleRNN(64, return_sequences=True, input_shape=(look_back, 1)))
rnn_model.add(SimpleRNN(32))
rnn_model.add(Dense(1))
rnn_model.compile(loss='mean_squared_error', optimizer='adam')
###Apprentissage
rnn_model.fit(train_X, train_Y, epochs=100, batch_size=64, verbose=2)
Cela complète l'apprentissage automatique avec LSTM et RNN à partir de l'ensemble de données. Les opérations de base sont les mêmes pour les deux, seules les classes utilisées sont différentes. Vient ensuite le processus de représentation graphique des résultats sur un graphique. Désormais, le modèle est affiché en tant que modèle, mais il fait référence à la fois à lstm_model et à rnn_model.
Forecast.py
#Créer des données de prévision
train_predict = model.predict(train_X)
test_predict = model.predict(test_X)
#Rétablissez les données mises à l'échelle. Convertit la valeur standardisée en valeur réelle prévue.
train_predict = scaler_train.inverse_transform(train_predict)
train_Y = scaler_train.inverse_transform([train_Y])
test_predict = scaler_train.inverse_transform(test_predict)
test_Y = scaler_train.inverse_transform([test_Y])
#Calcul de la précision des prévisions
train_score = math.sqrt(mean_squared_error(train_Y_original, train_predict[:, 0]))
print(train_score)
print('Train Score: %.2f RMSE' % (train_score))
test_score = math.sqrt(mean_squared_error(test_Y_original, test_predict[:, 0]))
print('Test Score: %.2f RMSE' % (test_score))
#Mise en forme des données pour les graphiques
train_predict_plot = np.empty_like(dataset)
train_predict_plot[:, :] = np.nan
train_predict_plot[look_back:len(train_predict)+look_back, :] = train_predict
train_predict_plot = pd.DataFrame({'sales':list(train_predict_plot.reshape(train_predict_plot.shape[0],))})
train_predict_plot.index = index
test_predict_plot = np.empty_like(dataset)
test_predict_plot[:, :] = np.nan
test_predict_plot[len(train_predict)+(look_back*2):len(dataset), :] = test_predict
test_predict_plot = pd.DataFrame({'sales':list(test_predict_plot.reshape(test_predict_plot.shape[0],))})
test_predict_plot.index = index
Ensuite, nous tracerons les données réelles sur le graphique.
Forecast.py
#Sortie des méta-informations du graphique
plt.title("monthly-sales")
plt.xlabel("time(month)")
plt.ylabel("sales")
#Tracer les données
plt.plot(dataset, label='sales_dataset', c='green')
plt.plot(train_predict_plot, label='train_data', c='red')
plt.plot(test_predict_plot, label='test_data', c='blue')
#Ajuster l'échelle de l'axe y
plt.yticks([500000, 600000, 700000, 800000, 900000, 1000000, 1100000])
#Tracer le graphique
plt.legend()
plt.show()
Les graphiques de sortie RNN et LSTM en conséquence sont affichés respectivement.
La valeur de la sortie est complètement perdue. .. .. J'ai beaucoup changé les paramètres, mais les résultats n'ont pas beaucoup changé. On peut voir que la méthode avec RNN ne convient pas même pour la durée de 84 données cette fois.
Par rapport aux prévisions RNN, nous pouvons en quelque sorte prédire la tendance des ventes. En particulier, nous avons pu contrôler la tendance à la hausse des ventes en avril et en décembre. Cependant, dans l'ensemble, de nombreux points diffèrent considérablement des valeurs mesurées. *** RMSE ***, qui est la norme de qualité du modèle, est également *** Note du train: 94750,73 RMSE, Note du test: 115472,92 RMSE ***, qui sont des valeurs assez grandes. Il semble que le résultat ne soit pas si bon.
Il a été constaté que LSTM peut réaliser une analyse détaillée des séries chronologiques, même pour les ensembles de données qui provoquent la disparition du gradient dans RNN. Cependant, la prévision de LSTM ne montre que la tendance des ventes, et de nombreuses valeurs s'écartent considérablement des valeurs réelles. Cela ne peut pas être considéré comme une prévision de ventes très précise et ne peut pas être une prévision de données de revenu qui peut être une décision de la direction.
Pour RNN et LSTM, j'ai essayé différents modèles de paramètres loop_back, epochs, batch_size, mais les performances ne se sont pas améliorées en particulier. On peut supposer que la cause est ** une petite quantité de données et une variation. ** Quand j'ai enquêté plus tard, il semble que le nombre de données 84 dans l'analyse des séries chronologiques soit assez petit. J'ai réalisé que ** les données sont la vie ** dans la construction d'un modèle d'apprentissage automatique.
Cependant, de toute façon, je pense que c'était un bon matériel pédagogique pour l'examen d'un mois de l'apprentissage automatique et des débutants. Désormais, je vais continuer à me consacrer pour améliorer mon niveau d'ingénieur en machine learning! *** ***
Forecast.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import SimpleRNN
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
#Créer un jeu de données
def create_dataset(dataset, look_back):
data_X, data_Y = [], []
for i in range(look_back, len(dataset)):
data_X.append(dataset[i-look_back:i, 0])
data_Y.append(dataset[i, 0])
return np.array(data_X), np.array(data_Y)
df_2019 = pd.read_csv('./sales_data/2019_sales.csv')
df_2018 = pd.read_csv('./sales_data/2018_sales.csv')
df_2017 = pd.read_csv('./sales_data/2017_sales.csv')
df_2016 = pd.read_csv('./sales_data/2016_sales.csv')
df_2015 = pd.read_csv('./sales_data/2015_sales.csv')
df_2014 = pd.read_csv('./sales_data/2014_sales.csv')
df_2013 = pd.read_csv('./sales_data/2013_sales.csv')
df_sales_concat = pd.concat([df_2013, df_2014, df_2015,df_2016,df_2017,df_2018,df_2019], axis=0)
index = pd.date_range("2013-01", "2019-12-31", freq='M')
df_sales_concat.index = index
del df_sales_concat['month']
dataset = df_sales_concat.values
dataset = dataset.astype('float32')
#Divisez en données d'entraînement et données de test
train_size = int(len(dataset) * 0.67)
train, test = dataset[0:train_size, :], dataset[train_size:len(dataset), :]
#Mise à l'échelle des données
scaler = MinMaxScaler(feature_range=(0, 1))
scaler_train = scaler.fit(train)
train_scale = scaler_train.transform(train)
test_scale = scaler_train.transform(test)
#Créer des données
look_back =1
train_X, train_Y = create_dataset(train_scale, look_back)
test_X, test_Y = create_dataset(test_scale, look_back)
#Créer un jeu de données pour l'évaluation
train_X_original, train_Y_original = create_dataset(train, look_back)
test_X_original, test_Y_original = create_dataset(test, look_back)
#Mise en forme des données
train_X = train_X.reshape(train_X.shape[0], train_X.shape[1], 1)
test_X = test_X.reshape(test_X.shape[0], test_X.shape[1], 1)
#Création et formation de modèles LSTM
model = Sequential()
model.add(LSTM(64, return_sequences=True, input_shape=(look_back, 1)))
model.add(LSTM(32))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(train_X, train_Y, epochs=100, batch_size=64, verbose=2)
#Créer des données de prévision
train_predict = model.predict(train_X)
test_predict = model.predict(test_X)
#Rétablissez les données mises à l'échelle.
train_predict = scaler_train.inverse_transform(train_predict)
train_Y = scaler_train.inverse_transform([train_Y])
test_predict = scaler_train.inverse_transform(test_predict)
test_Y = scaler_train.inverse_transform([test_Y])
#Calcul de la précision des prévisions
train_score = math.sqrt(mean_squared_error(train_Y_original, train_predict[:, 0]))
print(train_score)
print('Train Score: %.2f RMSE' % (train_score))
test_score = math.sqrt(mean_squared_error(test_Y_original, test_predict[:, 0]))
print('Test Score: %.2f RMSE' % (test_score))
#Mise en forme des données pour les graphiques
train_predict_plot = np.empty_like(dataset)
train_predict_plot[:, :] = np.nan
train_predict_plot[look_back:len(train_predict)+look_back, :] = train_predict
train_predict_plot = pd.DataFrame({'sales':list(train_predict_plot.reshape(train_predict_plot.shape[0],))})
train_predict_plot.index = index
test_predict_plot = np.empty_like(dataset)
test_predict_plot[:, :] = np.nan
test_predict_plot[len(train_predict)+(look_back*2):len(dataset), :] = test_predict
test_predict_plot = pd.DataFrame({'sales':list(test_predict_plot.reshape(test_predict_plot.shape[0],))})
test_predict_plot.index = index
#Graphique de données
plt.title("monthly-sales")
plt.xlabel("time(month)")
plt.ylabel("sales")
plt.plot(dataset, label='sales_dataset', c='green')
plt.plot(train_predict_plot, label='train_data', c='red')
plt.plot(test_predict_plot, label='test_data', c='blue')
plt.yticks([500000, 600000, 700000, 800000, 900000, 1000000, 1100000])
plt.legend()
plt.show()