ROC曲線とAUCについて
分類問題の評価をするときにROC曲線をよく使うと思うんですが、それの縦軸ってなんだっけ?とかなってしまいがちなので、備忘録としてROC曲線について紹介していきます
ROC曲線を評価する指標としてAUCというのもあるので、それも合わせてまとめていきます
ROC曲線とは
そもそもROC曲線とはなんぞやって話をしていきます
ROC曲線とはざっくり言うと、
分類の閾値を変化させていったときに、精度がどのように変化していくか
を可視化したものになります
ROC曲線の例
言葉だけだと理解しづらいので、ここからは図を用いて解説していきます
ROC曲線の例を以下に示します
縦軸、横軸は以下の計算式で算出されたものです
- False Positive Rate(横軸): FP/(FP+TN)
- 実際の負例の中で予測が間違っていたもの、低いほど良い
- True Positive Rate(縦軸): TP/(TP+FN)
- 実際の正例の中で予測が合っていたもの、高いほど良い
※参考
TP,FPとかの詳しい説明は、以下を参考にしてくださいhttps://minmin-21.hatenablog.com/entry/2019/03/23/152216
分類の閾値を変化させていったとき、False Positive Rate(以下FPR)とTrue Positive Rate(以下TPR)をプロットしたものがROC曲線になります
FPRとTPRのトレードオフについて
FPRとTPRはトレードオフの関係にあります
つまり、FPRが低いとき(間違えた真の負例が少ない)ときは、TPRも低くなってしまいます
また、逆にFPRが高い時はTPRも高くなります
ここは自分でもこんがらがってしまうので、もう少し詳しく説明します
例えば閾値を0.01にした場合を考えます
- 正例の確率が0.02と低いものでも正例と判定されるためFP(間違って正例と判定されたもの)が大きくなる
→ FPRが高くなる - ほとんどのものが正例と判定されるためTP(正例と予測された実際の正例)は大きくなる
→ TPRも高くなる
逆に閾値を0.99にした場合を考えます
- ほとんどのものが負例と判定されるためFPが小さくなる
→ FPRが低くなる - 逆に正例の確率が0.98とほぼほぼ正例であると思われるものも負例と判定されてしまうため、TPは小さくなる
→TPRも低くなる
グラフ上で確認すると、先ほどのグラフだと閾値が0.58のときにTPRが0.92,FPRが0.19となっています
閾値を0.89にずらすと、TPRが0.77でFPRが0.09ということが分かると思います
AUCとは
先ほど、AUCとはROC曲線を評価する指標だと説明しましたが、そもそもROC曲線はどのように評価すればよいのでしょう?
理想的なROC曲線と、良くないROC曲線を比較しながら説明していきます
理想的なROC曲線は、以下のようにFPRが0のときにTPRが1になっている曲線です
逆に良くないROC曲線とは、以下のような曲線です
(AUC=0.79は悪すぎる例ではないと思うのですが、そこはスルーしてください笑)
上の二つを比較してみると、ROC曲線の内側の面積が広い方が良いROC曲線ということが分かると思います
AUCはこの内側の面積を定量的に表したものになり、理想的なROC曲線のAUCを1としてそれを基準に評価した指標になります
参考
- 【ROC曲線とAUC】機械学習の評価指標についての基礎講座 - 世界一やさしいデータ分析教室
- 機械学習の評価指標 – ROC曲線とAUC | GMOアドパートナーズグループ TECH BLOG byGMO
- ROC曲線とAUCの出力 - Qiita
- Machine Learning実践の極意 機械学習システム構築の勘所をつかむ! (著)Henrik Brink, Joseph W. Richards, Mark Fetherolf (訳)株式会社クイープ
recall?precision?機械学習モデルの評価尺度についてまとめる
recall, precision, accuracy F値など機械学習モデルの評価尺度はいろいろあるのですが、どれがどれだかよくわからなくなってしまうのでまとめてみました
今回は1か0を予測する問題について考えたいと思います
※正例は1とします
はじめに
これからの説明に使用するので、以下に混同行列を書いておきます
混同行列(confusion matrix)とは予測結果と実際のデータを比較するときに使用する表のことです
これもどれがFPでどれがFNだか分からなくなってしまうのですが、
- 予測結果と実際のデータがあっているものがT, そうでないものがF
- 予測結果が正例である場合はP, 負例である場合はN
と覚えておけば大丈夫です
各評価指標の解説
accuracy
accuracyは以下の式で表されます
accuracyは、すべてのデータにおいて正解したものの割合はどのくらいかを表した指標になります
これはイメージしやすいと思います
recall
続いてrecallです
recallは以下の式で表されます
recallは実際の正例の中(TP+FN)から、モデルがどれだけ拾えているかをあらわした指標です
つまり、どれだけ正例を見逃していないかということになります
モデルの予測結果をすべて正例にしてしまえば、必然的にrecallは1となります
precision
precisionは以下の式で表されます
precisionは正例と予測したもの(TP+FP)の中に、どれだけ実際の正例があるかを表した指標です
つまり、正例をどれだけ命中させたかということになります
絶対に正例だと思うものだけ正例にしてしまえば、precisionは高くなります
F値
F値は以下の式で表されます
上のrecall, precisionでも説明したように
- recallを高くするようにモデルを極端に学習させた場合->全て正例と判断し、precisionが低くなる
- precisionを高くするようにモデルを極端に学習させた場合->正例と予測されるものが少なくなり、recallが低くなる
とrecallとprecisionはトレードオフの関係にあることがわかります
そこで、極端にモデルを学習させることなくrecallとprecisionを良い感じにするための指標としてF値があります
まとめ
- accuracy
- 純粋な正解率
- recall
- どれだけ正例を見逃していないか
- precision
- 正例をどれだけ命中させたか
- F値
- 極端にモデルを学習させることなくrecallとprecisionを良い感じにするための指標
参考
ユースケースごとによく使うgitコマンドを紹介する
備忘録としてgitでよく使うコマンドをユースケースごとに紹介したいと思います
随時アップデートしていく予定です
※本記事で紹介しているコマンドで事故ったとしても責任は負えないので、自己責任で参考程度にお使いいただければと思います
- 変更をremoteに反映する
- addした変更を取り消す
- ファイルの変更を取り消す
- 現在のブランチをmasterの最新状態に合わせてからpushする
- すでにremoteにあるブランチをlocalに持ってくる
- 最後に
- 参考
変更をremoteに反映する
git add [ファイル名] git commit -m "[some message]" git push
コミットメッセージはつけておいた方がそのメッセージをもとに変更箇所を特定できるので、個人開発の場合でもつけておくのがおススメです
基本的にはコミット単位でしか変更を戻すことができないので、こまめに変更をコミットした方が良いです
addした変更を取り消す
git reset HEAD
ファイルの変更を取り消す
git checkout [file name]
git checkout .
をするとaddされていない全ての変更を取り消すことができますが、事故を防ぐためにファイル単位で変更取り消しを行いましょう
現在のブランチをmasterの最新状態に合わせてからpushする
git checkout master git pull git checkout [branch name] git rebase master
最新のマスターと現在のブランチにコンフリクトがあれば、メッセージに従ってコンフリクトを解消していく
(これに関してはあまり自信がないので、もっと良いやり方があれば教えていただきたいです)
すでにremoteにあるブランチをlocalに持ってくる
git checkout -b [branch name] origin/[branch name]
チームの誰かが作業したブランチを引き継ぐ場合とかによく使います
originが前か後か毎回のように分からなくなってしまい、リモートのgitブランチをローカルにチェックアウトする - setoya-blogの記事には毎回お世話になっています
最後に
もっとたくさんのユースケースがあると思うんですが、自分はだいたいこれくらいでなんとかなっています
master等へのマージの作業は基本的にGUIで行い、コンフリクト解消するときにはCUIを使っているという感じです
参考
jupyter notebookを簡単に管理できるjupytextの紹介
データ分析とかを行うときにjupyter notebookをよく使うと思うんですが、それをgitで簡単に管理できるようにするjupytextなるものを知ったので、備忘録としてまとめてみたいと思います。
背景
jupyter notebookの中身はjsonで書かれているため、gitとかで管理しづらい
jupyter上での表示
git上での表示
printした結果や実行回数まで差分として出力されてしまう
データ分析を行う際に、jupyter notebookを使いたい派 vs 使いたくない派の戦争が発生する(?)
- 使いたい派:step by stepで途中経過を確認しながら分析したい
- 使いたくない派: コードが煩雑になりがちなので、出来れば
.py
ファイルを使いたい
jupytextとは
jupyter notebookをpython script(
.py
)として保存することができるツール.ipynb
ファイル(左)、変換された.py
ファイル(右)
他にも以下のような機能がある
基本的な使い方
使い方はとても簡単で、以下の3ステップを実行するだけ!!
pip install jupytext
~/.jupyter/jupyter_notebook_config.py
内の末尾に以下を追加c.NotebookApp.contents_manager_class = "jupytext.TextFileContentsManager"
- jupyter notebookを立ち上げ、Edit>Edit Notebook Metadataを開き、以下を追加
"jupytext": {"formats": "ipynb,py"}
これを仕込んでおくだけで、
jupyter notebookを保存する度に.pyファイルが自動で作成・更新されます
さらに、作成された.pyファイルを変更しても、自動的に変更が.ipynbに反映されます
発展的(?)な使い方
- すべての
.ipynb
ファイルに対して.py
ファイルを作成したい場合、~/.jupyter/jupyter_notebook_config.py
内の末尾に以下を追加c.ContentsManager.default_jupytext_formats = "ipynb,py"
- 作成される
.py
ファイルの場所も指定することができる- Edit Notebook Metadataに、
"jupytext": {"formats": "ipynb, scripts//py"}
と書くと、以下のようにscriptディレクトリの下に.py
ファイルが作成される
- Edit Notebook Metadataに、
|--- hoge.ipynb |--- scripts/ |----hoge.py
- コマンドラインからでも変換を行うことができる
jupytext --to py hoge.ipynb #hoge.ipynbをhoge.pyに変換する
メリット・デメリット
- メリット
.py
,.ipynb
片方を変更すると、もう片方のファイルも自動で同期される- jupyter notebookのgitでの管理が簡単になる
- デメリット
- 純粋にファイルの数が増える
- これは、作成場所をうまく指定してあげることで何とかなりそう
- 純粋にファイルの数が増える
まとめ
- jupytextを用いると、自動で
.py
ファイルが生成・変更され、コードの差分が分かりやすくなる .ipynb
と.py
ファイルそれぞれの変更が保存のタイミングで反映されるため、どちらの派閥にも対応できる
余談
jupytextを使って、.ipynb
を.md
に変更してみると、コード部分だけが抽出されたmarkdownが作成された。
参考
docker-composeの使い方
docker-composeの使い方について、備忘録として簡単にまとめておきます。
ゼロからはじめる Dockerによるアプリケーション実行環境構築 | Udemyで学んだことを基本に、docker-composeの使い方をまとめてみました。
docker-composeとは
複数のコンテナを使用したアプリケーションを定義・実行するツール
複数のコンテナを利用し疎結合なサービスにすることで、保守性や可読性が高まります。
docker-compose実行の手順
- Dockerfile or 使用するイメージの用意
- 各コンテナを立ち上げるための準備(Dockerfileの書き方とかは本記事では言及しません)
- docker-compose.ymlの作成
- サービスをどのように構成するかが記述されているファイル
- docker compose up の実行
- 上二つで用意したものを使って、実際にサービスを立ち上げる
docker-compose.ymlの書き方
version: '3' services: db: #サービス名 # サービス(コンテナ)をイメージから立ち上げる場合はimage、Dockerfileからならbuildを使用する image: [サービスを立ち上げる基になるイメージ名] build: [Dockerfileのあるディレクトリ名] ports: - "[外部に公開するport]:[マッピングするポート]" volumes: - [ホスト側のディレクトリ or volume名]:[docker内のディレクトリ] command: [コンテナ起動時に実行したいコマンド] links: - [linkしたいサービス名] depends_on: #依存関係の定義 - [サービス名] #本サービス起動前にどのサービスを起動したいか記載 frontend: ... volumes: #volumeを自分で定義する [volume名]:
主要コマンド
以下、使用頻度が高いであろうコマンドをまとめています。
※docker-composeのコマンドは基本的にdocker-compose.ymlがあるディレクトリで実行する。
-f
オプションで、docker-composeファイルを指定することもできる
docker-compose build
サービスのビルドを実行
docker-compose build
docker-compose up
サービスごとのコンテナを作成して起動する
--build
でコンテナ作成前にイメージを構築できる
docker-compose up
docker-compose stop
サービス・コンテナの停止
docker-compose stop
docker-compose down
コンテナ・ネットワークの削除を行う
-v
でvolumeの削除、---rmi
でimageの削除も行うことができる
docker-compose down
docker-compose ps
本アプリケーションで作成されたコンテナの一覧を表示する
docker-compose ps
docker-compose run
サービスのコンテナ内でコマンドを実行する
(個人的にはこのコマンドについては、docker execでコンテナの中に入り込んで作業した方がやりやすいと思っているのであまり使わないかも、、?)
docker-compose run [サービス] [サービスのコンテナ内で実行したいコマンド]
参考
jupyter notebookで上位階層のモジュールをimportする
jupyter notebookから上位階層にあるモジュールをimportするときに、通常のpythonファイルのようにはいかなかったので、その解決方法を紹介したいと思います。
解決方法としては、以下のコマンドをimportの前に追加してあげれば良いだけです。
import sys sys.path.append('..') #('')の中に探索元のpathを書く
以下、前提やら簡単な説明やらを書いていきます。
前提
以下のような階層を想定して、sample.py, sample.ipynbからhoge.py内のprint_fugaをimportしたいと思います。
|-- utils/ |-- hoge.py |-- examples/ |-- sample.py |-- sample.ipynb
通常のpythonファイルでは
以下のように、sys.path
に探索元のpathを追加してあげることで、importすることができます。
※sys.pathとは探索してくれるpathが格納されているリストのことです。
__file__
は実行場所から実行スクリプトファイル(この場合はsample.py)への相対パスなので、
どの場所からsample.pyを実行しても問題なくimportすることができます。
import sys, os sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from utils.hoge import print_fuga print_fuga()
同じ方法をnotebookで行おうとすると
通常のpythonファイルと同様の方法でnotebook上で実行しようとすると、以下のようなエラーが出てきてしまいます。
jupyter notebookでは、__file__
が定義されていないようですね、、(そのままですが、、)
NameError: name '__file__' is not defined
解決方法
import sys sys.path.append('..') from utils.hoge import print_fuga print_fuga()
これでも良いのかってほどの方法で解決してしまいました。
jupyter notebookは外から呼ばれることを想定されていないので、この方法で良いだろうって感じですね~。
ちなみに、sys.path.append(os.path.join(os.getcwd(), '..'))
とかでも解決できるのですが、一番シンプルな方法にしました。
補足
通常のpythonファイルでsys.path.append('..')
を使ってしまった場合、実行場所と実行スクリプトファイルの場所が異なるときにImport Error
が出てしまうので、注意してください。
jupyter notebookでは、実行場所と実行ファイルの場所が一致しているはずという前提のもと解決しているので、
参考
- Pythonの相対インポートで上位ディレクトリ・サブディレクトリを指定 | note.nkmk.me
- Pythonで実行ファイルの場所(パス)を取得するfile | note.nkmk.me
- 29.1. sys — System-specific parameters and functions — Python 3.6.8 documentation
最後に
解決方法は拍子抜けするほど簡単でした、、
この問題に引っかかって解決するまで20分ぐらい時間がかかった気がするので共有します
はじめてこういうものを書いてみたので慣れていないのですが、こっちの方が良いよ等の意見があればコメント・twitter等でお待ちしております。