K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

tsfresh

中級

04.14.4

tsfresh

最終更新 2020-02-26 読了時間 4 分
まとめ
時系列をそのまま分類や回帰モデルに渡すことはできないので、1 本の系列を「平均・分散・最大値・自己相関・FFT 係数…」といった数値の束に要約して 1 行にする作業が必要です。tsfresh はこの要約を 700 種類以上の計算式で一括実行するライブラリで、extract_features(X, column_id="id", column_sort="time") の 1 行で済みます。このページでは id と time と 4 本の値列(fx1〜fx4)を持つ長い形式の DataFrame を人工的に作り、100 本の系列から 3,156 列の特徴量が生成されることを確かめます。できた表は scikit-learn のモデルにそのまま渡せ、tsfresh.feature_selection で目的変数と関係のある列だけに絞ることもできます。

直感 #

100 台のセンサーから 10 日分ずつの温度が届いたとして、「どのセンサーが故障しかけているか」を分類したいとします。10 日分の数値 10 個をそのまま特徴量にすると、1 日ずれただけで別の値になり、長さの違う系列も扱えません。代わりに「平均 23.1、最大 27.5、1 日前との自己相関 0.8、変化の絶対値の平均 0.4」のように要約すれば、長さに関係なく 1 行で表せます。tsfresh はこの要約を人手で考えません。統計量・周波数・エントロピーなど数百種類の計算式を全列に当て、後で select_features で選別する前提で「とりあえず全部」作ります。

時系列データを扱うとき、タイムスタンプと数値の列をもとにさまざまな特徴量を計算することがあります。このページでは tsfresh を用いて時系列データから特徴量を計算してみます。

tsfresh #

Overview on extracted featuresを参考に、どんな特徴量が作成されるか確認してみます。まず、tsfresh が要求する「長い形式」(1 行が 1 時点、id 列で系列を区別、time 列で順序を示す)の DataFrame を人工的に作ります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tsfresh import extract_features

X = []
for id, it in enumerate(np.linspace(0.1, 100, 100)):
    for jt in range(10):
        X.append(
            [
                id,
                jt,
                jt + np.sin(it),
                jt % 2 + np.cos(it),
                jt % 3 + np.tan(it),
                np.log(it + jt),
            ]
        )

X = pd.DataFrame(X)
X.columns = ["id", "time", "fx1", "fx2", "fx3", "fx4"]
X.head()

idtimefx1fx2fx3fx4
0000.0998330.9950040.100335-2.302585
1011.0998331.9950041.1003350.095310
2022.0998330.9950042.1003350.741937
3033.0998331.9950040.1003351.131402
4044.0998330.9950041.1003351.410987

id == 3 の系列だけを取り出し、4 本の値列を縦に並べて形を確かめます。

1
2
X[X["id"] == 3].plot(subplots=True, sharex=True, figsize=(12, 10))
plt.show()

tsfreshの図

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:DTW は時間を伸び縮みさせて形を合わせる。タイミングがずれた似た波形を「近い」と判定できる。

特徴量を計算する #

extract_features を使って、一気にすべての特徴量を計算することができます。1,000 行の入力が 100 行 × 3,156 列の表になり、1 行が 1 本の系列に対応します。tsfresh.feature_selection 以下の関数を用いることで、目的変数と統計的に関係のある列だけに絞る特徴選択も実行できます。

1
2
extracted_features = extract_features(X, column_id="id", column_sort="time")
extracted_features.head()
Feature Extraction: 100%|█

fx1__variance_larger_than_standard_deviationfx1__has_duplicate_maxfx1__has_duplicate_minfx1__has_duplicatefx1__sum_valuesfx1__abs_energyfx1__mean_abs_changefx1__mean_changefx1__mean_second_derivative_centralfx1__median...fx4__permutation_entropy__dimension_6__tau_1fx4__permutation_entropy__dimension_7__tau_1fx4__query_similarity_count__query_None__threshold_0.0fx4__matrix_profile__feature_"min"__threshold_0.98fx4__matrix_profile__feature_"max"__threshold_0.98fx4__matrix_profile__feature_"mean"__threshold_0.98fx4__matrix_profile__feature_"median"__threshold_0.98fx4__matrix_profile__feature_"25"__threshold_0.98fx4__matrix_profile__feature_"75"__threshold_0.98fx4__mean_n_absolute_max__number_of_maxima_7
01.00.00.00.045.998334294.0846751.01.0-3.469447e-184.599833...-0.0-0.0NaNNaNNaNNaNNaNNaNNaN1.915905
11.00.00.00.053.952941373.5919821.01.0-6.938894e-185.395294...-0.0-0.0NaNNaNNaNNaNNaNNaNNaN1.918724
21.00.00.00.053.538882369.1411861.01.00.000000e+005.353888...-0.0-0.0NaNNaNNaNNaNNaNNaNNaN2.062001
31.00.00.00.045.143194286.2908001.01.0-8.673617e-194.514319...-0.0-0.0NaNNaNNaNNaNNaNNaNNaN2.186180
41.00.00.00.036.613658216.5559921.01.00.000000e+003.661366...-0.0-0.0NaNNaNNaNNaNNaNNaNNaN2.295964

5 rows × 3156 columns

使いどころと落とし穴 #

3,156 列のうち大半は目的変数と無関係か、互いにほぼ同じ情報を持つ列です。分類や回帰に使う前に select_features(extracted_features, y) で仮説検定に基づく選別をかけるか、extract_relevant_features(X, y, column_id="id", column_sort="time") で抽出と選別を一度に済ませます。列数が系列数(この例では 100)を大きく超える状態でそのまま木モデルや線形モデルに渡すと過学習しやすいので、選別後の列数を確認してから学習に進みます。計算時間は値列数 × 系列数 × 特徴量数に比例するため、最初は MinimalFCParameters() で流れを確認し、効果が見えたら既定の設定に広げるのが安全です。長さが 10 程度の短い系列では、表の右側のように NaN になる特徴量が多く出るので、impute で埋めてから使います。