[PYTHON] J'ai essayé de prédire l'évolution de la quantité de neige pendant 2 ans par apprentissage automatique

Cette entrée est une suite du précédent écrit J'ai essayé de prédire la présence ou l'absence de neige par apprentissage automatique. Pour le moment, je ne prévoyais que la présence ou l'absence de neige (1 ou 0), mais j'essayais un peu plus de prédire l'évolution de la quantité de neige.

Quand j'ai écrit le résultat en premier, ça ressemblait à ça. L'axe horizontal représente le nombre de jours et l'axe vertical la quantité de neige (cm).

Résultat 1 (le bleu est la quantité réelle de neige, la ligne rouge est la quantité de neige prévue) スクリーンショット 2016-05-01 17.45.39.png

Résultat 2 (le bleu est la quantité réelle de neige, la ligne rouge est la quantité de neige prévue) スクリーンショット 2016-05-01 17.59.35.png

Veuillez lire ce qui suit pour savoir ce que sont respectivement "Résultat 1" et "Résultat 2".

Ce que je voulais faire

Auparavant, j'essayais de prédire la présence ou l'absence de chutes de neige en utilisant «scikit-learn» dans J'ai essayé de prédire la présence ou l'absence de chutes de neige par apprentissage automatique. Cependant, je suis devenu un peu gourmand et je voulais prédire la quantité réelle de neige (cm) pour une certaine période, pas la présence ou l'absence.

Plus précisément, nous allons acquérir des données météorologiques telles que la température de la vitesse du vent des chutes de neige fournies par l'Agence météorologique, et utiliser les données pour les 7500 premiers jours d'apprentissage et les 2 années restantes (365x2 = Prédire les changements de neige (730 jours) et comparer avec les changements réels de neige.

Collecter des données d'entraînement

Les données de formation seront obtenues auprès de celle publiée par l'Agence météorologique. Plus précisément, veuillez vous référer au document précédemment écrit J'ai essayé de prédire la présence ou l'absence de neige par apprentissage automatique.

Les données CSV obtenues ressemblent à ceci. La cible était la ville de Sakai à Toyama, qui a beaucoup de neige.

data_2013_2015.csv


Temps de téléchargement: 2016/03/20 20:31:19

,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai,Sakai
Date et l'heure,Température(℃),Température(℃),Température(℃),La couverture de neige(cm),La couverture de neige(cm),La couverture de neige(cm),vitesse du vent(m/s),vitesse du vent(m/s),vitesse du vent(m/s),vitesse du vent(m/s),vitesse du vent(m/s),Précipitation(mm),Précipitation(mm),Précipitation(mm)
,,,,,,,,,Direction du vent,Direction du vent,,,,
,,information de qualité,Nombre homogène,,information de qualité,Nombre homogène,,information de qualité,,information de qualité,Nombre homogène,,information de qualité,Nombre homogène
2013/2/1 1:00:00,-3.3,8,1,3,8,1,0.4,8,Ouest,8,1,0.0,8,1
2013/2/1 2:00:00,-3.7,8,1,3,8,1,0.3,8,Nord,8,1,0.0,8,1
2013/2/1 3:00:00,-4.0,8,1,3,8,1,0.2,8,Silencieux,8,1,0.0,8,1
2013/2/1 4:00:00,-4.8,8,1,3,8,1,0.9,8,Sud-sud-est,8,1,0.0,8,1
...

façon de penser de base

L'idée est que ce type de prédiction est probablement standard, mais nous entraînons le modèle avec certains types de données périphériques et la quantité de neige résultante sous forme d'ensemble, et seules les données périphériques sont appliquées au modèle résultant. Il donne et obtient la valeur prévue de la quantité de neige. C'est ce que l'on appelle l ' "apprentissage enseigné" </ b>.

Dans ce cas, les données suivantes ont été utilisées comme données périphériques.

  • Température
  • Vitesse du vent
  • Chutes de neige d'hier
  • Température d'il y a 1 jour, température d'il y a 2 jours, température d'il y a 3 jours
  • Vitesse du vent il y a 1 jour, vitesse du vent il y a 2 jours, vitesse du vent il y a 3 jours

Cela ressemble à ça en termes d'image.

[Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]→ Chutes de neige le jour

[Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]→ Chutes de neige le jour

[Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]→ Chutes de neige le jour

....


[Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]→ Chutes de neige le jour

Donc, sur cette base, ne donnez que les données périphériques et obtenez la valeur prédite

[Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]→ (Chutes de neige prévues le jour)

Je l'ai fait comme ça. Fondamentalement, les données de la date cible de prévision sont données, mais une seule «chute de neige d'hier» correspond aux données un jour avant la date cible de prévision. Et cela semblait avoir le plus d'impact sur les données qu'il fournissait. Eh bien, quand on y pense, c'est naturel.

Comme je l'ai écrit au début, je vais utiliser les données pendant environ 7500 jours à partir des données obtenues de l'Agence météorologique pour la formation, prédire le changement de neige pour les 2 années restantes et le comparer avec le changement réel des chutes de neige.

Essayez de prédire

Le code réel ressemble à ceci:

snow_forecaster.py



import csv
import numpy as np
from matplotlib import pyplot
from sklearn import linear_model
from sklearn import cross_validation


class SnowForecast:

    def __init__(self):
        u"""Initialiser chaque variable d'instance"""
        self.model = None    #Modèle d'apprentissage généré
        self.data = []       #Tableau de données d'entraînement
        self.target = []     #Disposition des chutes de neige réelles
        self.predicts = []   #Disposition des valeurs prévues des chutes de neige
        self.reals = []      #Disposition des chutes de neige réelles
        self.day_counts = [] #Organisation des dates écoulées à partir de la date de début
        self.date_list = []
        self.record_count = 0

    def load_csv(self):
        u"""Lire un fichier CSV pour apprendre"""
        with open("sample_data/data.csv", "r") as f:
            reader = csv.reader(f)
            accumulation_yesterday0 = 0
            date_yesterday = ""            
            temp_3days = []
            wind_speed_3days = []

            for row in reader:
                if row[4] == "":
                    continue

                daytime = row[0]               # "yyyy/mmdd HH:MM:SS"
                date = daytime.split(" ")[0]   # "yyyy/mm/dd"
                temp = int(float(row[1]))      #Température. Il y a un effet subtil
                wind_speed = float(row[7])     #vitesse du vent. Il y a un effet subtil
                precipitation = float(row[12]) #Précipitation. aucun effet
                accumulation = int(row[4])     #La quantité de neige. La quantité de neige d'hier a un grand impact

                if len(wind_speed_3days) == 3:
                    #Données d'entraînement
                    # [Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]
                    sample = [temp, wind_speed, accumulation_yesterday0]
                    sample.extend(temp_3days)
                    sample.extend(wind_speed_3days)
                    self.data.append(sample)
                    self.target.append(accumulation)

                if date_yesterday != date:
                    accumulation_yesterday0 = accumulation
                    self.date_list.append(date)

                    wind_speed_3days.insert(0, wind_speed)
                    if len(wind_speed_3days) > 3:
                        wind_speed_3days.pop()

                    temp_3days.insert(0, temp)
                    if len(temp_3days) > 3:
                        temp_3days.pop()

                    date_yesterday = date

        self.record_count = len(self.data)
        return self.data

    def train(self):
        u"""Générez un modèle de formation. Utilisez jusqu'à environ 7500 jours des données d'origine pour les données d'entraînement"""
        x = self.data
        y = self.target
        print(len(x))
        # ElasticNetCV,LassoCV,Sélectionnez Elastic NetCV avec la plus petite erreur de RidgeCV
        model = linear_model.ElasticNetCV(fit_intercept=True)
        model.fit(x[0:self.training_data_count()], y[0:self.training_data_count()])
        self.model = model

    def predict(self):
        u"""Prédire à l'aide d'un modèle d'apprentissage. Faites des prédictions pour les deux dernières années"""
        x = self.data
        y = self.target
        model = self.model

        for i, xi in enumerate(x):
            real_val = y[i]

            if i < self.training_data_count() + 1:
                self.predicts.append(0)
                self.reals.append(real_val)
                self.day_counts.append(i)
                continue

            predict_val = int(model.predict([xi])[0])

            #Si la prévision de neige est égale ou inférieure à 0, elle est définie sur 0.
            if predict_val < 0:
                predict_val = 0

            self.predicts.append(predict_val)
            self.reals.append(real_val)
            self.day_counts.append(i)

    def show_graph(self):
        u"""Comparez les valeurs prédites et mesurées avec un graphique"""
        pyplot.plot(self.day_counts[self.predict_start_num():], self.reals[self.predict_start_num():], "b")
        pyplot.plot(self.day_counts[self.predict_start_num():], self.predicts[self.predict_start_num():], "r")
        pyplot.show()

    def check(self):
        u"""Mesurer l'erreur entre les données d'entraînement et les données de prédiction"""
        x = np.array(self.data[self.predict_start_num():])
        y = np.array(self.target[self.predict_start_num():])
        model = self.model
        p = np.array(self.predicts[self.predict_start_num():])
        e = p - np.array(self.reals[self.predict_start_num():])
        error = np.sum(e * e)
        rmse_10cv = np.sqrt(error / len(self.data[self.predict_start_num():]))
        print("RMSE(10-fold CV: {})".format(rmse_10cv))

    def training_data_count(self):
        u"""Laissez les deux dernières années et utilisez les données antérieures comme données d'entraînement. Renvoie le nombre de données d'entraînement"""
        return self.record_count - 365 * 2

    def predict_start_num(self):
        u"""Les deux dernières années sont prévues et utilisées pour mesurer l'erreur à partir de la valeur mesurée. Renvoie la position de départ prévue"""
        return self.training_data_count() + 1

if __name__ == "__main__":
    forecaster = SnowForecast()
    forecaster.load_csv()
    forecaster.train()
    forecaster.predict()
    forecaster.check()
    forecaster.show_graph()

La partie la plus ennuyeuse a été de créer des données d'entraînement à partir de données brutes comme dans le chapitre précédent. Pourtant, c'est facile parce que c'est python.

Ainsi, le résultat de l'exécution est le suivant (le bleu est la quantité réelle de neige, la ligne rouge est la quantité de neige prévue). C'est le premier "résultat 1" affiché. スクリーンショット 2016-05-01 17.45.39.png

Je prédis quelque chose comme ça.

À ce stade, je me suis soudain demandé comment faire cela. "Mais je prédis en donnant la quantité de neige il y a un jour, donc quand j'essaye de l'utiliser pour des prévisions futures, je ne peux prédire la quantité de neige que demain…?" b>

Non, tu sais? Si vous dites cela, la température et la vitesse du vent seront les mêmes. Mais vous voyez, ce sont des prévisions météorologiques ... Gefun Gefun

Changé pour prédire les chutes de neige du lendemain en utilisant les chutes de neige d'hier que j'avais prédites

Donc, j'ai immédiatement modifié le code comme ça. Il n'y a pas de modifications particulières à la partie formation du modèle. Parmi les données fournies lors de la prédiction de la quantité de neige, remplaçons la quantité de neige d'hier par la` valeur prévue un jour avant, qui a été prédite par lui-même, au lieu de la valeur de mesure réelle.

Le code est comme suit. Seule la fonction «prédire» a changé.

snow_forecaster.py


import csv
import numpy as np
from matplotlib import pyplot
from sklearn import linear_model
from sklearn import cross_validation


class SnowForecast:

    def __init__(self):
        u"""Initialiser chaque variable d'instance"""
        self.model = None    #Modèle d'apprentissage généré
        self.data = []       #Tableau de données d'entraînement
        self.target = []     #Disposition des chutes de neige réelles
        self.predicts = []   #Disposition des valeurs prévues des chutes de neige
        self.reals = []      #Disposition des chutes de neige réelles
        self.day_counts = [] #Organisation des dates écoulées à partir de la date de début
        self.date_list = []
        self.record_count = 0

    def load_csv(self):
        u"""Lire un fichier CSV pour apprendre"""
        with open("sample_data/data.csv", "r") as f:
            reader = csv.reader(f)
            accumulation_yesterday0 = 0
            date_yesterday = ""            
            temp_3days = []
            wind_speed_3days = []

            for row in reader:
                if row[4] == "":
                    continue

                daytime = row[0]               # "yyyy/mmdd HH:MM:SS"
                date = daytime.split(" ")[0]   # "yyyy/mm/dd"
                temp = int(float(row[1]))      #Température. Il y a un effet subtil
                wind_speed = float(row[7])     #vitesse du vent. Il y a un effet subtil
                precipitation = float(row[12]) #Précipitation. aucun effet
                accumulation = int(row[4])     #La quantité de neige. La quantité de neige d'hier a un grand impact

                if len(wind_speed_3days) == 3:
                    #Données d'entraînement
                    # [Température,vitesse du vent,Chutes de neige d'hier,1日前のTempérature,2日前のTempérature,3日前のTempérature, 1日前のvitesse du vent, 2日前のvitesse du vent, 3日前のvitesse du vent]
                    sample = [temp, wind_speed, accumulation_yesterday0]
                    sample.extend(temp_3days)
                    sample.extend(wind_speed_3days)
                    self.data.append(sample)
                    self.target.append(accumulation)

                if date_yesterday != date:
                    accumulation_yesterday0 = accumulation
                    self.date_list.append(date)

                    wind_speed_3days.insert(0, wind_speed)
                    if len(wind_speed_3days) > 3:
                        wind_speed_3days.pop()

                    temp_3days.insert(0, temp)
                    if len(temp_3days) > 3:
                        temp_3days.pop()

                    date_yesterday = date

        self.record_count = len(self.data)
        return self.data

    def train(self):
        u"""Générez un modèle de formation. Utilisez jusqu'à environ 7500 jours des données d'origine pour les données d'entraînement"""
        x = self.data
        y = self.target
        print(len(x))
        # ElasticNetCV,LassoCV,Sélectionnez Elastic NetCV avec la plus petite erreur de RidgeCV
        model = linear_model.ElasticNetCV(fit_intercept=True)
        model.fit(x[0:self.training_data_count()], y[0:self.training_data_count()])
        self.model = model

    def predict(self):
        u"""Prédisez la quantité de neige à l'aide d'un modèle d'apprentissage. Faites des prédictions pour les deux dernières années"""
        x = self.data
        y = self.target
        model = self.model
        yesterday_predict_val = None #Variable pour stocker la valeur prévue d'hier

        for i, xi in enumerate(x):
            real_val = y[i]

            if i < self.training_data_count() + 1:
                self.predicts.append(0)
                self.reals.append(real_val)
                self.day_counts.append(i)
                continue

            #Remplacez les chutes de neige d'hier par les prévisions d'hier
            if yesterday_predict_val != None:
                xi[2] = yesterday_predict_val

            predict_val = int(model.predict([xi])[0])

            #Si la prévision de neige est égale ou inférieure à 0, elle est définie sur 0.
            if predict_val < 0:
                predict_val = 0

            self.predicts.append(predict_val)
            self.reals.append(real_val)
            self.day_counts.append(i)
            yesterday_predict_val = predict_val

    def show_graph(self):
        u"""Comparez les valeurs prédites et mesurées avec un graphique"""
        pyplot.plot(self.day_counts[self.predict_start_num():], self.reals[self.predict_start_num():], "b")
        pyplot.plot(self.day_counts[self.predict_start_num():], self.predicts[self.predict_start_num():], "r")
        pyplot.show()

    def check(self):
        u"""Mesurer l'erreur entre les données d'entraînement et les données de prédiction"""
        x = np.array(self.data[self.predict_start_num():])
        y = np.array(self.target[self.predict_start_num():])
        model = self.model
        p = np.array(self.predicts[self.predict_start_num():])
        e = p - np.array(self.reals[self.predict_start_num():])
        error = np.sum(e * e)
        rmse_10cv = np.sqrt(error / len(self.data[self.predict_start_num():]))
        print("RMSE(10-fold CV: {})".format(rmse_10cv))

    def training_data_count(self):
        u"""Laissez les deux dernières années et utilisez les données antérieures comme données d'entraînement. Renvoie le nombre de données d'entraînement"""
        return self.record_count - 365 * 2

    def predict_start_num(self):
        u"""Les deux dernières années sont prévues et utilisées pour mesurer l'erreur à partir de la valeur mesurée. Renvoie la position de départ prévue"""
        return self.training_data_count() + 1

if __name__ == "__main__":
    forecaster = SnowForecast()
    forecaster.load_csv()
    forecaster.train()
    forecaster.predict()
    forecaster.check()
    forecaster.show_graph()

Le résultat est le suivant (le bleu est la quantité réelle de neige, la ligne rouge est la quantité de neige prévue). "Résultat 2" affiché au début. スクリーンショット 2016-05-01 17.59.35.png

Hmm. Comme prévu, il est devenu plus imprécis que lorsque la quantité réelle de neige a été donnée hier. Cependant, il semble que la forme d'onde ne soit pas si perturbée.

Impressions etc.

Je me demandais si ce serait une prédiction plus foirée, mais je pensais que j'étais capable de la prédire comme ça. Cependant, bien qu'il ait été trompé avec succès par Gefun Gefun en cours de route, la température et la vitesse du vent données lors de la prédiction utilisent les valeurs mesurées du jour. Mais si vous souhaitez faire des prédictions pour une certaine période dans le futur, vous devez utiliser les valeurs prédites séparément ou arrêter d'utiliser ces valeurs en premier lieu, donc si vous utilisez les valeurs prédites, la précision sera plus élevée. Il descendra. De plus, le plus l'avenir. Donc, si vous voulez faire quelque chose comme ça, faites une prédiction en utilisant la valeur prédite, puis faites une prédiction en l'utilisant, et ainsi de suite, et plus tard, la légère erreur dans le processus précédent augmentera considérablement. pensée. Alors faites de votre mieux (Agence météorologique)

Recommended Posts