minminの備忘録

フルスタックになりたいエンジニアの備忘録 → https://zuminblog.com/ へ引越し中

ROC曲線とAUCについて

分類問題の評価をするときにROC曲線をよく使うと思うんですが、それの縦軸ってなんだっけ?とかなってしまいがちなので、備忘録としてROC曲線について紹介していきます
ROC曲線を評価する指標としてAUCというのもあるので、それも合わせてまとめていきます

ROC曲線とは

そもそもROC曲線とはなんぞやって話をしていきます

ROC曲線とはざっくり言うと、
分類の閾値を変化させていったときに、精度がどのように変化していくか
を可視化したものになります

ROC曲線の例

言葉だけだと理解しづらいので、ここからは図を用いて解説していきます

ROC曲線の例を以下に示します

f:id:minmin_21:20190331121433p:plain
ROC_example

縦軸、横軸は以下の計算式で算出されたものです

  • False Positive Rate(横軸): FP/(FP+TN)
    • 実際の負例の中で予測が間違っていたもの、低いほど良い
  • True Positive Rate(縦軸): TP/(TP+FN)
    • 実際の正例の中で予測が合っていたもの、高いほど良い

※参考

f:id:minmin_21:20190323151512p:plain
confusion_matrix

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ということが分かると思います

f:id:minmin_21:20190331122945p:plain
ROC_example_with_description

AUCとは

先ほど、AUCとはROC曲線を評価する指標だと説明しましたが、そもそもROC曲線はどのように評価すればよいのでしょう?

理想的なROC曲線と、良くないROC曲線を比較しながら説明していきます


理想的なROC曲線は、以下のようにFPRが0のときにTPRが1になっている曲線です

f:id:minmin_21:20190331121531p:plain
best_ROC


逆に良くないROC曲線とは、以下のような曲線です
(AUC=0.79は悪すぎる例ではないと思うのですが、そこはスルーしてください笑)

f:id:minmin_21:20190331121548p:plain
bad_ROC

上の二つを比較してみると、ROC曲線の内側の面積が広い方が良いROC曲線ということが分かると思います

AUCはこの内側の面積を定量的に表したものになり、理想的なROC曲線のAUCを1としてそれを基準に評価した指標になります

参考

recall?precision?機械学習モデルの評価尺度についてまとめる

recall, precision, accuracy F値など機械学習モデルの評価尺度はいろいろあるのですが、どれがどれだかよくわからなくなってしまうのでまとめてみました

今回は1か0を予測する問題について考えたいと思います
※正例は1とします

はじめに

これからの説明に使用するので、以下に混同行列を書いておきます
混同行列(confusion matrix)とは予測結果と実際のデータを比較するときに使用する表のことです

f:id:minmin_21:20190323151512p:plain
confusion_matrix

これもどれがFPでどれがFNだか分からなくなってしまうのですが、

  • 予測結果と実際のデータがあっているものがT, そうでないものがF
  • 予測結果が正例である場合はP, 負例である場合はN

と覚えておけば大丈夫です

各評価指標の解説

accuracy

accuracyは以下の式で表されます


accuracy=\frac{TP+TN}{TP+FP+FN+TN}

accuracyは、すべてのデータにおいて正解したものの割合はどのくらいかを表した指標になります

これはイメージしやすいと思います

recall

続いてrecallです

recallは以下の式で表されます


recall=\frac{TP}{TP+FN}

recallは実際の正例の中(TP+FN)から、モデルがどれだけ拾えているかをあらわした指標です

つまり、どれだけ正例を見逃していないかということになります

モデルの予測結果をすべて正例にしてしまえば、必然的にrecallは1となります

precision

precisionは以下の式で表されます


precision=\frac{TP}{TP+FP}

precisionは正例と予測したもの(TP+FP)の中に、どれだけ実際の正例があるかを表した指標です

つまり、正例をどれだけ命中させたかということになります

絶対に正例だと思うものだけ正例にしてしまえば、precisionは高くなります

F値

F値は以下の式で表されます


F_{score} = \frac{2recall*precision}{recall+precision}

上のrecall, precisionでも説明したように

  • recallを高くするようにモデルを極端に学習させた場合->全て正例と判断し、precisionが低くなる
  • precisionを高くするようにモデルを極端に学習させた場合->正例と予測されるものが少なくなり、recallが低くなる

とrecallとprecisionはトレードオフの関係にあることがわかります

そこで、極端にモデルを学習させることなくrecallとprecisionを良い感じにするための指標としてF値があります

まとめ

  • accuracy
    • 純粋な正解率
  • recall
    • どれだけ正例を見逃していないか
  • precision
    • 正例をどれだけ命中させたか
  • F値
    • 極端にモデルを学習させることなくrecallとprecisionを良い感じにするための指標

参考

ユースケースごとによく使うgitコマンドを紹介する

備忘録としてgitでよく使うコマンドをユースケースごとに紹介したいと思います
随時アップデートしていく予定です

※本記事で紹介しているコマンドで事故ったとしても責任は負えないので、自己責任で参考程度にお使いいただければと思います

変更を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上での表示

      f:id:minmin_21:20190303095100p:plain
      jupyter notebookのサンプル

    • git上での表示
      printした結果や実行回数まで差分として出力されてしまう

      f:id:minmin_21:20190303095331p:plain
      jupyte notebookのgit上での表示

  • データ分析を行う際に、jupyter notebookを使いたい派 vs 使いたくない派の戦争が発生する(?)

    • 使いたい派:step by stepで途中経過を確認しながら分析したい
    • 使いたくない派: コードが煩雑になりがちなので、出来れば.pyファイルを使いたい

jupytextとは


  • jupyter notebookをpython script(.py)として保存することができるツール

    • .ipynbファイル(左)、変換された.pyファイル(右)
      f:id:minmin_21:20190303095331p:plainf:id:minmin_21:20190303095441p:plain
      .ipynbファイルと変換された.pyファイルの比較
  • 他にも以下のような機能がある

基本的な使い方


使い方はとても簡単で、以下の3ステップを実行するだけ!!

  1. pip install jupytext
  2. ~/.jupyter/jupyter_notebook_config.py内の末尾に以下を追加
    • c.NotebookApp.contents_manager_class = "jupytext.TextFileContentsManager"
  3. 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ファイルが作成される
|--- 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が作成された。

f:id:minmin_21:20190303095733p:plain
変換された.mdファイル

参考


docker-composeの使い方

docker-composeの使い方について、備忘録として簡単にまとめておきます。
ゼロからはじめる Dockerによるアプリケーション実行環境構築 | Udemyで学んだことを基本に、docker-composeの使い方をまとめてみました。

docker-composeとは

複数のコンテナを使用したアプリケーションを定義・実行するツール
複数のコンテナを利用し疎結合なサービスにすることで、保守性や可読性が高まります。

docker-compose実行の手順

  1. Dockerfile or 使用するイメージの用意
    • 各コンテナを立ち上げるための準備(Dockerfileの書き方とかは本記事では言及しません)
  2. docker-compose.ymlの作成
    • サービスをどのように構成するかが記述されているファイル
  3. 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では、実行場所と実行ファイルの場所が一致しているはずという前提のもと解決しているので、

参考

最後に

解決方法は拍子抜けするほど簡単でした、、
この問題に引っかかって解決するまで20分ぐらい時間がかかった気がするので共有します
はじめてこういうものを書いてみたので慣れていないのですが、こっちの方が良いよ等の意見があればコメント・twitter等でお待ちしております。