イントロダクション
みなさん初めまして。情報工学部の4年生で、機械学習を勉強する学生団体に参加している学生です。縁あって、データサイエンティストのインターンを4ヶ月間行いました。
初めて実務でデータ分析を行うということで、あらかじめ知っていた方がよかったことをまとめ、次の案件を行うための前準備としたいと思います。
この記事について
体系的に学んだ訳ではないのでこのTipsが100%正しいとは限りません。あくまで僕がこれまでやっていた手法よりは効率的な方法をまとめたものになります。
始める前の状況
履修済み
- データサイエンス
- パターン認識
- ソフトウェア工学
- コンピュータアーキテクチャ
- アルゴリズムとデータ構造
- etc...
案件の内容
Google satelliteから得られる衛星画像データや、田んぼのデータから田んぼをクラスタリング(守秘義務のため詳細は割愛)。
環境
Google Colab
1. 前処理
実務でのデータ分析では、前処理の良し悪しが推論結果を大きく左右します。大学のレジュメや機械学習の記事ばかり読んでいたので、ここまで前処理が重要だと思いませんでした。
csvファイルの読み込み
初めは読み込みたいcsvファイルを別々にpd.read_csv()
で読み込み、df_hoge_1
、df_hoge_2
のように変数を宣言したのですが、後々ファイル数が増えてくると何度も同じコードを書く必要が出てきます。とってもめんどくさいですね。
df_hoge_1 = pd.read_csv('content/drive/Mydrive/hoge_1.csv')
df_hoge_2 = pd.read_csv('content/drive/Mydrive/hoge_2.csv')
数行のコードで済ませるために、glob
でワイルドカードでcsvファイル名を取得してあげましょう。データフレームをdf_list
のようなリストに追加していけば、for文を回してあげるだけで簡単に取得することができます。
import glob
files = glob.glob('/content/drive/MyDrive/data/*.csv')
for filename in files:
pd.read_csv(filename)
このように書くことで、後からデータが増えてもコードを変更する必要がありません。
あ、もちろん生データを置くフォルダは1つにまとめてくださいね。
欠損値処理
これに関してはデータの性質によります。dropna
の引数をhow=any
かhow=all
のどちらにするか、NaNを0埋めするのか、補間にするのかはその場で判断しましょう。
グラフ表示
基本的にPlotlyを使いましょう。マウスホバーは異常値の特定に便利ですし、ズームはデータ数が多い場合に役立ちます。
3次元のグラフまでなら対応できるので、積極的に使ってみてください。
また、どんな些細なグラフでもメインタイトル、x軸のタイトル、y軸のタイトルは忘れないでください。何を表すグラフなのかを、グラフのみの情報で分かるようにしましょう。来週の自分が見た時に何のグラフだったかを忘れることもありますよ。
自分はよくタイトルなどの設定方法を忘れがちなので、簡単な関数を使い回していました。
import plotly.graph_objects as go
def show_graph(
df,
x_col,
y_col,
title="title",
x_title="x_title",
y_title="y_title",
):
fig = go.Figure()
fig.add_trace(go.Scatter(x=df[x_col],
y=df[y_col],
mode='lines',)
)
fig.update_layout(
title=title,
xaxis=dict(title=x_title),
yaxis1=dict(title=y_title,
side='left'),
yaxis2=dict(side='right',
showgrid=False,
overlaying='y'))
fig.show()
補間
時系列データフレーム同士を結合する場合、互いに同じ時刻のデータを持つとは限りません。
最低でも片方のデータフレームは補間で補う必要がありますが、スプラインにしても移動平均にしてもパラメーターは手動で指定してあげる必要があります。
パラメータの更新ごとにセルを実行するのは効率が悪いので、for文などで候補を一気に突っ込んじゃいましょう。
win_size_list = [10, 20, 30, 40]
for win_size in win_size_list:
df_rolling = df.rolling(win_size)
show_graph(df_rolling, x_col='hoge', y_col='fuga')
2. ひとまずの学習
意外と簡単なモデルで課題解決できることもあります。最新モデルは実行に時間がかかるものも多いので、線形回帰などの簡単な学習を試してみましょう。
今回は分類タスクですが、回帰直線のyを閾値で区切ってあげれば分類を行うことができます。
3. 本番の学習
分類モデルにはロジスティック回帰、SVM、決定木など多数のモデルがあります。各モデルの特性を深く知りながら使う必要がありますが、実際予想外のモデルを利用した方がスコアが高くなることがあります。学習にかかる時間が1ケタ分なら、とりあえずデータを突っ込んでみるのがいいでしょう。
また、sklearn
で手軽に出せるスコアがaccuracy
のみなので、cross_validate
を用いて複数のスコアを出せるようにしましょう(交差検証については後述)。
僕は最低でもrecall
、precision
、f1
は使っています。
4. 交差検証
実務では0.9以上の精度が出ることは稀です。精度が高すぎるモデルが出たら逆に疑いましょう。
そのような状況を防ぐために、交差検証(cross_validation)を行います。
過学習を防ぎ、汎化性能を上げることが期待できます。
ちなみに僕は正解ラベルを含んだデータで決定木を学習していたことがあり、交差検証を行なっても全モデルの精度が100%になっていたことがありました。
5. スタッキング
今回のデータセットではaccuracyやf値などを用いていたため、スコアごとに最も良いモデルがバラけていました。
そこで、スタッキングを用いてそれぞれのモデルの主張を全て拾い上げてあげましょう。今回はどのモデルも比較的有用だったので、Ridgeでまとめたいと思います。
最終的にどのような重みで学習されたのかをグラフにしてあげるとより丁寧でしょう。
clf = Ridge(alpha=0.1, random_state=42)
# y_predsはモデルの出力をデータフレームにまとめたもの yは正解ラベル
clf.fit(y_preds, y)
plt.figure(figsize=(12, 7))
plt.title('Ridge')
plt.bar(x=y_preds.columns, height=clf.coef_[0])
plt.xticks(rotation=90) # モデル名が日本語のため、回転させて文字が重ならないようにする
plt.tight_layout();
6. コーディングのTips
データをいじるときは都度新しい変数を用意する
欠損値を削除したときや補間を行ったとき、グラフ表示すると「なんか違う」と思うことがあります。その際、元のデータフレームを更新していると別の補間方法を試せませんよね?
後で綺麗なコードにすればいいので、調査段階ではたくさん変数を作りましょう。
df = df.rolling(100, center=True)
show_graph(df, x_col='hoge', y_col='fuga') # 思ってたんと違うグラフが表示される
df = pd.read_csv('content/drive/Mydrive/hoge.csv')
df_rolling_100 = df.rolling(100, center=True)
show_graph(df_rolling_100, x_col='hoge', y_col='fuga')
df_rolling_100 = df.rolling(100, center=True)
show_graph(df_rolling_100, x_col='hoge', y_col='fuga') # 思ってたんと違うグラフが表示される
df_rolling_1000 = df.rolling(1000, center=True)
show_graph(df_rolling_1000, x_col='hoge', y_col='fuga')
キーワード引数を明示的に書く
僕のPython歴が浅いのが一番の原因だと思いますが、位置引数で指定すると「何を指定しているんだっけ」となることが時々あります。慣れないうちはキーワード引数を書いてあげましょう。
with open('hoge.csv', 'a') as f:
writer = csv.writer(f)
writer.writerow(hoge_list)
with open('hoge.csv', mode='a') as f:
writer = csv.writer(f)
writer.writerow(hoge_list)
初めのセルでまとめてimportしない
別のノートブックに同じ処理をコピペするとき、import文もまとめて持っていきたいです。
パッケージは必要になったセルでインポートするようにしましょう。
最後に
ここまで紹介してきた方法は、書籍や記事などで「良い方法」と紹介されたものではありません。一般的に非推奨な方法があったらコメントで教えてくださると嬉しいです。