KaggleのOSICコンペ概要と反省

2020/10/12に公開

この記事の概要

KaggleのOSICコンペに参加して、231位でした。

かなりやり込んだので、自信があったんですけどね。コンペの概要を説明しつつ、やったこととか、反省点をまとめて行きたいと思います。

コンペの概要

肺繊維症とは

肺繊維症については、【Kaggle】Osic肺線維症コンペ振り返りが詳しかったので、一部引用。

肺胞壁に炎症や損傷が起こり、壁が繊維化(厚く、硬くなること)することで、本来の機能である酸素を赤血球に与え、二酸化炭素を取り出すガス交換が上手くできなくなる希少疾患です。
残念ながら原因、治療法ともに不明であり、日本では指定難病になっています。症状を抑える薬はありますが治療法がないため、患者さんの予後は基本的には悪いです。ただ、患者さんによって予後には大きなばらつきがあり、急激に悪化する人もいれば、比較的安定した予後の人もいて、その予測は困難です。

(引用)難病情報センター
患者さんの予後が予測できれば、患者さんの人生設計であったり、薬の投与計画などの見通しが立てやすくなりますので、今回Kaggle上でコンペが開催された、ということになります。

データについて

target

今回提出する必要があるのは、FVC(forced vital capacity)とConfidenceです。

FVCとは、日本語では、「努力性肺活量」と訳され、「精一杯息を吸った後、精一杯吐き出した空気の量」です。(https://www.zai-kkc.or.jp/doc/glossary02/lung_function.pdf より)
よく聞くことがある、「肺活量(vital capacity)」とは異なる量であり、FVCは、肺活量の80%以上あれば正常とされているようです。

Confidenceは、自信度で、FVCの予測に自信がある場合は小さく、自信がない場合は大きく提出すると、良いスコアになるようになっています。詳しくは評価指標の箇所で説明します。

学習データとTarget

トレーニングデータには、176人分のデータがあります。
それぞれのデータは、6回ないし10回のFVCの測定結果と、年齢、性別、喫煙状況、Week0のCT画像があります。

例えば1人目の ID00007637202177411956430のデータは、Week-4, 5, 7, 9, 11, 17, 29, 41, 57の9回のFVCのデータと、Week0のCT画像となっています。

テーブルデータは、このようなデータです。性別、年齢、喫煙状況は変わらないので、とてもシンプルなデータです。

グラフにするとこんな形。

Percentというのは、FVCが、その人の年齢・性別・人種などから決まる標準的なFVCとの比率であり、FVCと完全に相関します。

またCT画像の1つを表示してみたのが次です。

テストデータ

テストデータは、初めてのFVC測定時のデータと、Week0でのCTスキャンの画像が与えられます。

このテストデータの患者は、Week6が初めてのFVCの計測であり、Week0でとったCTスキャンのデータも与えられます。

また、サブミットは、リーク防止のため、テストデータのWeek-12からWeek133までの予測値を全て提出します。評価に使われるのは、その患者が実際にFVCを計測した最後の3回のみであり、どの週が使われたかはわかりません。

また、LBProbingから、テストデータには188人分のデータがあることと、学習データとテストデータでPatientIDに重複がないことがわかっています。https://www.kaggle.com/c/osic-pulmonary-fibrosis-progression/discussion/183079

評価指標

FVCの予測値であるFVC_{predicted}と自信度である\sigma(confidence)から、評価指標は次のように計算されます。

metricの第1項にのみFVC_{predictred}が含まれており、confidenceは第1項と第2項の両方に含まれています。

\Delta = \min(|FVC_{true} - FVC_{predicted}|, 1000)の値が、0, 100, 200, 300, 400, 500の場合のconfidenceによるmetricの値を描いてみたのが次の図です。

この評価指標は、初めて見た種類の指標でよくわかりませんでしたが、この様に\Delta(FVC予測の誤差)を固定して、Confidenceに応じたmetricを描くことで、コンペ中にもイメージを掴むことができました。

このタスクについて

このように、与えられるデータは、176人分のデータと少なく、Week0でのCTスキャン画像と、9回くらいのFVCの測定結果と性別・年齢・喫煙状況から、他の患者の将来のFVCの値を予測するというタスクになります。

多くは、だんだんとFVCが小さくなるというデータになっていたので、Weekが進むに連れてFVCが減少するという予想をしておけば大きく外しはしないという印象です。ただ、大きくFVCが回復する患者がいることや、ある週の計測のみ小さかったり、大きかったりする患者がいたことから、そのような外れ値にも対応する必要があるというコンペだったと思います。

最終モデル

最終モデルは、ツイートした次のもの。(確認すると少し間違っていました)

上のツイートでは間違っていたので、もう1度書きます。

  1. FVCの予測を、Ridgeとサンプルウェイトを変えたCatboost3モデルの4モデルで行う。
  2. 最後の3サンプルのMAEが最小になるようにsp.optimize.minimizeを用いて①の予測値をアンサンブル。
  3. ②で求めたFVCの予測値を基に、最適なConfidenceをsp.optimize.minimizeで求める。
  4. ③のConfidenceをtargetに、LightGBMとCatboostでConfidenceを予想する。
  5. 最後の3サンプルのmetricが採用になるようにsp.optimize.minimizeを用いて④をアンサンブル。

NNも何度も試したが、サンプルが少ないのか、トレーニングデータに過学習してしまい(trainのlossがゼロにすぐ近づき、cvがあまり良くならず)、常にweight0で採用できず。
notebookで流行っていた、quantile regressionも試しましたが、あまり良い結果にはならず。一応filan submissionの1つは、quantile regressionでConfidenceを予測して⑤のアンサンブルに加えるのも選びました。

また、1.と4.の画像の特徴は、最終的には、このドメインで採用されているものを自分で作っていれる形となりました。
このpdfなどとても参考になりました。コンピュータによる間接性肺炎のCT画像の定量評価

これらの肺の容量、肺部分の平均、歪度、尤度や肺部分の周りとの差分をとっての統計量はかなり効きました。

Lateサブ

何が悪かったのか、確認するためにLateサブしてみました。

患者毎に最後の3サンプルに着目して、earlystoppingやアンサンブルをこの3サンプルだけで行う。

評価に使われるデータは、各患者の最後の3サンプルだけであることから、自分は学習データの最後の3サンプルだけをearlystoppingやアンサンブルで対象にしていました。

Lateサブの結果は次の通り。

FVC_all_MAE FVC_last_three_MAE cv_metric_all cv_metric_last_three pulic private
last3サンプルで実施 141.2 188.5 - -6.91145 -6.8777 -6.8695
全部で実施 138.7 190.9 -6.50520 -6.9385 -6.8876 -6.8734

最後の3サンプルに着目するのは、した方が良さそうです。このコンペの目的も最後の3サンプルについて精度が欲しいということだし、後ろの方(CT計測からの時間が経ってから)の予測の精度を高めたいというのは、ドメイン的にも意義があるのでやって良かったんじゃないでしょうか。

これをやる、デメリットはサンプル数が少なくなるので、overfitしてしまうリスクはあるかも。

コンペ後には、ラスト3サンプルに限定するのではなく、割合で抽出して、earlystopping・アンサンブルをするのがベストだったかもと思いました。

学習データの水増し

これは、コンペ開始後すぐにNakamaさんNotebookで公開された学習データの作り方です。

これは、本来、テストデータは、患者のFVC初計測の値のみが与えられるので、学習データは次の様にしか作れず行数も増えないのですが、学習データの初計測以外のFVCの結果も、初計測(下の画像でいうBase)にしてしまおうという、データの水増しです。
文字で書いてもわかりにくいので、データフレームで表すと次の様になります。

与えられた学習データ

通常の学習データの作り方

1番上のデータは除くので、学習データは8行になる。

水増しをした場合


水増しをしたものは長くなるので下の方を省略していますが、全部で72行(9 x 8)となります。

メリットとしては、データ数が増えること。
デメリットとしては本来(testデータでは)、FVC初計測のデータのみが与えられるところ、学習データでは初計測以外もbase_FVCになり得るように拡張したため、データ(ドメイン)によっては悪影響を与えることもあると思います。

この様にデータを作りLateサブをしたところ次の結果となりました。

FVC_all_MAE FVC_last_three_MAE cv_metric_all cv_metric_last_three pulic private
水増しなし 141.2 188.5 - -6.91145 -6.8777 -6.8695
水増しあり (152.1802) (165.2962) (-6.6910) (6.7775) -6.9131 -6.8602
  • 水増しなしとありでは、計算しているサンプルが異なるので、cvは比較できない。
  • publicは0.04程度悪化したが、privateは0.01弱良くなった。

今回のデータだとやっても良かったし、初めの方のweekのみをBaseにする拡張をするなど工夫すればもう少し良くなるかもしれません。

反省

もう少しLateサブしたいところですが、とりあえずここでやめておきます。(Code CompetitionはLateサブが面倒だ。。。)
上位のサブはあまり読めていないので、かけませんでした。
【Kaggle】Osic肺線維症コンペ振り返り#上位解法など、読みましょう。

反省点としては、次のことでしょうか。

  • Nakamaさんが公開されていたトレーニングデータの作り方を試すべきだった。
  • NNで良いモデルを作るべきだった。画像からの特徴抽出も含めて。
  • 上の2つを検証するために、学習データを、trainとdevに分けて検証するべきだった。
    • この学習データをtrainとdevに分けて、devをpublicLBとして扱う検証の仕方なんていうやり方なんでしょう。
  • コンペ中に、submission errorが連発する時期があって(コードにバグがあって)、その解決に時間を費やしすぎてしまった。

金メダル取れると思っていて、全然ダメな順位だったので、Kaggleで良い順位をとりたくなりました。次のコンペ頑張ります。

Discussion