データの確認

データの中身を見る

import datetime
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

from scipy import stats
from statsmodels.tsa import stattools

データセットの読み込み

data = pd.read_csv("sample.csv")
data.head(10)
DateTemp
01981-01-0120.7
11981-01-0217.9
21981-01-0318.8
31981-01-0414.6
41981-01-0515.8
51981-01-0615.8
61981-01-0715.8
71981-01-0817.4
81981-01-0921.8
91981-01-1020.0

タイムスタンプをdatetimeにする

Date列は現在Object型、つまり文字列として読み込まれています。これをタイムスタンプとして扱うため、 datetime — 基本的な日付型および時間型を確認しつつ、datetime型に変換します。

data["Date"] = data["Date"].apply(
    lambda x: datetime.datetime.strptime(str(x), "%Y-%m-%d")
)

print(f"Date列のdtype: {data['Date'].dtype}")
Date列のdtype: datetime64[ns]

時系列の概要を確認する

pandas.DataFrame.describe

はじめに、データがどのようなものであるか簡単に確認します。 pandas.DataFrame.describeを使って、Temp列の簡単な統計量を確認します。

data.describe()
Temp
count3650.000000
mean11.177753
std4.071837
min0.000000
25%8.300000
50%11.000000
75%14.000000
max26.300000

折れ線グラフ

seaborn.lineplotを使って、どのような周期になっているか確認します。

plt.figure(figsize=(12, 6))
sns.lineplot(x=data["Date"], y=data["Temp"])
plt.ylabel("Temp")
plt.grid(axis="x")
plt.grid(axis="y", color="r", alpha=0.3)
plt.show()

png

ヒストグラム

plt.figure(figsize=(12, 6))
plt.hist(x=data["Temp"], rwidth=0.8)
plt.xlabel("Temp")
plt.ylabel("日数")
plt.grid(axis="y")
plt.show()

png

自己相関とコレログラム

pandas.plotting.autocorrelation_plotを用いて自己相関を確認し、時系列データの周期性をチェックします。

大雑把に言うと、自己相関とは、信号がそれ自身を時間シフトした信号とどれくらい一致するかを測る尺度であり、時間シフトの大きさの関数として表される。 引用元:wikipedia - 自己相関

plt.figure(figsize=(12, 6))
pd.plotting.autocorrelation_plot(data["Temp"])
plt.grid()
plt.axvline(x=365)
plt.xlabel("ラグ")
plt.ylabel("自己相関")
plt.show()

png

単位根検定

データが単位根過程であるかどうかを確認します。 単位根過程であることを帰無仮説とする検定(Augmented Dickey-Fuller test)を行います。

statsmodels.tsa.stattools.adfuller

stattools.adfuller(data["Temp"], autolag="AIC")
(-4.444804924611697,
 0.00024708263003610177,
 20,
 3629,
 {'1%': -3.4321532327220154,
  '5%': -2.862336767636517,
  '10%': -2.56719413172842},
 16642.822304301197)

トレンドの確認

1次元多項式を時系列にフィットさせてトレンドの線を引きます。今回のデータはほとんどトレンド定常に近いので、トレンドはほとんどありません。

numpy.poly1d — NumPy v1.22 Manual

def get_trend(timeseries, deg=3):
    """時系列データのトレンドの線を作成する

    Args:
        timeseries(pd.Series) : 時系列データ。

    Returns:
        pd.Series: トレンドに相当する時系列データ。
    """
    x = list(range(len(timeseries)))
    y = timeseries.values
    coef = np.polyfit(x, y, deg)
    trend = np.poly1d(coef)(x)
    return pd.Series(data=trend, index=timeseries.index)

data["Trend"] = get_trend(data["Temp"])

# グラフをプロット
plt.figure(figsize=(12, 6))
sns.lineplot(x=data["Date"], y=data["Temp"], alpha=0.5, label="Temp")
sns.lineplot(x=data["Date"], y=data["Trend"], label="トレンド")
plt.grid(axis="x")
plt.legend()
plt.show()

png

補足:トレンドがはっきりとある場合

data_sub = data.copy()
data_sub["Temp"] = (
    data_sub["Temp"] + np.log(data_sub["Date"].dt.year - 1980) * 10
)  # ダミーのトレンド
data_sub["Trend"] = get_trend(data_sub["Temp"])

# グラフをプロット
plt.figure(figsize=(12, 6))
sns.lineplot(x=data_sub["Date"], y=data_sub["Temp"], alpha=0.5, label="Temp")
sns.lineplot(x=data_sub["Date"], y=data_sub["Trend"], label="トレンド")
plt.grid(axis="x")
plt.legend()
plt.show()

png