5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CRFモデルで時系列データからある時点の状態を推定する

Last updated at Posted at 2021-01-23

これを読んで得られること

  • CRF(条件付き確率場)を用いた時系列データの分類
    • 自分のためにまとめておこうというモチベーション
    • まとめているうちに自分の中で整理されてきて、記事にするほどじゃないよねという気になっている

これを読んでも書いていないこと

  • 自然言語のCRFによる分類の方法
    • 各ライブラリにあるチュートリアルが詳しいのでそちらへ
  • CRFの詳細説明
    • これも大学の講義資料とか書籍とかたくさん詳しい方がいらっしゃるのでそちらへ...

より正確にはCRFに入れる前に分布を仮定して離散化プロセスが必要です。

CRFとは

深層学習がはやる前に流行っていた教師あり学習のひとつ。例えば、文章中の固有表現の抽出といった系列に対するラベルの付与(系列ラベリング)問題を解く際に適用される。

系列ラベリング

  • 系列ラベリング
    • 系列に対してラベルを付与するもの
      • 隠れマルコフモデル(HMM)やCRFや深層学習のLSTMがある
  • 系列データ
    • 自然言語処理や時系列データ(前後関係がある)
    • 画像(周辺情報も大事)
  • ラベリング
    • 自然言語処理は分類で何かを分類すること(MeCabで形態素解析するとか)
    • 時系列データの場合は回帰で今の時点から次の時点を予測すること
    • 画像のピクセル毎の分類(セマンティックセグメンテーション)

今回やりたいことは、時系列データを用いてある時点での挙動を分類すること。
例えば、人の速度と歩数から歩いているか、走っているか、自転車に乗っているかといった推定をしたり、心臓の周波数データから緊張しているとかリラックスしているとかを推定すること。

HMMやCRFの関係性をまとめると次のような図となる。(日本語を付した。一部意訳。)
relationship_diagram_HMM_CRF.png
(引用: An Introduction to Conditional Random Fields https://arxiv.org/abs/1011.4088

CRFとは

  • マルコフ確率場の一種
    • マルコフ確率場とは依存関係を無向グラフで表すもの(上図の下段)
  • 学習で最大化する対象
    • 設計する事後確率
  • 教師あり学習

実装手順

ライブラリ候補

  • PyStruct
  • CRFSuite
  • sklearn_crfsuite

sklearn_crfsuiteはCRFSuiteのラッパーでsklearnのモデルセレクションのパッケージが利用できるようになっている。つまりはハイパーパラメーターチューニングが楽。なので今回はsklearn-crfsuiteを用いる。ちなみに線形連鎖条件付き確率場を実現しているライブラリである。

実装ステップ

  1. データを集める
  2. データを学習データとテストデータに分割する train_test_split
  3. 学習データとテストデータを整形する
  4. 系列データに分割する for文を用いて切ったりくっつけたり
  5. CRFのモデルを決めるsklearn_crfsuite.CRF()で最適化アルゴリズムを設定したり
  6. 学習データを学習させる crf.fit(X_train, y_train)
  7. テストデータで推論する crf.predict(X_test)
  8. テストデータの正解率を確認する metrics.flat_classification_report() recallとかもこれ
  9. ハイパーパラメータのチューニング RandomizedSearchCV
  10. ハイパーパラメーターと正解のスコアのばらつきを可視化

手順は公式チュートリアルを見ながら時系列データに応用
https://sklearn-crfsuite.readthedocs.io/en/latest/tutorial.html

1. データを集める

今回は気象庁の気温と気圧から天気を予測する。
2020年1月1日から2021年1月22日までの3時間毎の気温と気圧と天気をお借りした。
https://www.data.jma.go.jp/gmd/risk/obsdl/index.php

df = pd.read_csv('202001data.csv', encoding='shift-jis', skiprows=3)
df = df.append(pd.read_csv('202004data.csv', encoding='shift-jis', skiprows=3))
df = df.append(pd.read_csv('202007data.csv', encoding='shift-jis', skiprows=3))
df = df.append(pd.read_csv('202010data.csv', encoding='shift-jis', skiprows=3))
df.columns = ['datetime', 'temparature', 'weather', 'pressure']
df = df[['datetime', 'temparature', 'pressure', 'weather']]
df = df.dropna(how='any')
df = df.reset_index(drop = True)
データの外観

2. データを学習データとテストデータに分割する

X_df = df[['temparature', 'pressure']]
y_s = df['weather']
X_train, X_test, y_train, y_test = train_test_split(X_df, y_s, random_state=0)

3. 学習データとテストデータを整形する

入力データはdictionary型にする。

X_train = X_train.to_dict(orient='records')
X_test = X_test.to_dict(orient='records')

正解ラベルはリスト型

y_train = y_train.to_list()
y_test = y_test.to_list()

4. 系列データに分割する

全データを等間隔のwindow幅を持つ系列データに整形する。
これは辞書型の集合の配列とする。
学習データとテストデータは[[{}{}{}], [{}{}{}], [{}{}{}]]こんなイメージ。
正解ラベルは[[], [], []]こんなイメージ。

from_i = 0
step = 10 # window幅
to_i = len(X_train) - step

X_trains = []
for i in range(from_i, to_i, step):
    X_trains.append(X_train[i:i+step])

y_trains = []
for i in range(from_i, to_i, step):
    y_trains.append(y_train[i:i+step])

to_i = len(X_test) - step
X_tests = []
for i in range(from_i, to_i, step):
    X_tests.append(X_test[i:i+step])

y_tests = []
for i in range(from_i, to_i, step):
    y_tests.append(y_test[i:i+step])

5. CRFのモデルを決める

crf = sklearn_crfsuite.CRF(
    algorithm='lbfgs',
    c1=0.1,
    c2=0.1,
    max_iterations=100,
    all_possible_transitions=True
)

6. 学習データを学習させる

crf.fit(X_trains, y_trains)

7. テストデータで推論する

labels = list(crf.classes_)
y_pred = crf.predict(X_tests)
metrics.flat_f1_score(y_tests, y_pred, 
                      average='weighted', labels=labels)

8. テストデータの正解率を確認する

sorted_labels = sorted(
    labels, 
    key=lambda x: (x[1:], x[0])
)
print(metrics.flat_classification_report(
    y_tests, y_pred, labels=sorted_labels, digits=3
))
精度結果

9. ハイパーパラメータのチューニング

# define fixed parameters and parameters to search
crf = sklearn_crfsuite.CRF(
    algorithm='lbfgs', 
    max_iterations=100, 
    all_possible_transitions=True
)
params_space = {
    'c1': scipy.stats.expon(scale=0.5),
    'c2': scipy.stats.expon(scale=0.05),
}

# use the same metric for evaluation
f1_scorer = make_scorer(metrics.flat_f1_score, 
                        average='weighted', labels=labels)

# search
rs = RandomizedSearchCV(crf, params_space, 
                        cv=2, 
                        verbose=1, 
                        n_jobs=-1, 
                        n_iter=50, 
                        scoring=f1_scorer)
rs.fit(X_trains, y_trains)

10. ハイパーパラメーターと正解のスコアのばらつきを可視化

_x = [s['c1'] for s in rs.cv_results_['params']]
_y = [s['c2'] for s in rs.cv_results_['params']]
_c = [s for s in rs.cv_results_['mean_test_score']]

fig = plt.figure()
fig.set_size_inches(6, 6)
ax = plt.gca()
ax.set_yscale('log')
ax.set_xscale('log')
ax.set_xlabel('C1')
ax.set_ylabel('C2')
ax.set_title("Randomized Hyperparameter Search CV Results (min={:0.3}, max={:0.3})".format(
    min(_c), max(_c)
))

ax.scatter(_x, _y, c=_c, s=60, alpha=0.9)

print("Dark blue => {:0.4}, dark red => {:0.4}".format(min(_c), max(_c)))
結果

結果より気温と気圧だけでは最大で28%の予測精度であった。
つまり気温と気圧からCRFで天候を予測することは難しい。
本記事の目的としては予測精度を上げることではなく、CRFで時系列データのある点の予測を行うことである。

何かありましたらコメントいただけると幸いです。

参考ページ

sklearn-crfsuite
https://sklearn-crfsuite.readthedocs.io/en/latest/index.html

Using CRF in Python
http://acepor.github.io/2017/03/06/CRF-Python/

An Introduction to Conditional Random Fields
https://arxiv.org/abs/1011.4088

5
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?