
【시계열 데이터 분석】 웹 유입량 데이터 분석
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from prophet import Prophet
%matplotlib inline
pinkwink_web = pd.read_csv(
"../data/05_PinkWink_Web_Traffic.csv",
encoding="utf-8",
thousands=",",
names=["date", "hit"],
index_col=0
)
pinkwink_web
pinkwink_web = pinkwink_web[pinkwink_web["hit"].notnull()]
pinkwink_web["hit"].plot(figsize=(12, 4), grid=True);

먼저 numpy를 이용해 trend를 따로 파악해 본다.
prophet 모듈이 어떤 방식으로 예측을 하는지 알 수 없으므로 numpy를 이용해 직접 경향성을 파악해 본다.
다항식 회귀(Polynomial Regression) 모델을 사용한다.
다항식 회귀는 다항식 함수를 사용하여 데이터를 근사하는 회귀 모델이다.
일반적으로 다항식은 다음과 같은 형태를 가진다.
trend 분석을 위한 x, y축 값을 생성한다.
time = np.arange(0, len(pinkwink_web))
traffic = pinkwink_web["hit"].values
trend 파악을 위한 다항식 회귀 함수를 생성한다.
np.polyfit() : 먼저 데이터에 적합한 다항식의 계수를 구한다.
np.poly1d() : 계수를 적용한 다항식을 생성한다.
다항식은 1차, 2차, 3차, 15차 함수까지 4개를 생성한다.
pf1 = np.polyfit(time, traffic, 1)
f1 = np.poly1d(pf1)
pf2 = np.polyfit(time, traffic, 2)
f2 = np.poly1d(pf2)
pf3 = np.polyfit(time, traffic, 3)
f3 = np.poly1d(pf3)
pf15 = np.polyfit(time, traffic, 15)
f15 = np.poly1d(pf15)
numpy로 만든 4종류의 trend 함수들과 실제 데이터를 그래프로 확인해 본다.
plt.figure(figsize=(14, 6))
plt.scatter(time, traffic, s=10)
plt.plot(fx, f1(fx), lw=3, label='f1')
plt.plot(fx, f2(fx), lw=3, label='f2')
plt.plot(fx, f3(fx), lw=3, label='f3')
plt.plot(fx, f15(fx), lw=4, label='f15')
plt.grid(True, linestyle="-", color="0.75")
plt.legend(loc=2)
plt.show()

👉 실제 데이터에 가장 잘 맞는 경향성은 f15로 보인다.
경향성 모델이 얼마나 정확한지 확인해줄 지표로 RMSE(rmse average, 제곱근오차평균)을 사용한다.
numpy로 계산한 경향성과 실제 데이터의 오차가 얼마인지 확인해줄 error 함수를 생성한다.
def error(f, x, y):
return np.sqrt(np.mean((f(x) - y) ** 2))
print(error(f1, time, traffic))
print(error(f2, time, traffic))
print(error(f3, time, traffic))
print(error(f15, time, traffic))
--> 430.85973081109626
--> 430.6284101894695
--> 429.5328046676293
--> 330.47773079342267
👉 error() 함수로 검증한 값도 f15의 오차값이 가장 작았다.
Prophet에 학습시킬 데이터프레임 형식으로 웹 유입량 데이터를 변형시켜 준다.
df = pd.DataFrame({
"ds": pinkwink_web.index,
"y": pinkwink_web["hit"]
})
df.reset_index(inplace=True)
del df["date"]
df["ds"] = pd.to_datetime(df["ds"], format="%y. %m. %d.")
Prophet으로 모델을 생성하고 학습시킨 후 미래 예측값을 얻어온다.
model = Prophet(yearly_seasonality=True, daily_seasonality=True)
model.fit(df);
future = model.make_future_dataframe(periods=60)
forecast = model.predict(future)
forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail()

model.plot(forecast);

• Prophet.plot_components() : 미래 예측 데이터를 포함해 경향을 분석해준다.
model.plot_components(forecast);

np.sqrt(np.mean((forecast["trend"]-df["y"])**2))
//--> 536.0321309635455
👉 Prophet이 분석한 경향은 실제 데이터 분포와 상당한 오차가 존재하는 편이다.
실제 데이터와 Numpy로 계산한 trend, Prophet으로 예측한 trend를 모두 함께 비교한다.
plt.figure(figsize=(14, 6))
plt.scatter(time, traffic, s=10)
plt.plot(fx, f1(fx), lw=4, label='Numpy Trend')
ptrend = forecast.loc[:364, "trend"].values
plt.plot(time, ptrend, lw=4, label='Prophet Trend')
plt.grid(True, linestyle="-", color="0.75")
plt.legend(loc=2)
plt.show()

👉 Prophet이 분석한 경향보다 Numpy로 계산한 경향이
실제 데이터 추세와 더 잘 맞아 보인다.