1
0

More than 3 years have passed since last update.

リストワイズ除去のツリーを簡単に計算する関数(Python)

Last updated at Posted at 2021-01-06

本記事について

  • 疫学研究等で目にする、Fig1.本研究の解析対象者 のツリーを素早く計算する関数を書いた。
  • リストワイズ除去を行った際のツリーを想定する。
  • コードはPythonであるが、記事内にてRより呼び出す方法も追記した。
  • SQLでいう所の分析関数をpythonで実装ただけである。

そもそもリストワイズ除去のツリーって?

こんなヤツ↓ エクセルでシコシコ関数組んでると平気で半時間とかかかったり。(目や腰もいたくなるね)

risttttt.png

(この図に正式名称があればご教示ください)

 何が面倒くさいの?

単にそれぞれの変数の欠測数を乗せるだけならdf.isnull.sum()で終了ですが、、

  1. x1の欠測は●人でした。
  2. x1の欠測を除いたデータにおいて、x2の欠測は▲人でした。
  3. x1と、x2の欠測を除いたデータにおいてx3の欠測は■人でした。
  4. ・・・

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ライブラリ を使用する。(追記するかも)
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0