[PYTHON] Couper et prendre une moyenne mobile pondérée

introduction

Parfois, j'ai envie de rogner et de prendre une moyenne mobile. Je souhaite également prendre une moyenne pondérée car je souhaite augmenter l'influence de la dernière valeur numérique. Fondamentalement, la tendance est la même, mais je voudrais prendre une moyenne mobile sans référence aux données de la série chronologique lorsque la valeur numérique augmente de manière ponctuelle à l'occasion ou lorsque la valeur numérique augmente à la hâte. Vous pouvez le penser. Eh non? J'écris toujours. J'ai eu un peu de mal à rouler (). Postuler, alors je veux l'écrire.

Trim moyenne

Une méthode d'agencement des valeurs numériques du groupe de données à faire la moyenne par ordre de taille et à l'exclusion de N% d'un côté ou des deux côtés pour prendre la moyenne. On suppose qu'il y a 10 données ci-dessous. [10,24,31,34,65,86,87,88,99,101]

Si vous prenez la moyenne normalement, (10+24+31+34+65+86+87+88+99+101)\div10=62.50‬ En supposant que 10% d'un côté et 10% d'un côté sont supprimés, (24+31+34+65+86+87+88+99)\div8=64.25

La moyenne de la taille (taille) est de supprimer et la moyenne comme celle-ci. S'il s'agit d'une moyenne mobile, c'est une image qui rogne et fait la moyenne de la valeur numérique dans la taille de la fenêtre. Le mérite est que les valeurs aberrantes peuvent être éliminées. Il est possible d'empêcher la moyenne d'être tirée vers la valeur aberrante.

moyenne pondérée

Les explications étant écrites à divers endroits, les détails sont omis. Pour pondérer les nombres et prendre la moyenne. Les moyennes mobiles pondérées sont souvent pondérées de sorte que l'influence de la dernière valeur numérique soit grande.

Puisque nous voulons prendre la moyenne mobile pondérée ajustée cette fois, nous prenons la moyenne mobile pondérée après ajustement avec la valeur numérique dans la taille de la fenêtre de la moyenne mobile.

Essayez-le avec Python

Importation de package

import.py


import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import datetime as dt
from dateutil.relativedelta import relativedelta
sns.set()

Création de données

Créer des données en fonction de la transition du nombre d'utilisateurs actifs des applications pour smartphone

make_data.py


#Courbe de décroissance
def exp_func(x, a, b):
    return b*(x**a)
x=np.linspace(1,36,36)
data=exp_func(x, -0.5, 100000)

#Trame de données
df=pd.DataFrame({'x':x,'y':data})
df=df.astype(int)

#Créer une colonne de mois, car il s'agit d'une hypothèse de données de séries chronologiques
init_mon=dt.datetime(2017,df['x'].values[0],1)
months=[init_mon]
for mon in range(1,len(df)):
    months.append(init_mon + relativedelta(months=mon))
df['month']=months
df.index=months
display(df.head())

# plot
fig=plt.figure(figsize=(12,6))
ax=plt.subplot(1,1,1)
df.plot.bar('month','y',ax=ax)
plt.show()

image.png image.png

Traitement des données (saisie de valeurs anormales)

Il semble que le nombre d'utilisateurs actifs augmentera temporairement considérablement en fonction de la campagne ou de l'événement de l'application smartphone, changeons donc la valeur numérique des données en supposant une telle situation.

change_data.py


df2=df.copy()
df2.loc[(df2.index.month==1)&(df2.index.year>=2018), 'y']=df2['y']*1.6
df2.loc[(df2.index.month==2)&(df2.index.year>=2018), 'y']=df2['y']*1.4
df2.loc[(df2.index.month==3)&(df2.index.year>=2018), 'y']=df2['y']*1.2

fig=plt.figure(figsize=(12,6))
ax=plt.subplot(1,1,1)
df2.plot.bar('month','y',ax=ax)
plt.show()

image.png Les données qui semblent avoir augmenté le nombre d'utilisateurs actifs dans des campagnes telles que le 1er anniversaire sont terminées.

Prendre la moyenne mobile pondérée ajustée

Cette fois, construisons un code avec la politique d'utiliser la moyenne mobile pondérée par ajustement comme valeur prédite. La valeur prédite de la valeur numérique après 3 mois est utilisée comme valeur de la moyenne mobile pondérée ajustée. (Exemple: la valeur numérique de 2018-08 est prédite en prenant la moyenne mobile pondérée coupée à partir de 2018-05)

Tout d'abord, couper la fonction de moyenne mobile simple

sma.py


def sma(roll_list):
    # roll_Supprimer si Nan est dans la liste
    roll_list=roll_list[~np.isnan(roll_list)]
    # roll_Organiser la liste par ordre croissant
    sorted_roll_list=sorted(roll_list)
    #Rouleau disposé par ordre croissant_Définir la moitié de la longueur de la liste
    harf_span=round(len(sorted_roll_list)/2)
    if harf_span > 0:
        # roll_Obtenez les nombres sous la médiane de la liste et prenez la moyenne
        harf_index=np.where(roll_list < sorted_roll_list[harf_span])
        roll_list_harf=roll_list[harf_index]
        sma = np.sum(roll_list_harf) / len(roll_list_harf)
    else:
        # roll_La longueur de la liste étant inférieure ou égale à 1, la valeur médiane ne peut pas être obtenue.
        # roll_Utilisez la valeur de list telle quelle
        roll_list_harf=roll_list[0]
        sma = roll_list_harf
    return sma

Ensuite, la fonction moyenne mobile pondérée ajustée

sma.py


def wma(roll_list):
    # roll_Supprimer si Nan est dans la liste
    roll_list=roll_list[~np.isnan(roll_list)]
    # roll_Organiser la liste par ordre croissant
    sorted_roll_list=sorted(roll_list)
    #Rouleau disposé par ordre croissant_Définir la moitié de la longueur de la liste
    harf_span=round(len(sorted_roll_list)/2)
    # roll_Obtenez des nombres inférieurs à la médiane de la liste
    harf_index=np.where(roll_list < sorted_roll_list[harf_span])
    roll_list_harf=roll_list[harf_index]
    # roll_Calculez le poids des nombres sous la valeur médiane de la liste et prenez la moyenne mobile pondérée.
    weight = np.arange(len(roll_list_harf)) + 1
    wma = np.sum(weight * roll_list_harf) / weight.sum()
    return wma

Ensuite, en utilisant la fonction ci-dessus, la taille de la fenêtre est de 6 mois, et les parties autres que les 3 mois avec les valeurs numériques les plus faibles sont coupées et la moyenne mobile pondérée est prise. Vous pouvez facilement obtenir une moyenne mobile en utilisant le roulement des pandas, et vous pouvez appliquer votre propre fonction en utilisant apply. À propos, la liste_roulés qui apparaît dans les fonctions sma et wma ci-dessus fait référence à un tableau de données acquises dans la taille de la fenêtre (période) spécifiée par le roulement des pandas. Il semble que le tableau de données puisse être mis dans la fonction en tant que type Series si rien n'est fait. Puisque les fonctions sma et wma ont été construites en supposant ndarray, une erreur se produira s'il s'agit d'un type Series. Afin d'éviter une erreur, raw = True est mis dans l'argument de apply pour en faire un type ndarray.

moving_mean.py


#Créer une colonne de nombres il y a 3 mois
df2['y_shift'] = df2['y'].shift(3)
#SMA de la valeur il y a 3 mois
df2['y_sma'] = df2['y_shift'].rolling(6,min_periods=1).apply(sma, raw = True)
#WMA d'il y a 3 mois
df2['y_wma'] = df2['y_shift'].rolling(6,min_periods=1).apply(wma, raw = True)
#WMA ne peut pas être calculé NULL est défini sur la valeur SMA
df2.loc[pd.isna(df2['y_wma']), 'y_wma']=df2['y_sma']

display(df2.head(10))

# plot
fig=plt.figure(figsize=(12,6))
ax=plt.subplot(1,1,1)
df2.plot.bar('month','y',ax=ax,color='b',alpha=0.9)
df2.plot.bar('month','y_wma',ax=ax,color='r',alpha=0.6)
plt.show()

image.png image.png

Cadre de données La ligne jaune est la valeur réelle, la ligne bleu clair est la valeur des 3 derniers mois et la ligne verte est la valeur des 3 mois les plus bas des 6 derniers mois. Le bleu dans le graphique est la valeur réelle et le rouge est la valeur obtenue en prenant la moyenne mobile pondérée coupée des données il y a jusqu'à 3 mois (valeur prédite).

Par exemple, faites attention à juin 2018. ·Valeur actuelle:  23,570 ・ Lors de la prise d'une moyenne mobile pondérée pendant 3 mois sans ajustement: moyenne pondérée de janvier 2018 à mars 2018  (3 \times 30,983 + 2 \times 37,416 + 1 \times 44,376) \div (3+2+1) = 35,359 ・ Lors de la réduction et de la prise d'une moyenne mobile pondérée pendant 3 mois: moyenne pondérée pendant 3 mois avec des chiffres faibles d'octobre 2017 à mars 2018  (3 \times 30,982 + 2 \times 28,867 + 1 \times 30,151) \div (3+2+1) = 30,139

La réduction et la prise d'une moyenne mobile pondérée élimineront l'impact de la forte hausse de janvier 2018 sur les calculs ultérieurs.

Résumé

Je pense que c'est utile lorsque vous voulez prendre une moyenne mobile qui élimine l'influence des valeurs anormales dans les données de séries chronologiques qui contiennent souvent des valeurs anormales.

Recommended Posts

Couper et prendre une moyenne mobile pondérée
Graphique à barres de bougie et tracé de la moyenne mobile
[Systre] Achetez et vendez avec le MACD moyen mobile ♬
Jetez un œil au profilage et au vidage avec Dataflow
[Python] Prenez une capture d'écran
Moyenne mobile avec numpy
J'ai essayé d'implémenter une ligne moyenne mobile de volume avec Quantx