시간 : 특정 간격 갖는 시간
-Lag 에서 Data의 Trend를 찾는다.
일변량 정상시계열
-ARIMA Model
Trend : 추세 - 데이터의 변화되어있는 모형
Seasonality : 계절성 - 주기에 따라 trend가 달라질수 있음. ex)특정주기별로 반복되는추세가 있거나
Cycle : 주기
Noise : 번역하면 잡음 이지만, 시간에 따라서 독립적인 데이터 _ 평균,분산이 변하는 않는 데이터 = White Noise = 분석가능변동데이터
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rc("font", family = "Malgun Gothic")
필요한 모듈을 import 해줍니다.
df1= pd.read_csv("C:/000/data11.csv")
데이터를 불러와 줍니다.
df1.info()
info() 함수로 data의 형태를 check해 줍니다.
df1.head()
구매일 구매금액 물품대분류
0 2018-04-20 57120 기저귀
1 2018-04-20 15900 더블하트
2 2018-04-20 7000 더블하트
3 2018-04-20 20900 더블하트
4 2018-05-06 26500 더블하트
head()함수로 data 위 5개를 살펴봅니다.
df1["Datetime"] = pd.to_datetime(df1["구매일"])
df1
구매일이 object 로 되어있기 때문에 dtype를 datetime 형태로 바꿔줍니다.
pd.todatetime()
구매일 구매금액 물품대분류 Datetime
0 2018-04-20 57120 기저귀 2018-04-20
1 2018-04-20 15900 더블하트 2018-04-20
2 2018-04-20 7000 더블하트 2018-04-20
3 2018-04-20 20900 더블하트 2018-04-20
4 2018-05-06 26500 더블하트 2018-05-06
... ... ... ... ...
803670 2020-08-06 30960 더블하트 2020-08-06
803671 2020-08-06 6640 더블하트 2020-08-06
803672 2020-08-06 5600 더블하트 2020-08-06
803673 2020-08-06 7840 더블하트 2020-08-06
803674 2020-08-06 8500 기타 2020-08-06
803675 rows × 4 columns
df1["Datetime"].describe()
count 803675
unique 589
top 2019-10-11 00:00:00
freq 10500
first 2018-04-20 00:00:00
last 2020-08-07 00:00:00
Name: Datetime, dtype: object
describe()를 볼때, data의 처음은 first,
data 마지막은 last,
data중 제일 많이 차지하는건 top
전체 data는 589일(unique) - 판매가 안된 날짜가 있ㄷ. ex)주말휴무
df1["year"] =df1["Datetime"].dt.year
df1["month"] =df1["Datetime"].dt.month
df1["week"] =df1["Datetime"].dt.week
df1["day_of_week"] =df1["Datetime"].dt.day_name()
연도,월,일 로 바꿔준다.
sns.lineplot(data=df1, x="Datetime", y="구매금액", estimator=sum)
data가 80만개라 lineplot 그리면 시간이 오래걸리니 피보팅을 하여 시리즈를 정리해주고,피보팅한 변수로 lineplot을 그려준다. 시간도 효율적이고 값도 똑같다.
# 일별 구매계산 합
p1 = pd.pivot_table(data=df1,
index="Datetime", values="구매금액", aggfunc="sum").reset_index()
p1
Datetime 구매금액
0 2018-04-20 100920
1 2018-05-06 26500
2 2018-05-14 20600
3 2018-08-12 75700
4 2018-09-01 48300
... ... ...
584 2020-08-03 27560340
585 2020-08-04 31832500
586 2020-08-05 27683180
587 2020-08-06 22574070
588 2020-08-07 12099370
589 rows × 2 columns
sns.lineplot(data=p1, x="Datetime", y="구매금액")
p2 = pd.pivot_table(data=df1,
index=["Datetime","물품대분류"], values="구매금액", aggfunc="sum").reset_index()
print(p2)
p2 를 출력해봅니다.
# 기저귀 data 만 따로 뽑아 분석
# 2018년에는 1개에 data 만 존재하고 2019부터 data가 존재하므로 빼는 것 이 낫다는 결론.
cond1 = (df1["물품대분류"] == "기저귀")
df1.loc[cond1]
구매일 구매금액 물품대분류 Datetime year month week day_of_week
0 2018-04-20 57120 기저귀 2018-04-20 2018 4 16 Friday
29 2019-05-13 59520 기저귀 2019-05-13 2019 5 20 Monday
30 2019-05-10 50640 기저귀 2019-05-10 2019 5 19 Friday
31 2019-06-06 50640 기저귀 2019-06-06 2019 6 23 Thursday
32 2019-07-01 50640 기저귀 2019-07-01 2019 7 27 Monday
... ... ... ... ... ... ... ... ...
803578 2020-06-25 43400 기저귀 2020-06-25 2020 6 26 Thursday
803602 2020-06-26 43400 기저귀 2020-06-26 2020 6 26 Friday
803610 2020-06-28 49900 기저귀 2020-06-28 2020 6 26 Sunday
803631 2020-07-09 49900 기저귀 2020-07-09 2020 7 28 Thursday
803632 2020-07-25 49900 기저귀 2020-07-25 2020 7 30 Saturday
df2 = df1.loc[cond1].iloc[1:]
df2.head()
구매일 구매금액 물품대분류 Datetime year month week day_of_week
29 2019-05-13 59520 기저귀 2019-05-13 2019 5 20 Monday
30 2019-05-10 50640 기저귀 2019-05-10 2019 5 19 Friday
31 2019-06-06 50640 기저귀 2019-06-06 2019 6 23 Thursday
32 2019-07-01 50640 기저귀 2019-07-01 2019 7 27 Monday
33 2019-07-29 101280 기저귀 2019-07-29 2019 7 31 Monday
- P 시점 전의 자료가 현재 시점의 데이터에 영향을 주는 자기회귀모델
- 자기상관함수 (ACF : Auto Correlation Function)
- p 구간 내 데이터 사이의 상관관계 (교회 - 범죄 - [인구])
- 부분자기상관함수 (PACF : Partial Auto Correlation Function) :
- 다른 시점의 데이터들의 영향을 제외한 두 관측치 사이의 상관관계 (교회
- 범죄 !- [인구])
- 일반적인 AR 모델에서는 ACF는 일정히 감소 / PACF가 절단면을 갖는다
- ACF와 PACF를 확인하여 분석 모델을 선택한다
- 일정한 p구간의 데이터들의 평균을 계산하여, 미래를 예측하는 방법
- 시계열의 불규칙적인 변동을 제거하기 위함
- 정상성(Stationary)을 만족하지 못하는 시계열 데이터를 정상성이 만족하는 데이 터로 변환
- AR만 사용하면 변동자료들의 설명이 떨어짐 그래서 MA(이동평균모델)을 같이 사용해 줍니다.
ARIMA Model (사용하기 위한 조건)
# ARIMA_model 을 쓸떄 사용하는 모듈
import statsmodels.tsa.api as tsa
df2.head()
df2의 head()를 찍어 봅니다.
df_time = pd.pivot_table(data=df2, index="Datetime",
values="구매금액", aggfunc="sum")
df_time.head()
구매금액
Datetime
2019-01-01 3051240
2019-01-02 2556280
2019-01-03 2729480
2019-01-04 2238440
2019-01-05 2478680
# df_time = pd.pivot_table(data=df2, index="Datetime",
# values="구매금액", aggfunc="sum").reset_index()
# df_time.head().set_index("Datetime")
# # 일주일 단위로 평균 금액을 계산해줌
# EX) 1Y, 1M, 1W, 1D
# y = df_time["구매금액"].resample("1W").mean()
# y
y = df_time["구매금액"].resample("1D").mean()
y
Datetime
2019-01-01 3051240.0
2019-01-02 2556280.0
2019-01-03 2729480.0
2019-01-04 2238440.0
2019-01-05 2478680.0
...
2020-08-03 3075900.0
2020-08-04 4010200.0
2020-08-05 2937800.0
2020-08-06 2647000.0
2020-08-07 1022300.0
Freq: D, Name: 구매금액, Length: 585, dtype: float64
이전자료를 대처값으로 채워줌(여기선 전날 data로 채워 줌)
# Missing 값이 있는 경우에
y1 = y.fillna( method="ffill")
y1.isnull().sum()
from pylab import rcParams
rcParams["figure.figsize"]= 13,10 #그래프의 SIZE를 조정해주는 함수
# #차트 기본 크기 설정
# mpl.rcParams['axes.labelsize'] = 14
# mpl.rcParams['xtick.labelsize'] = 12
# mpl.rcParams['ytick.labelsize'] = 12
# mpl.rcParams['text.color'] = 'k'
#시계열 모델 생성
model_series = tsa.seasonal_decompose(y1, model="additive")
#모델 시각화
fig = model_series.plot()
plt.show()
import itertools # 반복수를 만드는 라이브러리
p = d = q = range(0, 2)
pdq = list(itertools.product(p, d, q))
seasonal_pdq = [(x[0], x[1], x[2] , 12) for x in list(itertools.product(p, d, q))]
seasonal_pdq
seasonal_pdq를 출력해 봅니다.
[(0, 0, 0, 12),
(0, 0, 1, 12),
(0, 1, 0, 12),
(0, 1, 1, 12),
(1, 0, 0, 12),
(1, 0, 1, 12),
(1, 1, 0, 12),
(1, 1, 1, 12)]
param_list = []
param_seasonal_list = []
results_AIC_list = []
for param in pdq:
for param_seasonal in seasonal_pdq:
try:
mod = tsa.statespace.SARIMAX(y1, order=param,
seasonal_order= param_seasonal,
enforce_stationarity=False,
enforce_invertibility=False)
results = mod.fit()
param_list.append(param)
param_seasonal_list.append(param_seasonal)
results_AIC_list.append(results.aic)
except:
continue
ARIMA_list = pd.DataFrame({'Parameter':param_list,'Seasonal':param_seasonal_list,'AIC':results_AIC_list})
ARIMA_list.to_excel('arima_model_list.xlsx')
mod = tsa.statespace.SARIMAX(y1,order=(0, 1, 1),seasonal_order=(0, 1, 1, 12),
enforce_stationarity=False, enforce_invertibility=False)
results = mod.fit()
print(results.summary())
mod = tsa.statespace.SARIMAX(y1,order=(0, 1, 1),seasonal_order=(0, 1, 1, 12),
enforce_stationarity=False, enforce_invertibility=False)
results = mod.fit()
print(results.summary())
mod = tsa.statespace.SARIMAX(y1,order=(0, 1, 1),seasonal_order=(0, 1, 1, 12),
enforce_stationarity=False, enforce_invertibility=False)
results = mod.fit()
print(results.summary())
SARIMAX Results
==========================================================================================
Dep. Variable: 구매금액 No. Observations: 585
Model: SARIMAX(0, 1, 1)x(0, 1, 1, 12) Log Likelihood -9521.297
Date: Wed, 22 Sep 2021 AIC 19048.594
Time: 14:34:08 BIC 19061.567
Sample: 01-01-2019 HQIC 19053.660
- 08-07-2020
coef std err z P>|z| [0.025 0.975]
ma.L1 -0.0721 0.063 -1.137 0.256 -0.196 0.052
ma.S.L12 -0.9948 0.022 -45.508 0.000 -1.038 -0.952
Ljung-Box (L1) (Q): 0.21 Jarque-Bera (JB): 324.63
Prob(Q): 0.65 Prob(JB): 0.00
Heteroskedasticity (H): 0.42 Skew: 0.31
Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
[2] Covariance matrix is singular or near-singular, with condition number 9.18e+43. Standard errors may be unstable.
p : AR에서의 p값 (p 구간 내 데이터 사이의 상관관계)
d : 차분
q : q MA PACF 편상관계수 q 값
P
D
Q
M
Ljung - Box Test : 일정 기간동안 관측치가 랜덤이고, 독립적인지 여부를 검정
귀무 : 데이터가 상관관계를 나타내지 않는다.
대립 : 데이터가 상관관계를 나타낸다.
P.value(귀무가설이 참일 확률) < 0.05 (유의수준) -> 대립가설 참
Jarque Bera Test : 왜도와 첨도가 정규분포와 일치하는지 가설검정
SARIMAX : 잔차의 분포가 정규분포 인가
귀무 가설 : 해당 잔차(residual)는 정규분포와 일치한다.
대립 가설 : 해당 잔차(residual)는 정규분포와 일치하지 않는다.
P.value < 0.05 , 해당 잔차(residual)는 정규분포와 일치하지 않는다.
results.plot_diagnostics(figsize=(16, 8))
plt.show()
results.get_prediction()
<statsmodels.tsa.statespace.mlemodel.PredictionResultsWrapper at 0x202851c0700>