การวิเคราะห์ข้อมูลอนุกรมเวลาด้วย Python
By: Nuthdanai Wangpratham
Tags: การวิเคราะห์อนุกรมเวลา, Time Series Analysis, ข้อมูลอนุกรมเวลา, การพยากรณ์, ทำนาย

การวิเคราะห์ข้อมูลอนุกรมเวลาด้วย Python

ข้อมูลอนุกรมเวลา(Time Series data) คือชุดของข้อมูลที่เก็บรวบรวมตามระยะเวลาเป็นช่วง ๆ การคาดการณ์อนุกรมเวลามีความสำคัญเชิงธุรกิจอย่างมาก ข้อมูลที่ธุรกิจเก็บและต้องการพยากรณ์มักมาในรูปแบบอนุกรมเวลา เช่นอุปสงค์และยอดขายจำนวนผู้เข้าชมเว็บไซต์ราคาหุ้น ฯลฯ เป็นข้อมูลอนุกรมเวลา

การวิเคราะห์อนุกรมเวลาเกี่ยวข้องกับการทำความเข้าใจกับแง่มุมต่าง ๆ เกี่ยวกับการเปลี่ยนแปลงตามธรรมชาติของข้อมูล เพื่อให้สามารถพยากรณ์ข้อมูลในอนาคตได้เเม่นยำขึ้น

ตัวอย่างข้อมูลอนุกรมเวลา (Time Series data)

from dateutil.parser import parse

import matplotlib as mpl

import matplotlib.pyplot as plt

import seaborn as sns

import numpy as np

import pandas as pd

df = pd.read_csv('

df.head() # Import as Dataframedf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'])df.head()

panel data

คือ ข้อมูลที่เก็บจากหน่วยตัวอย่าง i ในช่วงเวลาต่างๆ ทำให้ข้อมูลแต่ละช่วงเวลา ไม่เป็นอิสระต่อกัน ความแตกต่างคือนอกเหนือจากอนุกรมเวลายังมีตัวแปรที่เกี่ยวข้องอย่างน้อยหนึ่งตัวที่วัดในช่วงเวลาเดียวกัน โดยทั่วไปคอลัมน์ที่อยู่ในข้อมูลพาเนลจะมีตัวแปรอธิบายซึ่งมีประโยชน์ในการทำนาย Y โดยที่คอลัมน์เหล่านั้นจะพร้อมใช้งานในช่วงการคาดการณ์ในอนาคต

ตัวอย่างข้อมูล panel

การแสดงข้อมูลอนุกรมเวลา

มาใช้ matplotlib เพื่อแสดงข้อมูลอนุกรมเวลา



import matplotlib.pyplot as plt

df = pd.read_csv('



# Draw Plot

def plot_df(df, x, y, title="", xlabel='Date', ylabel='Value', dpi=100):

plt.figure(figsize=(16,5), dpi=dpi)

plt.plot(x, y, color='tab:red')

plt.gca().set(title=title, xlabel=xlabel, ylabel=ylabel)

plt.show()



plot_df(df, x=df.index, y=df.value, title='Monthly anti-diabetic drug sales in Australia from 1992 to 2008.') # Time series data source: fpp pacakge in R.import matplotlib.pyplot as pltdf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'], index_col='date')# Draw Plotdef plot_df(df, x, y, title="", xlabel='Date', ylabel='Value', dpi=100):plt.figure(figsize=(16,5), dpi=dpi)plt.plot(x, y, color='tab:red')plt.gca().set(title=title, xlabel=xlabel, ylabel=ylabel)plt.show()plot_df(df, x=df.index, y=df.value, title='Monthly anti-diabetic drug sales in Australia from 1992 to 2008.')

เนื่องจากค่าทั้งหมดเป็นค่าบวก เราสามารถแสดงสิ่งนี้บนทั้งสองด้านของแกน Y เพื่อเน้นการเติบโต

# Import data

df = pd.read_csv('datasets/AirPassengers.csv', parse_dates=['date'])

x = df['date'].values

y1 = df['value'].values



# Plot

fig, ax = plt.subplots(1, 1, figsize=(16,5), dpi= 120)

plt.fill_between(x, y1=y1, y2=-y1, alpha=0.5, linewidth=2, color='seagreen')

plt.ylim(-800, 800)

plt.title('Air Passengers (Two Side View)', fontsize=16)

plt.hlines(y=0, xmin=np.min(df.date), xmax=np.max(df.date), linewidth=.5)

plt.show()

การเปรียบเทียบรายปีบ้างครั้งเนื่องจากข้อมูลเป็นฤดูกาลเราอาจต้องเปลี่ยบเทียบในช่วงเดือนเดี่ยวกัน

# Import Data df = pd.read_csv('https://raw.githubusercontent.com/selva86/datasets/master/a10.csv', parse_dates=['date'], index_col='date') df.reset_index(inplace=True) # Prepare data df['year'] = [d.year for d in df.date] df['month'] = [d.strftime('%b') for d in df.date] years = df['year'].unique() # Prep Colors np.random.seed(100) mycolors = np.random.choice(list(mpl.colors.XKCD_COLORS.keys()), len(years), replace=False) # Draw Plot plt.figure(figsize=(16,12), dpi= 80) for i, y in enumerate(years): if i > 0: plt.plot('month', 'value', data=df.loc[df.year==y, :], color=mycolors[i], label=y) plt.text(df.loc[df.year==y, :].shape[0]-.9, df.loc[df.year==y, 'value'][-1:].values[0], y, fontsize=12, color=mycolors[i]) # Decoration plt.gca().set(xlim=(-0.3, 11), ylim=(2, 30), ylabel='$Drug Sales$', xlabel='$Month$') plt.yticks(fontsize=12, alpha=.7) plt.title("Seasonal Plot of Drug Sales Time Series", fontsize=20) plt.show()

Boxplot ของการกระจายแบบ Month-wise (Seasonal) และ Year-wise (trend)

เราสามารถจัดกลุ่มข้อมูลตามช่วงเวลาตามฤดูกาลและดูว่ามีการกระจายค่าภายในปีหรือเดือนที่กำหนดอย่างไรและเปรียบเทียบได้อย่างไรเมื่อเวลาผ่านไป



df = pd.read_csv('

df.reset_index(inplace=True)



# Prepare data

df['year'] = [d.year for d in df.date]

df['month'] = [d.strftime('%b') for d in df.date]

years = df['year'].unique()



# Draw Plot

fig, axes = plt.subplots(1, 2, figsize=(20,7), dpi= 80)

sns.boxplot(x='year', y='value', data=df, ax=axes[0])

sns.boxplot(x='month', y='value', data=df.loc[~df.year.isin([1991, 2008]), :])



# Set Title

axes[0].set_title('Year-wise Box Plot

(The Trend)', fontsize=18);

axes[1].set_title('Month-wise Box Plot

(The Seasonality)', fontsize=18)

plt.show() # Import Datadf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/mast er/a10.csv ', parse_dates=['date'], index_col='date')df.reset_index(inplace=True)# Prepare datadf['year'] = [d.year for d in df.date]df['month'] = [d.strftime('%b') for d in df.date]years = df['year'].unique()# Draw Plotfig, axes = plt.subplots(1, 2, figsize=(20,7), dpi= 80)sns.boxplot(x='year', y='value', data=df, ax=axes[0])sns.boxplot(x='month', y='value', data=df.loc[~df.year.isin([1991, 2008]), :])# Set Titleaxes[0].set_title('Year-wise Box Plot

(The Trend)', fontsize=18);axes[1].set_title('Month-wise Box Plot

(The Seasonality)', fontsize=18)plt.show()

บ็อกซ์พล็อตทำให้การกระจายรายปีและรายเดือนชัดเจน นอกจากนี้ในบ็อกซ์พล็อตแบบเดือนต่อเดือนของเดือนธันวาคมและมกราคมมีการขายยาที่สูงขึ้นอย่างชัดเจนซึ่งสามารถนำมาประกอบกับฤดูส่วนลดวันหยุด

การหา PATTERN ของข้อมูลอนุกรมเวลา

การหารูปแบบการเคลื่อนไหวของข้อมูลอนุกรมเวลาอย่างๆ ง่ายทำได้โดยการหาแนวโน้ม

การคาดการณ์เส้นแนวโน้มจากสมการต่างๆ โดยปกติมักใช้สมการดังต่อไปนี้

สมการเชิงเส้นตรง

Y = aX +b

สมการ Polynominal

Y =aX**n + aX**(n-1) …..aX +b

สมการ Logistic

Y = aIn(X) + b

สมการ exponential

Y = a* *x + b

#import libery

!pip install -q requests

import requeste

import pandas as pd

import datetime as dt

import matplotlib.pyplot as plt

import numpy as np

from scipy.optimize import curve_fit #import Dataset

dataurl = "https://covid19.th-stat.com/"

htmlsource = requests.get(dataurl).content

odat = pd.read_html(htmlsource)[0] #chang colum name

daycount = odat['หมายเลข'].values

daycount = [int(d.split('-')[-1].strip()) for d in daycount]

odat['daycount'] = daycount

dat = odat[['วันที่ยืนยัน','daycount']]

dat = dat.groupby('วันที่ยืนยัน').max()

dat = dat.sort_values(by='daycount')

dat['date'] = list(dat.index.values)

dat['date'] = dat['date'].astype('datetime64[ns]')

dat.index = range(len(dat)) import pylab as py

xdata = list(dat.index.values)

ydata = list(dat['daycount'].values)

py.plot(xdata,ydata)

ขั้นตอนต่อมาคือประกาศฟังชั่นที่จะใช้ในการพยากรณ์ ในที่นี้จะใช้ สมการ exponential และสมการ Polynominal กำลัง2,3

import matplotlib.pyplot as plt

import numpy as np

from scipy.optimize import curve_fit def expofunc(x, a, b, c):

return a * np.exp(b * x) + c def polyfunc(x,a,b,c):

return a*x**2+b*x+c def polyfunc2(x,a,b,c,d):

return a*x**3+b*x**2+c*x+d expoparam, _ = curve_fit(expofunc, xdata, ydata)

polyparam, _ = curve_fit(polyfunc, xdata, ydata)

polyparam2, _ = curve_fit(polyfunc2, xdata, ydata)

a,b,c=polyparam

predictfrompoly = []

daylist = list(range(0,xrange))

for xi in daylist:

predictfrompoly.append(polyfunc(xi,a,b,c))

xrange = 100

predictfromexpo = []

daylist = list(range(0,xrange))

for xi in daylist:

predictfromexpo.append(expofunc(xi,a,b,c)) a,b,c=polyparam

predictfrompoly = []

daylist = list(range(0,xrange))

for xi in daylist:

predictfrompoly.append(polyfunc(xi,a,b,c)) a,b,c,d=polyparam2 predictfrompoly2 = []

daylist = list(range(0,xrange))

for xi in daylist:

predictfrompoly2.append(polyfunc2(xi,a,b,c,d)) def funcplot. (xlim,predictfrompoly,predictfromexpo,daylist,xdata,ydata): py.plot(daylist[0:xlim],predictfrompoly[0:xlim],label='Predicted Polyfit')

py.plot(daylist[0:xlim],predictfromexpo[0:xlim],label='Predicted Expofit')

py.plot(xdata,ydata,label='Actual')

py.legend()

py.grid()

เปรียบเทียบแต่ละสมการที่เราทำนายได้

nextday = 0 xlim = 39 + nextday py.plot(daylist[0:xlim],predictfrompoly[0:xlim],label='Predicted Polyfit') py.plot(daylist[0:xlim],predictfrompoly2[0:xlim],label='Predicted Polyfit#2') py.plot(daylist[0:xlim],predictfromexpo[0:xlim],label='Predicted Expofit') py.plot(xdata,ydata,label='Actual')

py.legend()

py.grid()

จะสังเกตเห็นได้ว่าจำนวนผู้ติดเชื่อมีความใกล้เคียงกับ Polynominal กำลัง3 มากที่สุด

ต่อมาเราก็มาพยากรณ์จำนวนผู้ติดเชื่อในอีก 30 วันข้างหน้า

nextday = 30 xlim = 40 + nextday py.plot(daylist[0:xlim],predictfrompoly[0:xlim],label='Predicted Polyfit') py.plot(daylist[0:xlim],predictfrompoly2[0:xlim],label='Predicted Polyfit#2') py.plot(daylist[0:xlim],predictfromexpo[0:xlim],label='Predicted Expofit') py.plot(xdata,ydata,label='Actual')

py.legend()

py.grid()

ข้อมูลอนุกรมเวลาประกอบไปด้วย: ค่าพื้นฐาน+ แนวโน้ม + ฤดูกาล + ข้อผิดพลาด

มีการสังเกตแนวโน้มเมื่อมีการเพิ่มหรือลดความชันที่สังเกตได้ในอนุกรมเวลา ในขณะที่ฤดูกาลมีการสังเกตเมื่อมีรูปแบบการทำซ้ำที่ชัดเจนสังเกตได้ระหว่างช่วงเวลาปกติเนื่องจากปัจจัยตามฤดูกาล อาจเป็นเพราะเดือนของปี, วันที่ของเดือน, วันธรรมดาหรือแม้แต่เวลาของวัน

อย่างไรก็ตามไม่ได้บังคับว่าอนุกรมเวลาทั้งหมดจะต้องมีแนวโน้มและ / หรือฤดูกาล อนุกรมเวลาอาจไม่มีแนวโน้มที่ชัดเจน แต่มีฤดูกาล ตรงกันข้ามอาจมีแต่แนวโน้มไม่มีฤดูกาลก็ได้

ดังนั้นอนุกรมเวลาอาจถูกจินตนาการว่าเป็นการรวมกันของแนวโน้มฤดูกาลและข้อผิดพลาด

อีกแง่มุมที่ควรพิจารณาก็คือพฤติกรรมแบบวนรอบ ที่เกิดขึ้นเมื่อรูปแบบการขึ้นและลงในซีรีส์ไม่ได้เกิดขึ้นในช่วงเวลาที่กำหนดตามปฏิทิน ควรใช้ความระมัดระวังเพื่อไม่ให้เกิดความสับสน ‘เอฟเฟกต์’ กับเอฟเฟกต์ “ซีซัน”

ดังนั้นจะแยกความแตกต่างระหว่างรูปแบบ “วงจร” กับ “ฤดูกาล” อย่างไรหากรูปแบบไม่ใช่ความถี่ตามปฏิทินที่แน่นอนก็เป็นวงจร เพราะต่างจากฤดูกาลฤดูกาลผลกระทบตามวงจรมักจะได้รับอิทธิพลจากธุรกิจและปัจจัยทางเศรษฐกิจและสังคมอื่น ๆ

อนุกรมเวลาแบบเพิ่มและแบบคูณ

ขึ้นอยู่กับลักษณะของแนวโน้มและฤดูกาลอนุกรมเวลาสามารถสร้างแบบจำลองเป็นAdditiveหรือแบบMultiplicativeซึ่งการสังเกตแต่ละครั้งในชุดสามารถแสดงได้ทั้งผลรวมหรือผลคูณของส่วนประกอบ:

Additive time series:

Value = Base Level + Trend + Seasonality + Error

Multiplicative Time Series:

Value = Base Level x Trend x Seasonality x Error

7.จะแยกอนุกรมเวลาออกเป็นส่วนประกอบได้อย่างไร

เราสามารถสามารถแยกอนุกรมเวลาโดยพิจารณาว่าอนุกรมเป็นการรวมกันของBase Levelแนวโน้มดัชนีตามฤดูกาลและError โดยใช้ seasonal_decompose ใน statsmodels



from dateutil.parser import parse



# Import Data

df = pd.read_csv('



# Multiplicative Decomposition

result_mul = seasonal_decompose(df['value'], model='multiplicative', extrapolate_trend='freq')



# Additive Decomposition

result_add = seasonal_decompose(df['value'], model='additive', extrapolate_trend='freq')



# Plot

plt.rcParams.update({'figure.figsize': (10,10)})

result_mul.plot().suptitle('Multiplicative Decompose', fontsize=22)

result_add.plot().suptitle('Additive Decompose', fontsize=22)

plt.show() from statsmodels.tsa.seasonal import seasonal_decomposefrom dateutil.parser import parse# Import Datadf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'], index_col='date')# Multiplicative Decompositionresult_mul = seasonal_decompose(df['value'], model='multiplicative', extrapolate_trend='freq')# Additive Decompositionresult_add = seasonal_decompose(df['value'], model='additive', extrapolate_trend='freq')# Plotplt.rcParams.update({'figure.figsize': (10,10)})result_mul.plot().suptitle('Multiplicative Decompose', fontsize=22)result_add.plot().suptitle('Additive Decompose', fontsize=22)plt.show()

หากต้องการเอาผลลัพธ์มาแยกใน datafram ก็ทำได้ดังนี้





# Extract the Components — — # Actual Values = Product of (Seasonal * Trend * Resid) df_reconstructed = pd.concat([result_mul.seasonal, result_mul.trend, result_mul.resid, result_mul.observed], axis=1) df_reconstructed.columns = [‘seas’, ‘trend’, ‘resid’, ‘actual_values’] df_reconstructed.head()

ผลรวมของ seas , trend and resid จะเท่ากับ actual_values .

Stationary and Non-Stationary Time Series

Stationarity เป็นคุณสมบัติของอนุกรมเวลา อนุกรมที่อยู่กับที่นั้นเป็นค่าที่ค่าของอนุกรมไม่ใช่ฟังก์ชันของเวลา

นั่นคือคุณสมบัติทางสถิติของข้อมูลเช่นค่าเฉลี่ยความแปรปรวนและความสัมพันธ์อัตโนมัติมีค่าคงที่เมื่อเวลาผ่านไป Autocorrelation ของซีรี่ย์นั้นไม่มีอะไรนอกจากความสัมพันธ์ของซีรี่ย์กับค่าก่อนหน้านี้

ดังนั้นวิธีการระบุว่าชุดอยู่กับที่หรือไม่? ลองพล็อตตัวอย่างเพื่อทำให้ชัดเจน

วิธีการพยากรณ์ทางสถิติส่วนใหญ่ออกแบบมาเพื่อทำงานกับอนุกรมเวลาแบบ non-stationary ขั้นตอนแรกในกระบวนการคาดการณ์คือโดยทั่วไปแล้วจะทำการแปลงบางอย่างเพื่อแปลงข้อมูลให้เป็น stationary

วิธีสร้างข้อมูลอนุกรมเวลาแบบ stationary?

เราสามารถสร้าง stationary โดย:

ความแตกต่างของซีรี่ส์ (หนึ่งครั้งหรือมากกว่า)Differencing the Series (once or more) ใส่ Logarithm ในข้อมูล ใส่รากที่ n ให้ข้อมูล

วิธีที่นิยมใช้ในการแปลงข้อมูลอนุกรมเวลาให้เป็น time series โดย การดําเนินการหาผลต่างระหว่างช่วงเวลา ของข้อมูลอย่างน้อยหนึ่งครั้งจนกว่าจะกลายเป็นประมาณนิ่ง

ถ้า 𝑦𝑡 เป็นตัวแปรที่เราสนใจแล้ว first differencing ของ 𝑦𝑡 จะเท่ากับ 𝑦𝑡 − 𝑦𝑡−1 = 𝑦𝑡 − 𝐿𝑦𝑡 = (1 − 𝐿)𝑦𝑡

ตัวอย่างให้ข้อมูล: [1, 5, 2, 12, 20]

เราสามารถแปลงขั้นที่ 1: [5–1, 2–5, 12–2, 20–12] = [4, -3, 10, 8]

Seเราสามารถแปลงขั้นที่ 2: [-3–4, -10–3, 8–10] = [-7, -13, -2]

ทำใมต้องทำข้อมูลให้เป็น non-stationary series stationary ก่อนพยากรณ์?

การถดถอยเชิงเส้นจะเเม่นยำที่สุดเมื่อตัวแปร X ไม่สัมพันธ์กับตัวแปรเป้าหมาย ดังนั้นการแก้ปัญหาให้กับ stationary จะช่วยแก้ปัญหานี้ได้เนื่องจากจะลบความสัมพันธ์โดยธรรมชาติใดๆออกไป ทำให้ตัวแปรในการทำนายในแบบจำลองการพยากรณ์เป็นอิสระ

วิธีการทดสอบ stationary

วิธีทดสอบ stationary อาจทำง่ายๆด้วยการพล็อตกราฟ

อีกวิธีหนึ่งคือการแบ่งชุดข้อมูลออกเป็น 2 ส่วนหรือมากกว่านั้นและคำนวณสถิติสรุปเช่นค่าเฉลี่ยความแปรปรวนและค่าความสัมพันธ์อัตโนมัติ หากสถิติแตกต่างกันมากแสดงว่าซีรีส์ไม่น่าจะstationary

อย่างไรก็ตามคุณจำเป็นต้องมีวิธีในการพิจารณาเชิงปริมาณว่าชุดข้อมูล stationary หรือไม่ ซึ่งสามารถทำได้โดยใช้การทดสอบทางสถิติที่เรียกว่า ‘Unit Root Tests’ มีหลายรูปแบบของสิ่งนี้ซึ่งการทดสอบตรวจสอบว่าอนุกรมเวลาแบบ non-stationary และมี unit root

มีการทำสอบ Unit Root หลายวิธีเช่น

Augmented Dickey Fuller test (ADH Test) Kwiatkowski-Phillips-Schmidt-Shin — KPSS test (trend stationary) Philips Perron test (PP Test)

ที่ใช้กันมากที่สุดคือการทดสอบ ADF Test ที่สร้างสมมติฐาน null hypothesis ว่าข้อมูลเป็น non-stationary ดังนั้นถ้าค่าระดับนัยสำคัญ (0.05) เราจะปฏิเสธ null hypothesis

การทดสอบ KPSS นั้นใช้สำหรับทดสอบแนวโน้มstationary สมมติฐาน null hypothesis และการตีความค่า P เป็นค่าที่ตรงกันข้ามกับการทดสอบ ADH โค้ดด้านล่างใช้การทดสอบสองรายการนี้โดยใช้แพคเกจ statsmodels ด้วย Python



df = pd.read_csv('



# ADF Test

result = adfuller(df.value.values, autolag='AIC')

print(f'ADF Statistic: {result[0]}')

print(f'p-value: {result[1]}')

for key, value in result[4].items():

print('Critial Values:')

print(f' {key}, {value}')



# KPSS Test

result = kpss(df.value.values, regression='c')

print('

KPSS Statistic: %f' % result[0])

print('p-value: %f' % result[1])

for key, value in result[3].items():

print('Critial Values:')

print(f' {key}, {value}') from statsmodels.tsa.stattools import adfuller, kpssdf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'])# ADF Testresult = adfuller(df.value.values, autolag='AIC')print(f'ADF Statistic: {result[0]}')print(f'p-value: {result[1]}')for key, value in result[4].items():print('Critial Values:')print(f' {key}, {value}')# KPSS Testresult = kpss(df.value.values, regression='c')print('

KPSS Statistic: %f' % result[0])print('p-value: %f' % result[1])for key, value in result[3].items():print('Critial Values:')print(f' {key}, {value}')

การขจัดแนวโน้มออกจากชุดข้อมูลอนุกรณ์เวลา

การขจัดแนวโน้มออกจากชุดข้อมูลอนุกรณ์เวลา มีหลายวิธี

ลบเส้นแนวโน้มที่เหมาะสมที่สุดออกจากข้อมูลอนุกรมเวลา เส้นแนวโน้มที่เหมาะสมที่สุดหาได้จากแบบจำลองการถดถอยเชิงเส้นพร้อม ลบด้วยค่าเฉลี่ย ใช้วิธีการทางสถิติอื่นเช่น Baxter-King (statsmodels.tsa.filters.bkfilter) Hodrick-Prescott (statsmodels.tsa.filters.hpfilter) เพื่อลบเส้นค่าเฉลี่ยเคลื่อนที่หรือองค์ประกอบวัฏจักร



from scipy import signal

df = pd.read_csv('

detrended = signal.detrend(df.value.values)

plt.plot(detrended)

plt.title('Drug Sales detrended by subtracting the least squares fit', fontsize=16) # Using scipy: Subtract the line of best fitfrom scipy import signaldf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'])detrended = signal.detrend(df.value.values)plt.plot(detrended)plt.title('Drug Sales detrended by subtracting the least squares fit', fontsize=16)

from scipy import signal

df = pd.read_csv('

detrended = signal.detrend(df.value.values)

plt.plot(detrended)

plt.title('Drug Sales detrended by subtracting the least squares fit', fontsize=16) # Using scipy: Subtract the line of best fitfrom scipy import signaldf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'])detrended = signal.detrend(df.value.values)plt.plot(detrended)plt.title('Drug Sales detrended by subtracting the least squares fit', fontsize=16)

วิธีขจัดฤดูกาลออกจากข้อมูลอนุกรมเวลา

มีหลายวิธีในการขจัดฤดูกาลออกจากข้อมูลอนุกรมเวลา

ใช้ค่าเฉลี่ยเคลื่อนที่ ลบด้วยค่าของฤดูกาลก่อนหน้า แบ่งชุดข้อมูลด้วยดัชนีตามฤดูกาลที่ได้จากการแยก STL



df = pd.read_csv('



# Time Series Decomposition

result_mul = seasonal_decompose(df['value'], model='multiplicative', extrapolate_trend='freq')



# Deseasonalize

deseasonalized = df.value.values / result_mul.seasonal



# Plot

plt.plot(deseasonalized)

plt.title('Drug Sales Deseasonalized', fontsize=16)

plt.plot() # Subtracting the Trend Component.df = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'], index_col='date')# Time Series Decompositionresult_mul = seasonal_decompose(df['value'], model='multiplicative', extrapolate_trend='freq')# Deseasonalizedeseasonalized = df.value.values / result_mul.seasonal# Plotplt.plot(deseasonalized)plt.title('Drug Sales Deseasonalized', fontsize=16)plt.plot()

วิธีทดสอบฤดูกาลตามในข้อมูลอนุกรมเวลา

หากคเราต้องการการตรวจสอบฤดูกาลที่ชัดเจนยิ่งขึ้นให้ใช้พล็อต Autocorrelation Function (ACF) เพิ่มเติมเกี่ยวกับ ACF ในส่วนที่จะเกิดขึ้น แต่เมื่อมีรูปแบบตามฤดูกาลที่แข็งแกร่งพล็อต ACF มักจะแสดงให้เห็นถึงหนามแหลมที่ซ้ำแล้วซ้ำอีกที่ทวีคูณของหน้าต่างตามฤดูกาล



df = pd.read_csv('



# Draw Plot

plt.rcParams.update({'figure.figsize':(9,5), 'figure.dpi':120})

autocorrelation_plot(df.value.tolist()) from pandas.plotting import autocorrelation_plotdf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ')# Draw Plotplt.rcParams.update({'figure.figsize':(9,5), 'figure.dpi':120})autocorrelation_plot(df.value.tolist())

วิธีการจัดการกับค่าที่หายไปในอนุกรมเวลา?

ในบ้างครั้งข้อมูลที่เราได้มาอาจมีข้อมูลที่ขาดหายไป เรามีทางเลือกมากมายในการเติบค่าที่หายไปอาทิเช่น

Backward Fill

Linear Interpolation

Quadratic interpolation

Mean of nearest neighbors

Mean of seasonal couterparts

เราจะเลือกวิธีใหนนั้นขึ้นอยู่กัว่าเราต้องการความเชื่อมั่นในค่านั้นขนาดใหน

หากเรามีตัวแปรอธิบายให้ใช้แบบจำลองการทำนาย เช่นฟอเรสต์แบบสุ่มหรือเพื่อนบ้าน k- ที่ใกล้ที่สุดเพื่อทำนาย หากการสังเกตการณ์ในอดีตเพียงพอให้คาดการณ์ค่าที่หายไป หากมีข้อสังเกตในอนาคตมากพอให้ย้อนกลับค่าที่หายไป

การคาดการณ์ของคู่จากรอบก่อนหน้า

autocorrelation

Autocorrelation เป็นความสัมพันธ์ของชุดข้อมูลที่เกิดจากตัวข้อมูลเอง หากชุดข้อมูลมีความสัมพันธ์กันอย่างมีนัยสำคัญ นั่นหมายความว่าค่าก่อนหน้าของชุดข้อมูล อาจมีประโยชน์ในการทำนายค่าปัจจุบัน

การประเมินการพยากรณ์

ยิ่งมีรูปแบบเวลาปกติและทำซ้ำได้มากเท่าไหร่ก็ยิ่งง่ายต่อการคาดการณ์เท่านั้น ‘Entropimate Entropy’ สามารถใช้ในการกำหนดปริมาณความสม่ำเสมอและความไม่แน่นอนของความผันผวนในอนุกรมเวลา

ยิ่งค่าเอนโทรปีโดยประมาณสูงเท่าไหร่ก็ยากที่จะคาดการณ์ได้

https://en.wikipedia.org/wiki/Approximate_entropy

ss = pd.read_csv('

a10 = pd.read_csv('

rand_small = np.random.randint(0, 100, size=36)

rand_big = np.random.randint(0, 100, size=136)



def ApEn(U, m, r):

"""Compute Aproximate entropy"""

def _maxdist(x_i, x_j):

return max([abs(ua - va) for ua, va in zip(x_i, x_j)])



def _phi(m):

x = [[U[j] for j in range(i, i + m - 1 + 1)] for i in range(N - m + 1)]

C = [len([1 for x_j in x if _maxdist(x_i, x_j) <= r]) / (N - m + 1.0) for x_i in x]

return (N - m + 1.0)**(-1) * sum(np.log(C))



N = len(U)

return abs(_phi(m+1) - _phi(m))



print(ApEn(ss.value, m=2, r=0.2*np.std(ss.value))) # 0.651

print(ApEn(a10.value, m=2, r=0.2*np.std(a10.value))) # 0.537

print(ApEn(rand_small, m=2, r=0.2*np.std(rand_small))) # 0.143

print(ApEn(rand_big, m=2, r=0.2*np.std(rand_big))) # 0.716 ss = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/sunspotarea.csv ')a10 = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ')rand_small = np.random.randint(0, 100, size=36)rand_big = np.random.randint(0, 100, size=136)def ApEn(U, m, r):"""Compute Aproximate entropy"""def _maxdist(x_i, x_j):return max([abs(ua - va) for ua, va in zip(x_i, x_j)])def _phi(m):x = [[U[j] for j in range(i, i + m - 1 + 1)] for i in range(N - m + 1)]C = [len([1 for x_j in x if _maxdist(x_i, x_j) <= r]) / (N - m + 1.0) for x_i in x]return (N - m + 1.0)**(-1) * sum(np.log(C))N = len(U)return abs(_phi(m+1) - _phi(m))print(ApEn(ss.value, m=2, r=0.2*np.std(ss.value))) # 0.651print(ApEn(a10.value, m=2, r=0.2*np.std(a10.value))) # 0.537print(ApEn(rand_small, m=2, r=0.2*np.std(rand_small))) # 0.143print(ApEn(rand_big, m=2, r=0.2*np.std(rand_big))) # 0.716

การปรับค่าอนุกรมเวลาให้ราบเรียบ

การทำให้เรียบของอนุกรมเวลาอาจมีประโยชน์ใน: การลดเอฟเฟกต์ของการรบกวนในในการประมาณค่าวิธีการทำในการปรับค่าข้อมูลให้ราบเรียบ มีวิธีการต่อไปนี้:

ค่าเฉลี่ยเคลื่อนที่ ค่าเฉลี่ยเคลื่อนที่คือ ค่าเฉลี่ยของชุดข้อมูเป็นช่วงๆเช่น: 12 มักมีประโยชน์ในการเปรียบเทียบข้อมูลที่มีทั้งแนวโน้มและฤดูกา Localized Regression LOESS ย่อมาจาก ‘regression LOcalized’ เหมาะกับการถดถอยหลายจุดในพื้นที่ใกล้เคียงของแต่ละจุด. ถูกนำมาใช้ในแพคเกจ statsmodels ซึ่งสามารถควบคุมระดับของการปรับให้เรียบโดยใช้อาร์กิวเมนต์ frac ซึ่งระบุเปอร์เซ็นต์ของจุดข้อมูลในบริเวณใกล้เคียงที่ควรได้รับการพิจารณาว่าเหมาะสมกับแบบจำลองการถดถอย Locally Weighted Regression

from statsmodels.nonparametric.smoothers_lowess import lowess

plt.rcParams.update({'xtick.bottom' : False, 'axes.titlepad':5})



# Import

df_orig = pd.read_csv('datasets/elecequip.csv', parse_dates=['date'], index_col='date')



# 1. Moving Average

df_ma = df_orig.value.rolling(3, center=True, closed='both').mean()



# 2. Loess Smoothing (5% and 15%)

df_loess_5 = pd.DataFrame(lowess(df_orig.value, np.arange(len(df_orig.value)), frac=0.05)[:, 1], index=df_orig.index, columns=['value'])

df_loess_15 = pd.DataFrame(lowess(df_orig.value, np.arange(len(df_orig.value)), frac=0.15)[:, 1], index=df_orig.index, columns=['value'])



# Plot

fig, axes = plt.subplots(4,1, figsize=(7, 7), sharex=True, dpi=120)

df_orig['value'].plot(ax=axes[0], color='k', title='Original Series')

df_loess_5['value'].plot(ax=axes[1], title='Loess Smoothed 5%')

df_loess_15['value'].plot(ax=axes[2], title='Loess Smoothed 15%')

df_ma.plot(ax=axes[3], title='Moving Average (3)')

fig.suptitle('How to Smoothen a Time Series', y=0.95, fontsize=14)

plt.show()

การทดสอบความเป็นเหตุเป็นผลของ Granger

การทดสอบความเป็นเหตุเป็นผลของ Granger ใช้เพื่อพิจารณาว่าอนุกรมเวลาหนึ่งจะมีประโยชน์ในการคาดการณ์แบบอื่น

โดยมีแนวคิดที่ว่าถ้า X ทำให้ Y ดังนั้นการคาดการณ์ของ Y ตามค่าก่อนหน้าของ Y และค่าก่อนหน้าของ X ความเชื่อมั่นควรสูงกว่าการคาดการณ์ของ Y ตามค่าก่อนหน้าของ Y เพียงอย่างเดียว

ดังนั้นเข้าใจว่า Granger causality ไม่ควรใช้เพื่อทดสอบว่าความล่าช้าของ Y เป็นสาเหตุของ Y หรือไม่โดยทั่วไปจะใช้กับตัวแปรภายนอก (ไม่ใช่ Y lag) เท่านั้น

สมมติฐาน Null คือ: ซีรีส์ในคอลัมน์ที่สองไม่เกรนเจอร์ทำให้เกิดซีรีส์ในครั้งแรก หากค่า P-Value มีค่าน้อยกว่าระดับนัยสำคัญ (0.05) คุณก็จะปฏิเสธสมมติฐานว่างแล้วสรุปได้ว่าความล่าช้าของ X นั้นมีประโยชน์จริง ๆ

อาร์กิวเมนต์ที่สอง maxlag บอกว่าจนถึงจำนวน lags ของ Y ที่ควรรวมในการทดสอบ



df = pd.read_csv('

df['month'] = df.date.dt.month

grangercausalitytests(df[['value', 'month']], maxlag=2) from statsmodels.tsa.stattools import grangercausalitytestsdf = pd.read_csv(' https://raw.githubusercontent.com/selva86/datasets/master/a10.csv ', parse_dates=['date'])df['month'] = df.date.dt.monthgrangercausalitytests(df[['value', 'month']], maxlag=2)

ในกรณีข้างต้นค่า P เป็นศูนย์สำหรับการทดสอบทั้งหมด ดังนั้น ‘เดือน’ จึงสามารถใช้ในการคาดการณ์ผู้โดยสารได้

Note book

https://colab.research.google.com/drive/1dpkarE1ESU0Pe56cde4_yqt86BGhi-Yc

อ้างอิง