欠測の取り扱い

例えば、臨床研究などでデータを収集していると、何らかの理由で検査ができなかったりなどで、どうしても取得できなかったデータなどが出てくる。
このような一部の項目が欠けてしまったデータは欠測のあるデータという。

欠測のあるデータはそのままでは統計に流せない(NaNやNullは数値ではない)。
この対処例として、欠測を含むデータは解析セットに含めない、あるいは、欠測を何らかの値で補完する方法がある。

ほとんどの場合、解析セットから欠測を含むデータを除外してしまう方法がとられるかもしれない。

しかし、除外されるデータが決定境界に影響を与えるかもしれないという可能性は否定できない。できればこれは避けたい。どうするか。 

このような疑問に真摯に対応しようとするのが補完という対応である。
補完は、切り捨てるメリット、切り捨てないメリット、両方のいいところを残していい塩梅を探そうとする。

ただし、前提として、欠測を推定した値が正確であったかどうかはわからないため、適用しても問題ないだろうと思われる落としどころを探すことが必要になる(PMM感度分布解析)。 

多少面倒だが、欠測が起こる契機についても考慮しておく必要がある。
欠測が本当に偶然に起こっている場合(missing at random)と、何かの要因でシステマチックに欠測としている場合などがある。 

基本的に、統計的にも、バイアスを除外したいというモチベーションから、たまたま欠損した場合には補完で対処しようというアプローチが許容されやすい。 

欠測の補完方法は大きく分けて2つある。 欠測値がある場合、その欠測値を含む観測データを除外できれば良いが、そうできないとき、穴埋めを行う。これをインピューテーションという。 単一値の補完や予測補完が可能である。 

対照試験では、対照群のデータを使って補完する「pMI」という手法が用いられることがある。しかし、欠損した値の補完であることに変わりはないので、インピュートしたデータでの解析結果は、試験の有効性というより、有用ということを主張するための手段となるようである(主張が弱まる)。 SASではインピューテーションの影響をpMIで感度分析するアルゴリズムがある。

単一補完法


1つの欠測に対して1つの値を補完する。(例えば、Last Observation Carried Forward(時系列に取得していたなら、最後に取得できた値で代用する方法)、同じ系列の値の中央値、平均値、最頻値などによる単純な補完)。

多重補完法


欠測値を他の特徴量から回帰計算して予測する。

現在は後者の多重補完が主流のようである。どちらが正しいということではなく、双方をいかに使うかが大切といえるだろう。
研究者間でも意見が分かれるところである。個人的には、単一補完単体はテストケースで利用し、精度を検証するような厳密な解析では多重補完という感じではないだろうか。もっと言えば、両方試して傾向が同じかどうかを確かめておくことも必要と思う。

欠損値の補完:MICE



  # data load
  # https://drive.google.com/file/d/1f1MoJj0-SJwPXzvGQTB2ycg-MeJFWtLO/view?usp=sharing
  #MissingAtRandom
  !curl -L -o "MAR.csv" "https://drive.google.com/uc?export=download&id=1f1MoJj0-SJwPXzvGQTB2ycg-MeJFWtLO"
  
  # データをテーブルにします
  import pandas as pd
  # "group":群,"timepoint":時点,"Y":事象(死亡、打ち切り)
  data = pd.read_csv(filepath_or_buffer="MAR.csv" ,encoding="utf-8")[["ID","Group","W0","W1","W3","W6"]]
  print(data.head())
  
  # impute NaN
  from sklearn.impute import SimpleImputer
  imp = SimpleImputer(missing_values=np.nan, strategy='mean')
  imp.fit(data[["W0","W1","W3","W6"]].values.tolist())
  imputedValues = imp.transform(data[["W0","W1","W3","W6"]].values.tolist())
  imputedValues = pd.DataFrame(imputedValues,columns=["W0","W1","W3","W6"])
  imputed = pd.DataFrame(pd.concat([data[["ID","Group"]],imputedValues],axis=1),columns=["ID","Group","W0","W1","W3","W6"])
  print("imputed! \n",imputed.head())
  # save as csv NaN does not included by imputes
  # data3.to_csv('RepeatedMeasureANOVA_mod_postImpute.csv')