1 of 67

Toshiki Haraguchi

2022/11/18

2 of 67

はじめに

本ハンズオンはできるだけ初心者の方が分かり易いように心がけています 

どうしても足りない部分などがあるかもしれません。

などを並行して読んでいただくとかなり理解が捗ると思います!

合わせて、わからないところがあれば いつでも お声がけください

ではスタートです!!

3 of 67

目次

  1. テーブルデータとは?
  2. データの前処理
  3. データの確認
  4. Catboostで学習
  5. 特徴エンジニアリングにチャレンジ!

4 of 67

テーブルデータとは?

5 of 67

テーブルデータとは何ぞや?

テーブルデータ

Excel

みたいにいい感じにまとまっているデータ

これはテーブルデータ

間違ってもこんな使い方はしちゃだめだよ

データベースみたいなのをイメージすると分かり易い

6 of 67

テーブルデータの利点

利点

  • パット見てまとまっているのでいろいろしやすい

Excelだとグラフ書いたりできるし

  • 関係性を見ることもできる

これとこれよく同時に出てるなーとか

今回のハンズオン

テーブルデータを使ってAIの構築に取り組みます!

何を予測できるAIを作る・・・?

7 of 67

今回扱うテーブルデータ

テーブルデータの種類

中古マンション価格のテーブルデータ

のデータから

予測できるようなAIを構築するのが今回の趣旨

その過程で様々なことを学んでいきましょう!

8 of 67

前処理とは?

9 of 67

前処理ってなんでんねん!

前処理とは?

生データを扱いやすいデータに手直しする作業

生データ

使えないデータやいらないデータがたくさん存在

そのまま使うのは無駄が多すぎる・・・

できるだけ扱いやすいデータに変換して解析を行う

この作業を前処理といいます!

どうやって前処理する?

ライブラリ「Pandas」に頼み込みまくる

データサイエンス3種の神器

10 of 67

三種の神器「Pandas」

Pandasってなに?

と同じことをPythonで簡単にできるようにするライブラリ

  • 列の計算
  • 四則演算
  • 統計
  • グラフの描画

など

Pandasを制するものは

データサイエンスを制する

11 of 67

今回の前処理方針

今回実施する前処理

  1. そもそもデータを使える形にする

ばらばらのデータがあってもどうしようもないですよね・・・

せめて全体を見れるように合体させましょう

2. いらないデータを消す

ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!

3. 各カラムをきれいにする

機械が認識しにくいものを変換してきれいにしましょう!

こうすることでAIも喜びます(?)

12 of 67

今回の前処理方針

今回実施する前処理

  1. そもそもデータを使える形にする

ばらばらのデータがあってもどうしようもないですよね・・・

せめて全体を見れるように合体させましょう

2. いらないデータを消す

ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!

3. 各カラムをきれいにする

機械が認識しにくいものを変換してきれいにしましょう!

こうすることでAIも喜びます(?)

13 of 67

データを使える形にする

Pandasで読み込んだデータを

DataFrame といいます

まずはデータがどんな形をしているか確認

import pandas as pd

# データを読み込んでいる

df = pd.read_csv("./train/01.csv")

# データを表示する

df.head()

14 of 67

データを使える形にする

今選択したデータ

一番上のデータのみ

全データのごく一部のみ

全部使えるように!

import os

import glob

#train内のすべてのデータのパスを取得

data_list = glob.glob(os.path.join("./train/", "*"))�# 読み込んだDataFrameを保存するリスト

df_list = []�# パスをひとつづつ取り出す

for path in data_list:

    # データを放り込む

    df_list.append(pd.read_csv(path))�# 縦方向に連結

df = pd.concat(df_list)�# 描画

df.reset_index(drop=True, inplace=True)

df

15 of 67

今回の前処理方針

今回実施する前処理

  1. そもそもデータを使える形にする

ばらばらのデータがあってもどうしようもないですよね・・・

せめて全体を見れるように合体させましょう

2. いらないデータを消す

ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!

3. 各カラムをきれいにする

機械が認識しにくいものを変換してきれいにしましょう!

こうすることでAIも喜びます(?)

16 of 67

いらないデータを消す

データが読み込めた! ・・・けどこれじゃうまく解析できないよぉ・・・。

次は何をするの?

次は使えそうなデータを抽出しましょう!

言い換えると 使えないデータを消しましょう

使えないデータとは?

  • 全データで欠損が激しい列

  • 中古価格予測に関係のない列(IDなど)

予測に使えなさそうなものを消す

17 of 67

何がゴミなのか確認する

  • df.isna():欠損値かどうか判定
  • df.index:dfのindexリスト

していること

データ全体に対しての欠損割合の算出

欠損値が9割以上を使い物にならないと仮定すると

地域・土地の形状・間口・延床面積・前面道路・取引の事情など

計8種類のデータが使えないことが判明!

使えないデータを削除

nan_data = df.isna().sum()/len(df.index)

nan_data

18 of 67

使えないデータを削除

削除対象

残った

カラム

# 欠損率0.9以上を除外対象にする

delete_rate = 0.9

# いらないカラムを登録するリスト

delete_list = []

# 各カラム検証

for key in nan_data.keys():

    # もし欠損率が0.9以上なら

    if nan_data[key] >=delete_rate:

        # 削除リストに入れる

        delete_list.append(key)

delete_list

delete_rate=0.9は完全に適当

本当はこの値も試行錯誤が必要

# 削除

df = df.drop(delete_list,axis = 1)

# 残ったカラムを確認

df.columns

df.drop:指定した行/列を削除できる

19 of 67

いったん完成

とりあえず扱いやすいデータが完成しました!

続いてデータをきれいにしていきましょう!

20 of 67

今回の前処理方針

今回実施する前処理

  1. そもそもデータを使える形にする

ばらばらのデータがあってもどうしようもないですよね・・・

せめて全体を見れるように合体させましょう

2. いらないデータを消す

ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!

3. 各カラムをきれいにする

機械が認識しにくいものを変換してきれいにしましょう!

こうすることでAIも喜びます(?)

21 of 67

データをきれいにするとは?

最寄駅:距離(分)を例に

想定

最寄駅からの距離(分)

この行は数字で構成されているはず

実際

NaN (Not a Numer) や 文字列(30分?60分)等想定しないものがある

問題:機械学習時にうまく読み込めない

予想外のデータをきれいにする必要がある

クレンジングという

数値や思たら違うやーん

22 of 67

どういう基準できれいにする?

データにはざっくり二種類

順序に意味がるもの

順序に意味がいもの

例)順位・日時・大きさ など

きれいにする方法:順序を統一するように変換(単位を揃える、西暦に直すなど)

きれいにする方法:数値としてラベル付けする等

例)食べ物の種類・性別・向きなど

大小関係がはっきりとわかるように

23 of 67

最寄駅:距離(分)をきれいにしてみる

よく見ると数値のはずなのに文字列ですね?

ここも一緒に直しましょう!

変換の方針

  • 文字列を数値に変換する → 順序として扱うため
  • 「2H?」は120に変換 → とりあえず書いてあることを信じる
  • ○?●?は間をとる → 大体平均しとけば大丈夫だろ論

これは1例!

df["最寄駅:距離(分)"].unique()

24 of 67

最寄駅:距離(分)をきれいにしてみる

列に一度に変換を掛ける場合はapply()を使います!

25 of 67

続いて建築年をきれいに

機械は昭和平成のどちらが新しいか分からない

西暦に統一して順序が分かりやすく

26 of 67

続いて建築年をきれいに

建築年の大小関係がすっきりと分かりやすくなった!

27 of 67

最後に取引時点

取引時点は何が問題?

2019年第3四半期

連続値っぽい

第3四半期ってどれ?

全部を数値で表せていない

カテゴリだと判断される

順序に意味がないとみなされる

変換方針

四半期

1年の1/4 0.25なので、0.25×(第n - 1)で変換

2019年第3四半期

2019 + 0.25×(3 - 1) = 2019.5 のような感じ

連続値で表せるので分かりやすい

28 of 67

最後に取引時点

曖昧な四半期を小数以下に収めることで

扱いやすいデータに!

29 of 67

いったん完成

とりあえずデータが完成しました!続いてどんなデータなのか見てみましょう!

データをよく見たものだけが勝利を手にすることができるのです・・・!

30 of 67

データの確認

31 of 67

いったん完成

今回はピックアップした赤枠の変数と、青枠がどういう関係を持つのかを見たいと思います

32 of 67

都道府県と取引価格

都道府県と取引価格の関係性

カテゴリ別で情報を知りたいとき

GroupBy」実行する

集約する

都道府県の場合は・・・

各都道府県の

平均取引を知りたい!

GroupByを実行

その県の取引平均を見れる

33 of 67

都道府県と取引価格

では実践

df[["都道府県名", "取引価格(総額)_log"]].groupby("都道府県名").mean().sort_values("取引価格(総額)_log",ascending=False)

カラムの指定(なくても可)

都道府県名で集約取る

平均で

降順でソートするよ

結果

東京・神奈川・大阪等都会は取引価格が高いことが分かった

常識がそのまま反映されている

都道府県は取引価格をよく説明できるといえる

機械学習に用いると精度が向上する

34 of 67

改装と取引価格

改装すると取引価格が上がるのでしょうか?

df[[“改装”, “取引価格(総額)_log”]].groupby("改装").mean().sort_values("取引価格(総額)_log",ascending=False)

カラムの指定(なくても可)

改装で集約取る

平均で

降順でソートするよ

改装してもしなくてもあまり価格には影響が無いようです

結果

何か腑に落ちないような・・・

予測に用いても精度向上に寄与しない可能性あり

35 of 67

建築年と取引価格

建築年と取引価格に関係性はあるのでしょうか?

df[[“建築年”, “取引価格(総額)_log”]].groupby(“建築年").mean().sort_values("取引価格(総額)_log",ascending=False)

結果

これだけだと分かりづらい・・・。どうなっている?

数値列データの集計結果

グラフにプロットすることも重要

可視化という

36 of 67

建築年と取引価格

可視化してみる

年代ごとに上昇していることが一目瞭然

これが可視化を勧める理由

これ一つでいろいろ読み取れる

赤丸:バブル崩壊があったであろう期間

緑丸:リーマンショックの影響であろう期間

など

37 of 67

面積と取引価格

面積と距離!

駅までの時間と取引価格

何らかの関係がありそう!

38 of 67

そのほかは?

今までのハンズオンを基にほかのグラフを描画してみましょう!

何が分かるかな?

39 of 67

いざ学習!

やはり

CatBoostか……

いつ利用する?

わたしも

実行する

40 of 67

CatBoostとは

カテゴリ処理が上手な決定木モデル

木構造とは?

Category

任意の閾値(条件)を用いてデータを分割し、データがどこに属するかを推定する

形状

匂い

料理

茶色

スパイス

カレー

茶色

スパイス

カレーうどん

クリーミー

ドリア

ダシ

うどん

形状

うどん

カレー

うどん

ドリア

カレー

こんな感じ

41 of 67

CatBoostで予測をしてみる

その前に・・・

このままでは学習に入れることができません!

なぜ?

日本語のままの部分あり

Label Encodingしてみる

Label Encodingとは?

42 of 67

Label Encodingとは?

Label Encoding

カテゴリにラベル(数字)を割り当てていくこと

形状

匂い

料理

茶色

スパイス

カレー

茶色

スパイス

カレーうどん

クリーミー

ドリア

ダシ

うどん

形状

匂い

料理

0

0

0

カレー

1

0

0

カレーうどん

0

1

1

ドリア

1

1

2

うどん

こんな感じ!

実際に実装してみましょう!

43 of 67

Label Encodingの実装

Python特有の「内包表記」C言語の3項演算子的な

小ネタ:内包表記は普通にリスト作るより高速に動作します。嘘じゃないよ、ホントダヨ……

NaNは除外

Uniqueなものだけピックアップ

xがNoneなら-1へ、そうでなければ変換

list.index(x):list内でxがある場所を教えてくれる

扱いやすいNoneへ変換

44 of 67

Label Encodingの結果

45 of 67

AIの学習についてちょろっとだけ解説

ご存じかもしれませんが・・・

AIの学習

説明変数(状況データ)

AI君

AI君の予測

正解データ

誤差計測

どれだけ間違えてるか計測

間違えたところ教える

上の作業を繰り返し実行することで最強に近づいていきます!

46 of 67

きれいになったので学習

全データの8割を学習に使います

学習データ以外のデータを検証に使います

target以外のデータを学習へ

targetを予測値へ

Catboostが扱いやすい形にしています

エラーが起きにくいのでお勧めです

木の深さ

誤差の測り方

GPU使うぜ!

1000回学習するよ

初期値は42を利用

実行お願いします!

47 of 67

ちょっと休憩

学習中にちょっと一息

学習用データと検証用データを分ける理由は?

A:過度に偏った学習をしないようにするため

AIの学習

予測値に合うように微修正を繰り返す

やりすぎると「学習データ特有の特徴」を使いだすように

汎用性が低下

イメージ)テスト勉強で過去問ばっかり解いて過去問の傾向しかついてない生徒みたいな

検証用データ

学習中にモデルの汎化性能を測るために利用

適宜学習中に検証データで精度を測ることにより、過度に学習データへ適合することを防げます

注意点 できるだけデータの分布が一致するように学習用/検証用を分けましょう

一致していないと検証の意味がなくなってしまいます

数学の勉強をして英語のテストが解けるはずないですからね

48 of 67

何もしなかったときの精度

精度向上にチャレンジ(ここから本番)

特徴エンジニアリングをしていきましょう

  • データを見たエンジニアリング
  • 数学的なエンジニアリング

今回は

を行ってみたいと思います

49 of 67

そもそもなぜ精度が低い?

コンペ時の精度

何でこんなに違う?

A:データがうまく分割できていないから

そもそも・・・

CatboostなどのAIはそのままだとカラム同士の関係性を理解しにくいという特徴があります

人間の「東京かつ駅チカであればかなり高いな」 みたいな考え方が苦手という感じ

特徴エンジニアリングはカラム同士の関係性を明示的にAIへ教え込む作業に近い

使っているデータが少ないのもありますが・・・

50 of 67

データを見たエンジニアリング

すること

一般常識やその分野の常識をふんだんに取り入れていく

例えば

  • 建築されている都道府県と駅への近さが重要
  • 都道府県と建築された年が重要  などなど

のような普段生活の中で感じる常識をデータから導き出してみましょう

51 of 67

都道府県と駅への近さ

  • 基本東京は高い

  • 大阪と兵庫は似ているが
    • 20分を超えたあたりで兵庫は大きく下がる
    • 大阪は緩やかに下がる

県ごとに特色がある

これを入れてみるとどうなるか?

52 of 67

都道府県と駅への近さ

これを数値的に表して放り込んでみる(あくまで一例)

都道府県と距離コンビ = 都道府県名の番号×1000 +距離(分)

これで精度が上がれば「いい特徴が作れた」と言えます!

試してみましょう!

53 of 67

都道府県と駅への近さ

分析に貢献しています!

いい特徴を作れましたね!

このような形で関係性のありそうな部分を掘り起こして新しい特徴として入れることで精度向上ができます。

同じように新しい特徴を作ってみましょう

54 of 67

都道府県と建築された年

さっきのコピペで使いまわせます!

やはり東京・大阪・兵庫で分布が違いますね

東京は古くてもいいみたいです

何かおかしなからくりがありそうです

だた東京だけ古くても高い

違和感

違和感はメモ

後ほどそれに関連したところを掘る

コンペの基本

55 of 67

都道府県と建築された年

これを数値的に表して放り込んでみる(あくまで一例)

都道府県と建築年コンビ = 都道府県名の番号×10000 +建築年

これで精度が上がれば「いい特徴が作れた」と言えます!

試してみましょう!

56 of 67

都道府県と駅への近さ

精度に寄与それなりに寄与してそうですね

57 of 67

各自お楽しみタイム

思いついた常識をどんどん試してみましょう!

その次は数学的エンジニアリングを見てみましょう!

58 of 67

数学的なエンジニアリング

二分木のすること

入力された値を閾値で区切ることでいい精度を出す

区切ること以外が難しい・・・

単純な差・比などを自分で獲得することが困難

数学的なエンジニアリング

意図的に各カラムの差や比を作成し教え込む

59 of 67

まずは平均との差をとったもの

平均との差

その値自身が平均に対してどれだけ特異なものかを表現

平均周りとそれ以外の部分で分けることができるように

今回は

  • 面積
  • 距離
  • 建築年

で試してみましょう!

差の取り方

60 of 67

まずは平均との差をとったもの

重要度

こいつは効いてるような効いてないような・・・?

これはすごい影響してますね

61 of 67

次は比をとったもの

平均との比

その値自身が平均に対してどれだけ特異なものかを表現

平均周りとそれ以外の部分で分けることができるように

引き続き

  • 面積
  • 距離
  • 建築年

で試してみましょう!

比の取り方

62 of 67

次は比をとったもの

面積は非常に効いてますね

面積は比較すると強くなるタイプの特徴ですね

建築年の平均自体に意味がないのかもしれない(建築年は経てば勝手に増えていくし)

63 of 67

そのほかの特徴量作成方法

CountEncoding

カテゴリ系に使える有名な特徴量作成手法

決定木

カテゴリがポピュラーなのかマイナーなのかはわからん

出現回数をラベルとして割り当てる手法

間取り・改装・都道府県にCountEncodingに取り入れてみましょう

64 of 67

CountEncoding

実装はこんな感じ

65 of 67

CountEncoding

都道府県名はCEのほうが理解しやすいみたいですね

66 of 67

数学的特徴エンジニアリング

その他

  • Target Encoding:カテゴリを正解データの数値で穴埋めする

うまくいくと最強だがミスると爆死する劇薬特徴

  • OneHot Encoding:カテゴリ要素をYes・Noで表せるようにする

カテゴリ数が多い場合凄いことになるので、「改装」ぐらいのものに使うとよい

  • 分散との差・カラム同士の差:意味がありそうなカラム同士の差はよく効く

今回だと取引時点と建築年で経ってからどれくらい経って買われたのかがわかる

色々ある統計の式をぶっこんでみると意外とうまくいったり・・・?

  • 平均をやめて中央値にする:グラフが歪んで切るときはさらに効きそう

平均が強いのは左右対称の時だけ。いろいろ試すといい感じ

67 of 67

まとめ

  • テーブルデータを扱う際は前処理が非常に重要

今回適当に埋めているところもあるが、実際はもう少し考えたほうがいい

ほかの類似したデータと比較して予測することも非常に重要

  • モデル作成自体はあっさり

モデル作成はさっと実行可能。前処理に時間のほとんどを要する・・・

  • 特徴エンジニアリングは常識と数式をまず使う

常識はだいたい当たっているので、常識を再現できるようにデータを抽出する

木構造は「比較」が苦手。人間側で組み合わせて実現してあげることで