[PYTHON] Schneiden Sie und nehmen Sie einen gewichteten gleitenden Durchschnitt

Einführung

Manchmal habe ich Lust, zu schneiden und einen gleitenden Durchschnitt zu nehmen. Ich möchte auch einen gewichteten Durchschnitt nehmen, weil ich den Einfluss des neuesten numerischen Werts erhöhen möchte. Grundsätzlich ist der Trend der gleiche, aber ich möchte einen gleitenden Durchschnitt ohne Bezugnahme auf die Zeitreihendaten nehmen, wenn der numerische Wert gelegentlich spitzenartig ansteigt oder wenn der numerische Wert in Eile ansteigt. Sie können so denken. Ähm nein? Ich schreibe immer noch. Ich hatte ein kleines Problem mit dem Rollen (). Bewerben Sie sich, also möchte ich es aufschreiben.

Durchschnitt schneiden

Ein Verfahren zum Anordnen der numerischen Werte der zu mittelnden Datengruppe in der Reihenfolge ihrer Größe und zum Ausschließen von N% auf einer Seite oder auf beiden Seiten, um den Durchschnitt zu ermitteln. Es wird angenommen, dass unten 10 Daten vorhanden sind. [10,24,31,34,65,86,87,88,99,101]

Wenn Sie den Durchschnitt normal nehmen, (10+24+31+34+65+86+87+88+99+101)\div10=62.50‬ Angenommen, 10% auf einer Seite und 10% auf einer Seite werden entfernt, (24+31+34+65+86+87+88+99)\div8=64.25

Trimm (Schnitt) Durchschnitt ist zu entfernen und so zu mitteln. Wenn es sich um einen gleitenden Durchschnitt handelt, handelt es sich um ein Bild, das den numerischen Wert in der Fenstergröße schneidet und mittelt. Der Vorteil ist, dass Ausreißer beseitigt werden können. Es ist möglich zu verhindern, dass der Durchschnitt zum Ausreißer gezogen wird.

gewichteter Durchschnitt

Da Erklärungen an verschiedenen Stellen geschrieben werden, werden Details weggelassen. Es bedeutet, die Zahlen zu gewichten und den Durchschnitt zu nehmen. Gewichtete gleitende Durchschnitte werden häufig so gewichtet, dass der Einfluss des neuesten Zahlenwerts groß ist.

Da wir diesmal den trimmgewichteten gleitenden Durchschnitt nehmen möchten, nehmen wir den gewichteten gleitenden Durchschnitt nach dem Trimmen mit dem numerischen Wert innerhalb der Fenstergröße des gleitenden Durchschnitts.

Versuchen Sie es mit Python

Paketimport

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()

Datenerstellung

Erstellen Sie Daten basierend auf dem Übergang der Anzahl der aktiven Benutzer von Smartphone-Apps

make_data.py


#Abklingkurve
def exp_func(x, a, b):
    return b*(x**a)
x=np.linspace(1,36,36)
data=exp_func(x, -0.5, 100000)

#Datenrahmen
df=pd.DataFrame({'x':x,'y':data})
df=df.astype(int)

#Erstellen Sie eine Monatsspalte, da dies eine Annahme von Zeitreihendaten ist
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

Datenverarbeitung (Eingabe abnormaler Werte)

Es scheint, dass die Anzahl der aktiven Benutzer je nach Kampagne oder Ereignis der Smartphone-Anwendung vorübergehend erheblich zunimmt. Ändern wir daher den numerischen Wert der Daten unter der Annahme einer solchen 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 Daten, die die Anzahl der aktiven Benutzer in Kampagnen wie dem 1. Jahrestag erhöht zu haben scheinen, wurden abgeschlossen.

Nehmen Sie den trimmgewichteten gleitenden Durchschnitt

Lassen Sie uns dieses Mal einen Code mit der Richtlinie erstellen, den trimmgewichteten gleitenden Durchschnitt als vorhergesagten Wert zu verwenden. Der vorhergesagte Wert des numerischen Werts nach 3 Monaten wird als Wert des trimmgewichteten gleitenden Durchschnitts verwendet. (Beispiel: Der numerische Wert von 2018-08 wird unter Verwendung des trimmgewichteten gleitenden Durchschnitts von 2018-05 vorhergesagt.)

Trimmen Sie zunächst die einfache Funktion des gleitenden Durchschnitts

sma.py


def sma(roll_list):
    # roll_Entfernen Sie, wenn Nan in der Liste ist
    roll_list=roll_list[~np.isnan(roll_list)]
    # roll_Liste in aufsteigender Reihenfolge anordnen
    sorted_roll_list=sorted(roll_list)
    #Rolle in aufsteigender Reihenfolge angeordnet_Definieren Sie die halbe Länge der Liste
    harf_span=round(len(sorted_roll_list)/2)
    if harf_span > 0:
        # roll_Holen Sie sich die Zahlen unter dem Median der Liste und nehmen Sie den Durchschnitt
        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_Da die Länge der Liste 1 oder weniger beträgt, kann der Medianwert nicht erhalten werden.
        # roll_Verwenden Sie den Wert der Liste so wie er ist
        roll_list_harf=roll_list[0]
        sma = roll_list_harf
    return sma

Dann die trimmgewichtete Funktion des gleitenden Durchschnitts

sma.py


def wma(roll_list):
    # roll_Entfernen Sie, wenn Nan in der Liste ist
    roll_list=roll_list[~np.isnan(roll_list)]
    # roll_Liste in aufsteigender Reihenfolge anordnen
    sorted_roll_list=sorted(roll_list)
    #Rolle in aufsteigender Reihenfolge angeordnet_Definieren Sie die halbe Länge der Liste
    harf_span=round(len(sorted_roll_list)/2)
    # roll_Holen Sie sich Zahlen unter dem Median der Liste
    harf_index=np.where(roll_list < sorted_roll_list[harf_span])
    roll_list_harf=roll_list[harf_index]
    # roll_Berechnen Sie das Gewicht der Zahlen unter dem Medianwert der Liste und nehmen Sie den gewichteten gleitenden Durchschnitt.
    weight = np.arange(len(roll_list_harf)) + 1
    wma = np.sum(weight * roll_list_harf) / weight.sum()
    return wma

Als nächstes beträgt die Fenstergröße unter Verwendung der obigen Funktion 6 Monate, und die anderen Teile als die 3 Monate mit den niedrigsten numerischen Werten werden abgeschnitten und der gewichtete gleitende Durchschnitt wird genommen. Mit Pandas Rolling können Sie leicht einen gleitenden Durchschnitt ermitteln und mithilfe von Apply Ihre eigene Funktion anwenden. Übrigens bezieht sich die in den obigen Funktionen sma und wma angezeigte roll_list auf das Datenarray, das in der durch das Rollen von Pandas angegebenen Fenstergröße (Periode) erfasst wurde. Es scheint, dass das Datenarray als Serientyp in die Funktion eingefügt werden kann, wenn nichts unternommen wird. Da die Funktionen sma und wma unter der Annahme von ndarray erstellt wurden, tritt ein Fehler auf, wenn es sich um einen Serientyp handelt. Um einen Fehler zu vermeiden, wird raw = True in das Argument von apply eingefügt, um es zu einem ndarray-Typ zu machen.

moving_mean.py


#Erstellen Sie vor 3 Monaten eine Zahlenspalte
df2['y_shift'] = df2['y'].shift(3)
#SMA des Wertes vor 3 Monaten
df2['y_sma'] = df2['y_shift'].rolling(6,min_periods=1).apply(sma, raw = True)
#WMA vor 3 Monaten
df2['y_wma'] = df2['y_shift'].rolling(6,min_periods=1).apply(wma, raw = True)
#WMA kann nicht berechnet werden NULL wird auf SMA-Wert gesetzt
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

Datenrahmen Die gelbe Linie ist der tatsächliche Wert, die hellblaue Linie ist der Wert für die letzten 3 Monate und die grüne Linie ist der Wert für die niedrigsten 3 Monate der letzten 6 Monate. Blau in der Grafik ist der tatsächliche Wert, und Rot ist der Wert, der erhalten wird, indem der trimmgewichtete gleitende Durchschnitt der Daten bis vor 3 Monaten (vorhergesagter Wert) genommen wird.

Achten Sie beispielsweise auf Juni 2018. ·Tatsächlicher Wert:  23,570 ・ Wenn Sie einen gewichteten gleitenden Durchschnitt für 3 Monate ohne Trimmen nehmen: gewichteter Durchschnitt von Januar 2018 bis März 2018  (3 \times 30,983 + 2 \times 37,416 + 1 \times 44,376) \div (3+2+1) = 35,359 ・ Beim Trimmen und Nehmen eines gewichteten gleitenden Durchschnitts für 3 Monate: Gewichteter Durchschnitt für 3 Monate mit niedrigen Zahlen von Oktober 2017 bis März 2018  (3 \times 30,982 + 2 \times 28,867 + 1 \times 30,151) \div (3+2+1) = 30,139

Durch Trimmen und Verwenden eines gewichteten gleitenden Durchschnitts werden die Auswirkungen des starken Anstiegs im Januar 2018 auf nachfolgende Berechnungen beseitigt.

Zusammenfassung

Ich denke, es ist nützlich, wenn Sie einen gleitenden Durchschnitt verwenden möchten, der den Einfluss abnormaler Werte in Zeitreihendaten eliminiert, die häufig abnormale Werte enthalten.

Recommended Posts

Schneiden Sie und nehmen Sie einen gewichteten gleitenden Durchschnitt
Kerzenbalkendiagramm und gleitender Durchschnittsliniendiagramm
[Systre] Kaufen und verkaufen mit mobilem Durchschnitts-MACD ♬
Sehen Sie sich das Profiling und Dumping mit Dataflow an
[Python] Machen Sie einen Screenshot
Gleitender Durchschnitt mit Numpy
Ich habe versucht, mit Quantx eine Linie mit gleitendem Durchschnitt des Volumens zu implementieren