Toshiki Haraguchi
2022/11/18
はじめに
本ハンズオンはできるだけ初心者の方が分かり易いように心がけています が
どうしても足りない部分などがあるかもしれません。
などを並行して読んでいただくとかなり理解が捗ると思います!
合わせて、わからないところがあれば いつでも お声がけください
ではスタートです!!
目次
テーブルデータとは?
テーブルデータとは何ぞや?
テーブルデータ
Excel
みたいにいい感じにまとまっているデータ
これはテーブルデータ
間違ってもこんな使い方はしちゃだめだよ
データベースみたいなのをイメージすると分かり易い
テーブルデータの利点
利点
Excelだとグラフ書いたりできるし
これとこれよく同時に出てるなーとか
今回のハンズオン
テーブルデータを使ってAIの構築に取り組みます!
何を予測できるAIを作る・・・?
今回扱うテーブルデータ
テーブルデータの種類
中古マンション価格のテーブルデータ
のデータから
を予測できるようなAIを構築するのが今回の趣旨
その過程で様々なことを学んでいきましょう!
前処理とは?
前処理ってなんでんねん!
前処理とは?
生データを扱いやすいデータに手直しする作業
生データ
使えないデータやいらないデータがたくさん存在
そのまま使うのは無駄が多すぎる・・・
できるだけ扱いやすいデータに変換して解析を行う
この作業を前処理といいます!
どうやって前処理する?
ライブラリ「Pandas」に頼み込みまくる
データサイエンス3種の神器
三種の神器「Pandas」
Pandasってなに?
と同じことをPythonで簡単にできるようにするライブラリ
など
Pandasを制するものは
データサイエンスを制する
今回の前処理方針
今回実施する前処理
ばらばらのデータがあってもどうしようもないですよね・・・
せめて全体を見れるように合体させましょう
2. いらないデータを消す
ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!
3. 各カラムをきれいにする
機械が認識しにくいものを変換してきれいにしましょう!
こうすることでAIも喜びます(?)
今回の前処理方針
今回実施する前処理
ばらばらのデータがあってもどうしようもないですよね・・・
せめて全体を見れるように合体させましょう
2. いらないデータを消す
ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!
3. 各カラムをきれいにする
機械が認識しにくいものを変換してきれいにしましょう!
こうすることでAIも喜びます(?)
データを使える形にする
Pandasで読み込んだデータを
DataFrame といいます
まずはデータがどんな形をしているか確認
import pandas as pd
�# データを読み込んでいる
df = pd.read_csv("./train/01.csv")
�# データを表示する
df.head()
データを使える形にする
今選択したデータ
一番上のデータのみ
全データのごく一部のみ
全部使えるように!
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
今回の前処理方針
今回実施する前処理
ばらばらのデータがあってもどうしようもないですよね・・・
せめて全体を見れるように合体させましょう
2. いらないデータを消す
ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!
3. 各カラムをきれいにする
機械が認識しにくいものを変換してきれいにしましょう!
こうすることでAIも喜びます(?)
いらないデータを消す
データが読み込めた! ・・・けどこれじゃうまく解析できないよぉ・・・。
次は何をするの?
次は使えそうなデータを抽出しましょう!
言い換えると 使えないデータを消しましょう!
使えないデータとは?
予測に使えなさそうなものを消す
何がゴミなのか確認する
していること
データ全体に対しての欠損割合の算出
欠損値が9割以上を使い物にならないと仮定すると
地域・土地の形状・間口・延床面積・前面道路・取引の事情など
計8種類のデータが使えないことが判明!
使えないデータを削除
nan_data = df.isna().sum()/len(df.index)
nan_data
使えないデータを削除
削除対象
残った
カラム
# 欠損率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:指定した行/列を削除できる
いったん完成
とりあえず扱いやすいデータが完成しました!
続いてデータをきれいにしていきましょう!
今回の前処理方針
今回実施する前処理
ばらばらのデータがあってもどうしようもないですよね・・・
せめて全体を見れるように合体させましょう
2. いらないデータを消す
ゴミまみれのデータを消しましょう!必要ないものを消して見やすさアップ!
3. 各カラムをきれいにする
機械が認識しにくいものを変換してきれいにしましょう!
こうすることでAIも喜びます(?)
データをきれいにするとは?
最寄駅:距離(分)を例に
想定
最寄駅からの距離(分)
この行は数字で構成されているはず
実際
NaN (Not a Numer) や 文字列(30分?60分)等想定しないものがある
問題:機械学習時にうまく読み込めない
予想外のデータをきれいにする必要がある
クレンジングという
数値や思たら違うやーん
どういう基準できれいにする?
データにはざっくり二種類
順序に意味が有るもの
順序に意味が無いもの
例)順位・日時・大きさ など
きれいにする方法:順序を統一するように変換(単位を揃える、西暦に直すなど)
きれいにする方法:数値としてラベル付けする等
例)食べ物の種類・性別・向きなど
大小関係がはっきりとわかるように
最寄駅:距離(分)をきれいにしてみる
よく見ると数値のはずなのに文字列ですね?
ここも一緒に直しましょう!
変換の方針
これは1例!
df["最寄駅:距離(分)"].unique()
最寄駅:距離(分)をきれいにしてみる
列に一度に変換を掛ける場合はapply()を使います!
続いて建築年をきれいに
機械は昭和と平成のどちらが新しいか分からない
西暦に統一して順序が分かりやすく
続いて建築年をきれいに
建築年の大小関係がすっきりと分かりやすくなった!
最後に取引時点
取引時点は何が問題?
2019年第3四半期
連続値っぽい
第3四半期ってどれ?
全部を数値で表せていない
カテゴリだと判断される
順序に意味がないとみなされる
変換方針
四半期
1年の1/4 0.25なので、0.25×(第n - 1)で変換
2019年第3四半期
2019 + 0.25×(3 - 1) = 2019.5 のような感じ
連続値で表せるので分かりやすい
最後に取引時点
曖昧な四半期を小数以下に収めることで
扱いやすいデータに!
いったん完成
とりあえずデータが完成しました!続いてどんなデータなのか見てみましょう!
データをよく見たものだけが勝利を手にすることができるのです・・・!
データの確認
いったん完成
今回はピックアップした赤枠の変数と、青枠がどういう関係を持つのかを見たいと思います
都道府県と取引価格
都道府県と取引価格の関係性
カテゴリ別で情報を知りたいとき
「GroupBy」実行する
集約する
都道府県の場合は・・・
各都道府県の
平均取引を知りたい!
GroupByを実行
その県の取引平均を見れる
都道府県と取引価格
では実践
df[["都道府県名", "取引価格(総額)_log"]].groupby("都道府県名").mean().sort_values("取引価格(総額)_log",ascending=False)
カラムの指定(なくても可)
都道府県名で集約取る
平均で
降順でソートするよ
結果
東京・神奈川・大阪等都会は取引価格が高いことが分かった
常識がそのまま反映されている
都道府県は取引価格をよく説明できるといえる
機械学習に用いると精度が向上する
改装と取引価格
改装すると取引価格が上がるのでしょうか?
df[[“改装”, “取引価格(総額)_log”]].groupby("改装").mean().sort_values("取引価格(総額)_log",ascending=False)
カラムの指定(なくても可)
改装で集約取る
平均で
降順でソートするよ
改装してもしなくてもあまり価格には影響が無いようです
結果
何か腑に落ちないような・・・
予測に用いても精度向上に寄与しない可能性あり
建築年と取引価格
建築年と取引価格に関係性はあるのでしょうか?
df[[“建築年”, “取引価格(総額)_log”]].groupby(“建築年").mean().sort_values("取引価格(総額)_log",ascending=False)
結果
これだけだと分かりづらい・・・。どうなっている?
数値列データの集計結果
グラフにプロットすることも重要
可視化という
建築年と取引価格
可視化してみる
年代ごとに上昇していることが一目瞭然
これが可視化を勧める理由
これ一つでいろいろ読み取れる
赤丸:バブル崩壊があったであろう期間
緑丸:リーマンショックの影響であろう期間
など
面積と取引価格
面積と距離!
駅までの時間と取引価格
何らかの関係がありそう!
そのほかは?
今までのハンズオンを基にほかのグラフを描画してみましょう!
何が分かるかな?
いざ学習!
やはり
CatBoostか……
いつ利用する?
わたしも
実行する
CatBoostとは
はカテゴリ処理が上手な決定木モデル
木構造とは?
Category
任意の閾値(条件)を用いてデータを分割し、データがどこに属するかを推定する
形状 | 色 | 匂い | 料理 |
米 | 茶色 | スパイス | カレー |
麺 | 茶色 | スパイス | カレーうどん |
米 | 白 | クリーミー | ドリア |
麺 | 白 | ダシ | うどん |
形状
色
色
麺
米
うどん
カレー
うどん
ドリア
カレー
こんな感じ
CatBoostで予測をしてみる
その前に・・・
このままでは学習に入れることができません!
なぜ?
日本語のままの部分あり
Label Encodingしてみる
Label Encodingとは?
Label Encodingとは?
Label Encoding
カテゴリにラベル(数字)を割り当てていくこと
形状 | 色 | 匂い | 料理 |
米 | 茶色 | スパイス | カレー |
麺 | 茶色 | スパイス | カレーうどん |
米 | 白 | クリーミー | ドリア |
麺 | 白 | ダシ | うどん |
形状 | 色 | 匂い | 料理 |
0 | 0 | 0 | カレー |
1 | 0 | 0 | カレーうどん |
0 | 1 | 1 | ドリア |
1 | 1 | 2 | うどん |
こんな感じ!
実際に実装してみましょう!
Label Encodingの実装
Python特有の「内包表記」C言語の3項演算子的な
小ネタ:内包表記は普通にリスト作るより高速に動作します。嘘じゃないよ、ホントダヨ……
NaNは除外
Uniqueなものだけピックアップ
xがNoneなら-1へ、そうでなければ変換
list.index(x):list内でxがある場所を教えてくれる
扱いやすいNoneへ変換
Label Encodingの結果
AIの学習についてちょろっとだけ解説
ご存じかもしれませんが・・・
AIの学習
説明変数(状況データ)
AI君
AI君の予測
正解データ
誤差計測
どれだけ間違えてるか計測
間違えたところ教える
上の作業を繰り返し実行することで最強に近づいていきます!
きれいになったので学習
全データの8割を学習に使います
学習データ以外のデータを検証に使います
target以外のデータを学習へ
targetを予測値へ
Catboostが扱いやすい形にしています
エラーが起きにくいのでお勧めです
木の深さ
誤差の測り方
GPU使うぜ!
1000回学習するよ
初期値は42を利用
実行お願いします!
ちょっと休憩
学習中にちょっと一息
学習用データと検証用データを分ける理由は?
A:過度に偏った学習をしないようにするため
AIの学習
予測値に合うように微修正を繰り返す
やりすぎると「学習データ特有の特徴」を使いだすように
汎用性が低下
イメージ)テスト勉強で過去問ばっかり解いて過去問の傾向しかついてない生徒みたいな
検証用データ
学習中にモデルの汎化性能を測るために利用
適宜学習中に検証データで精度を測ることにより、過度に学習データへ適合することを防げます
注意点 できるだけデータの分布が一致するように学習用/検証用を分けましょう
一致していないと検証の意味がなくなってしまいます
数学の勉強をして英語のテストが解けるはずないですからね
何もしなかったときの精度
精度向上にチャレンジ(ここから本番)
特徴エンジニアリングをしていきましょう
今回は
を行ってみたいと思います
そもそもなぜ精度が低い?
コンペ時の精度
何でこんなに違う?
A:データがうまく分割できていないから
そもそも・・・
CatboostなどのAIはそのままだとカラム同士の関係性を理解しにくいという特徴があります
人間の「東京かつ駅チカであればかなり高いな」 みたいな考え方が苦手という感じ
特徴エンジニアリングはカラム同士の関係性を明示的にAIへ教え込む作業に近い
使っているデータが少ないのもありますが・・・
データを見たエンジニアリング
すること
一般常識やその分野の常識をふんだんに取り入れていく
例えば
のような普段生活の中で感じる常識をデータから導き出してみましょう!
都道府県と駅への近さ
県ごとに特色がある
これを入れてみるとどうなるか?
都道府県と駅への近さ
これを数値的に表して放り込んでみる(あくまで一例)
都道府県と距離コンビ = 都道府県名の番号×1000 +距離(分)
これで精度が上がれば「いい特徴が作れた」と言えます!
試してみましょう!
都道府県と駅への近さ
分析に貢献しています!
いい特徴を作れましたね!
このような形で関係性のありそうな部分を掘り起こして新しい特徴として入れることで精度向上ができます。
同じように新しい特徴を作ってみましょう
都道府県と建築された年
さっきのコピペで使いまわせます!
やはり東京・大阪・兵庫で分布が違いますね
東京は古くてもいいみたいです
何かおかしなからくりがありそうです
だた東京だけ古くても高い
違和感
違和感はメモ
後ほどそれに関連したところを掘る
コンペの基本
都道府県と建築された年
これを数値的に表して放り込んでみる(あくまで一例)
都道府県と建築年コンビ = 都道府県名の番号×10000 +建築年
これで精度が上がれば「いい特徴が作れた」と言えます!
試してみましょう!
都道府県と駅への近さ
精度に寄与それなりに寄与してそうですね
各自お楽しみタイム
思いついた常識をどんどん試してみましょう!
その次は数学的エンジニアリングを見てみましょう!
数学的なエンジニアリング
二分木のすること
入力された値を閾値で区切ることでいい精度を出す
区切ること以外が難しい・・・
単純な差・比などを自分で獲得することが困難
数学的なエンジニアリング
意図的に各カラムの差や比を作成し教え込む
まずは平均との差をとったもの
平均との差
その値自身が平均に対してどれだけ特異なものかを表現
平均周りとそれ以外の部分で分けることができるように
今回は
で試してみましょう!
差の取り方
まずは平均との差をとったもの
重要度
こいつは効いてるような効いてないような・・・?
これはすごい影響してますね
次は比をとったもの
平均との比
その値自身が平均に対してどれだけ特異なものかを表現
平均周りとそれ以外の部分で分けることができるように
引き続き
で試してみましょう!
比の取り方
次は比をとったもの
面積は非常に効いてますね
面積は比較すると強くなるタイプの特徴ですね
建築年の平均自体に意味がないのかもしれない(建築年は経てば勝手に増えていくし)
そのほかの特徴量作成方法
CountEncoding
カテゴリ系に使える有名な特徴量作成手法
決定木
カテゴリがポピュラーなのかマイナーなのかはわからん
出現回数をラベルとして割り当てる手法
間取り・改装・都道府県にCountEncodingに取り入れてみましょう
CountEncoding
実装はこんな感じ
CountEncoding
都道府県名はCEのほうが理解しやすいみたいですね
数学的特徴エンジニアリング
その他
うまくいくと最強だがミスると爆死する劇薬特徴
カテゴリ数が多い場合凄いことになるので、「改装」ぐらいのものに使うとよい
今回だと取引時点と建築年で経ってからどれくらい経って買われたのかがわかる
色々ある統計の式をぶっこんでみると意外とうまくいったり・・・?
平均が強いのは左右対称の時だけ。いろいろ試すといい感じ
まとめ
今回適当に埋めているところもあるが、実際はもう少し考えたほうがいい
ほかの類似したデータと比較して予測することも非常に重要
モデル作成はさっと実行可能。前処理に時間のほとんどを要する・・・
常識はだいたい当たっているので、常識を再現できるようにデータを抽出する
木構造は「比較」が苦手。人間側で組み合わせて実現してあげることで