#本記事について
- 疫学研究等で目にする、Fig1.本研究の解析対象者 のツリーを素早く計算する関数を書いた。
- リストワイズ除去を行った際のツリーを想定する。
- コードはPythonであるが、記事内にてRより呼び出す方法も追記した。
- SQLでいう所の分析関数をpythonで実装ただけである。
そもそもリストワイズ除去のツリーって?
こんなヤツ↓ エクセルでシコシコ関数組んでると平気で半時間とかかかったり。(目や腰もいたくなるね)
(この図に正式名称があればご教示ください)
# 何が面倒くさいの?
単にそれぞれの変数の欠測数を乗せるだけなら**df.isnull.sum()**で終了ですが、、
- x1の欠測は●人でした。
- x1の欠測を除いたデータにおいて、x2の欠測は▲人でした。
- x1と、x2の欠測を除いたデータにおいてx3の欠測は■人でした。
- ・・・
SQLで言うところの分析関数のような物を書く必要があるんですよね。
あぁ面倒くさい(pythonでは)。
では、本題へ
import pandas as pd
import numpy as np
def caluculate_missing_tree(df):
d ={}
d[0]= df.loc[df[df.columns[0]].isnull() != True]
for i in range(len(df.columns)-1):
d[1+i]= d[i].loc[d[i][d[i].columns[1+i]].isnull() != True]
le = []
colnames = []
missing_tree = pd.DataFrame()
for i in range(len(df.columns)):
le.append(len(d[i]))
for i in range(len(df.columns)):
colnames.append(df.columns[i])
missing_tree['col_name'] = colnames
missing_tree['Size'] = le
return missing_tree
caluculate_missing_tree() の引数に、ツリーを描きたい順番に変数が入っているデータフレームをぶち込むだけです。
たとえば、titanicのデータで試してみる。
import pandas as pd
import numpy as np
import os
df = pd.read_csv("train.csv")
df.shape #(891, 12)
df.isnull().sum() # それぞれの変数の欠測数
--------------------------------
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
こいつを今回の関数に食わせると・・
caluculate_missing_tree(df)
--------------------------------------
col_name Size
0 PassengerId 891
1 Survived 891
2 Pclass 891
3 Name 891
4 Sex 891
5 Age 714
6 SibSp 714
7 Parch 714
8 Ticket 714
9 Fare 714
10 Cabin 185
11 Embarked 183
一瞬で計算できた。嬉しい。
中身の説明
.loc を使用して、条件に合う(欠測していない)データセットをどんどん作っていけば良いのではという発想。
df <- 元のデータ
df1 = df.loc[df['x1'].isnull() != True]] <- x1 の欠測が除かれたデータ
df2 = df1.loc[df1['x2'].isnull() != True]] <- x1, x2の欠測が除かれたデータ
df3 = df2.loc[df2['x3'].isnull() != True]] <- x1, x2, x3の欠測が除かれたデータ
...
...
こんな感じ。
さらに、for文書くことまで考えてみるとこんな感じ。
d[0]= df.loc[df[df.columns[0]].isnull() != True] <- ここはfor文の外
--- こっからfor のイメージ ---
d[1]= d[0].loc[d[0][d[0].columns[1]].isnull() != True]
d[2]= d[2-1].loc[d[2-1][d[2-1].columns[2]].isnull() != True]
d[3]= d[3-1].loc[d[3-1][d[3-1].columns[3]].isnull() != True]
しかし、for文でdfの作成を自動化するのが少々難儀だった。
複数のデータフレームを格納するリストを作成。そこに、それぞれの変数に対応するデータフレームを格納していくという手法を使用した。
d ={}
d[0]= df.loc[df[df.columns[0]].isnull() != True]
for i in range(len(df.columns)-1):
d[1+i]= d[i].loc[d[i][d[i].columns[1+i]].isnull() != True]
こんな感じ。例えばtitanicのデータでは、
・d[0]はPassengerID
・d[1]はPassengerID, Survived
・d[2]はpassengerID, Survived, Pclass の欠測に対応している。
その後、確認を容易にするために、変数名とサンプルサイズを列名に持つデータフレームを作ろうという発想になるのは必然であろう。
le = []
colnames = []
missing_tree = pd.DataFrame()
for i in range(len(df.columns)):
le.append(len(d[i]))
for i in range(len(df.columns)):
colnames.append(df.columns[i])
missing_tree['col_name'] = colnames
missing_tree['Size'] = le
return missing_tree
leにそれぞれの変数の欠測値を消去したデータフレームのlen(df.columns)を格納していった。同様に、colnamesにそれぞれのデータフレームに対応する変数名を格納し、可視化した。
caluculate_missing_tree(df)
--------------------------------------
col_name Size
0 PassengerId 891
1 Survived 891
2 Pclass 891
3 Name 891
4 Sex 891
5 Age 714
6 SibSp 714
7 Parch 714
8 Ticket 714
9 Fare 714
10 Cabin 185
11 Embarked 183
ジャジャーン(2度目)
Rでの実装方法
- Rnotebookと reticulateライブラリ を使用する。(追記するかも)