kaggleの雑記

ラグ特徴量の作り方3種類

ラグ特徴量とは

ラグ特徴量は時系列的に過去のデータの実績値を利用した特徴量です。

kaggleで勝つデータ分析の技術から学んだ手法を参考に、こちらの旅客機の乗客数データに対して、特徴量を付与していきます。

付与する特徴量は以下の3種類です。

  • 単純に過去のレコードの値をそのまま利用する
  • 移動平均を用いてい一定期間の情報の統計量をとる(平均だけではなく中央値・最大(小)値なども可能)
  • 過去全体からの累積をとる

実際のデータとコードと解説

データ

https://github.com/jinfagang/LSTM_learn/blob/master/international-airline-passengers.csv

今回はこちらのデータを利用しています。

月と乗客数の2カラムのデータです。

timepassengers
1949-01112
1949-02118
1949-03132
1949-04129

コード

import pandas as pd

date_parser = lambda date: pd.datetime.strptime(date, "%Y-%m") 
df = pd.read_csv("international-airline-passengers.csv", date_parser=date_parser, index_col=0)

# 数ヶ月前のデータを取得する
df["1month_ago"] = df[["passengers"]].shift(1)
df["2months_ago"] = df[["passengers"]].shift(2)
df["3months_ago"] = df[["passengers"]].shift(3)
df["last_year"] = df[["passengers"]].shift(12)

# 移動平均を取得する
df["rolling_mean_4months"] = df[["passengers"]].rolling(4).mean()

# 過去の全平均を取得する
df["expanding_mean"] = df[["passengers"]].expanding().mean()

単純に過去のレコードの値をそのまま利用する

# 数ヶ月前のデータを取得する
df["1month_ago"] = df[["passengers"]].shift(1)
df["2months_ago"] = df[["passengers"]].shift(2)
df["3months_ago"] = df[["passengers"]].shift(3)
df["last_year"] = df[["passengers"]].shift(12)

最も単純なラグ特徴量の取得方法はshiftです。これで時系列的に何期分過去のデータを取得します。何期が1日なのか1週間なのか1ヶ月なのかは、データのレコード同士の感覚に依存します。

移動平均を用いてい一定期間の情報の統計量をとる

df["rolling_mean_4months"] = df[["passengers"]].rolling(4).mean()

移動平均を取ることで任意の一定区間の情報を取得することができます。周期性を持っている場合でも、その周期幅を超える期間を指定することで、周期性に依存しない長期間での傾向を知ることができます。この期間をwindowと呼びます。

過去全体からの累積をとる

df["expanding_mean"] = df[["passengers"]].expanding().mean()

データ開始時点からの累積値もデータとして有効となる場合があります。kaggleで勝つデータ分析の技術ではお店を例に出してセールを行った回数を累積値として集計する例を出していました。

 

追記:移動平均rolling()から取得できるいくつかの特徴量

# required library
import numpy as np
import pandas as pd

# prepare data
train = pd.DataFrame()
time_features = []
windows = [3, 5, 10, 50, 100, 500, 1000]

# parameters
None


# create feautures
def calc_roll_stats(s, feature_name, windows=windows):
    '''
    Calculates rolling stats like mean, std, min, max...
    '''
    roll_stats = pd.DataFrame()
    for w in windows:
        roll_stats[feature_name + '_roll_mean_' + str(w)] = s.rolling(window=w, min_periods=1).mean()
        roll_stats[feature_name + '_roll_std_' + str(w)] = s.rolling(window=w, min_periods=1).std()
        roll_stats[feature_name + '_roll_min_' + str(w)] = s.rolling(window=w, min_periods=1).min()
        roll_stats[feature_name + '_roll_max_' + str(w)] = s.rolling(window=w, min_periods=1).max()
        roll_stats[feature_name + '_roll_range_' + str(w)] = roll_stats['roll_max_' + str(w)] - roll_stats['roll_min_' + str(w)]

        # 未来のデfeature_name + ー_タに利用できる時のみ
        roll_stats[feature_name + '_roll_mean_s_' + str(w)] = s.rolling(window=w, min_periods=1).mean().shift(-w)
        roll_stats[feature_name + '_roll_std_s_' + str(w)] = s.rolling(window=w, min_periods=1).std().shift(-w)
        roll_stats[feature_name + '_roll_min_s_' + str(w)] = s.rolling(window=w, min_periods=1).min().shift(-w)
        roll_stats[feature_name + '_roll_max_s_' + str(w)] = s.rolling(window=w, min_periods=1).max().shift(-w)
        roll_stats[feature_name + '_roll_range_s_' + str(w)] = roll_stats['roll_max_s_' + str(w)] - roll_stats['roll_min_s_' + str(w)]

        roll_stats[feature_name + '_roll_q10_' + str(w)] = s.rolling(window=w, min_periods=1).quantile(0.10).shift()
        roll_stats[feature_name + '_roll_q25_' + str(w)] = s.rolling(window=w, min_periods=1).quantile(0.25).shift()
        roll_stats[feature_name + '_roll_q50_' + str(w)] = s.rolling(window=w, min_periods=1).quantile(0.50).shift()
        roll_stats[feature_name + '_roll_q75_' + str(w)] = s.rolling(window=w, min_periods=1).quantile(0.75).shift()
        roll_stats[feature_name + '_roll_q90_' + str(w)] = s.rolling(window=w, min_periods=1).quantile(0.90).shift()

        roll_stats[feature_name + '_mean_abs_chg' + str(w)] = roll_stats.apply(lambda x: np.mean(np.abs(np.diff(x))))

    roll_stats = roll_stats.fillna(value=0)

    return roll_stats


for time_feature in time_features:
    target = train[time_feature]
    roll_stats = calc_roll_stats(target, time_feature, windows)
    train = pd.concat([train, roll_stats], axis=1)
    train[f'{time_feature}+1'] = [0, ] + list(train[time_feature].values[:-1])
    train[f'{time_feature}-1'] = list(train[time_feature].values[1:]) + [0]
ABOUT ME
hirayuki
今年で社会人3年目になります。 日々体当たりで仕事を覚えています。 テーマはIT・教育です。 少しでも技術に親しんでもらえるよう、noteで4コマ漫画も書いています。 https://note.mu/hirayuki