랜덤 생존 포레스트를 이용한 암 유전자 생존 데이터 분석하기, 고차원 데이터와 중도 절단 자료

유전 정보 분석이 비교적 쉬워진 요즘 시대에는 암 데이터에 유전자 데이터가 함께 있는 경우가 많다. 이런 데이터를 분석할 때 맞닥뜨리는 문제는 분석된 유전자가 한 두개가 아니라 수 백개에 달한다는 것이다. 이런 문제를 고차원 문제 (High dimensionality problem)이라고 한다. 가지고 있는 데이터보다 분석해야할 유전자가 많은 경우이다. 

 

생존 데이터이기 때문에 발생하는 문제도 있다. 우리가 어떤 사람의 특성 x와 생존 기간 y의 관련성을 파악하려고 한다고 하자. 어떤 사람이 10개월 생존하고 사망했다고 하면, 그 사람의 관측된 생존 기간 y는 단순하게 10개월로 생각할 수 있다. 하지만 만약 10개월 째 생존해있었다고 하면 문제가 발생한다. 그 사람이 앞으로 오래오래 살아서 500개월 뒤에 사망할지, 갑자기 질병이 진행해서 11개월 째 사망할지 관측 시점에서는 도무지 알 수가 없기 때문이다. 즉 그 사람의 관측될 생존기간 y는 알 수 없다. 이런 것을 절단 자료 (censored data)라고 한다.

 

고차원 데이터의 분석법

고차원 데이터를 분석하는 방법은 여러가지가 있다.

1. LASSO (Least Absolute Shrinkage and Selection Operator)

2. 주성분 분석 Principal Component Analysis (PCA)

3. t-distributed Stochastic Neighbor Embedding (t-SNE)

4. Random Forests

5. Elastic Net

 

나는 여기에서 Random Forest를 먼저 이용해보기로 했다.

 

Random Forest이란?

랜덤 포레스트란 앙상블 학습을 이용한 분석 방법이다. 앙상블은 음악에서 합창, 합주를 의미하는 단어이다. 그 말처럼 앙상블 학습은 하나의 데이터에 여러가지 모델을 적용한 뒤 각 모델의 결과를 모아서 결과를 내는 학습 방법을 의미한다. 결과를 모으는 것은 다수결로 할 수도 있고, 평균으로 할 수도 있다.

분류 모델의 경우 0 아니면 1 이야하므로 다수결로 가게 되고, 회귀 모델의 경우 연속 변수로 결과가 나오므로 평균으로 결과를 내게 된다.

 

랜덤 포레스트는 여러가지 의사결정나무 Decision Tree를 이용한 앙상블 학습이다. 의사 결정 나무가 모여서 숲 (Forest)를 만들어 결론을 도출하는 기법이라 이름이 그렇게 지어졌다.

 

 

의사결정나무란?

그럼 의사결정나무에 대해서 알아보도록 하자.

100개의 데이터가 있다. 그리고 각 데이터는 X1, X2, X3, X4, X5 이라는 특성과 Y라는 값으로 이루어져있다.

 

 

뿌리마디가 결정되는 과정을 시뮬레이션해보자.

일단 X1으로 데이터를 분류해본다. 분류한 뒤의 데이터가 얼마나 분류가 잘 되었는지 계산한다.

이를 계산하는 함수는 Gini 함수, 엔트로피 함수 등이 있다.

회귀 문제의 경우에서는 분류한 뒤의 분산이 얼마나 작아지는지로 분류가 잘 되었는지를 계산하곤 한다.

X2, X3, X4, X5에 대해서도 데이터를 각각 다 분류해보고 분류가 잘 되었는지 계산한다.

X1 ~ X5 중 어떤 기준으로 분류했을 때 가장 분류가 잘 되었는지 판단한다.

 

만약 X3로 분류했을 때 분류가 잘 되었다고하면 이제 X3로 데이터를 분류하고 그 다음 마디로 넘어간다.

 

그 다음 마디에서는 X1, X2, X4, X5로 위와 같은 과정을 똑같이 진행한다.

 

이렇게 만들어진 나무가 바로 의사결정나무이다.

 

랜덤포레스트에서 의사결정나무를 만드는 법

그럼 랜덤포레스트에서 의사결정나무는 어떻게 만들까?

랜덤포레스트는 2가지 의미에서 랜덤이다.

 

1. 데이터 선택을 랜덤으로 일부만 선택

2. 특성을 랜덤으로 일부만 선택

 

150개 정도의 샘플이 있고, 샘플의 데이터의 특성이 500개 정도 되는 고차원 데이터를 생각해보자.

랜덤포레스트를 구성하는 개별의 나무는 데이터의 일부만 뽑아서 사용된다.

 

예를들면 150개 샘플 중 50개의 샘플만 이용하고,

데이터의 특성 중 30개만 뽑아서 그것만 이용하여 분류 나무를 만드는 그런 식이다.

 

 

생존데이터로 랜덤포레스트 이용하기

생존 데이터로 랜덤 포레스트를 이용하려면 기존의 랜덤 포레스트를 확장 시킨 랜덤 생존 포레스트 (Random Survival Forest)를 이용하면 된다. 분류와 회귀 방정식을 이용했던 기존의 랜덤 포레스트와 달리 여기에서는 Nelson-Aalen estimator나 Kaplan-Meier estimator를 이용한다. 기존에는 데이터 불순도 지수인 Gini 지수나 분산을 이용하여 분류 정도를 판단했었다면 여기에서는 Log-rank 함수 등을 이용하여 데이터 분류가 잘 되었는지 판단하게 된다. 

 

 

 

랜덤포레스트 코드

import numpy as np
import pandas as pd
from sksurv.ensemble import RandomSurvivalForest
from sksurv.util import Surv

df = pd.read_csv('your_filename.csv')

# 필요없는 cloumns 
excluded_columns = ['sample', 'tumor', 'margin']

# Survival outcomes가 담겨있는 columns
survival_columns = ['progression', 'PFS', 'death', 'OS']

# Features dataframe은 다음과 같이 정의된다
X = df.drop(columns=excluded_columns + survival_columns)

# Survival outcome은 다음과 같이 정의된다.
event = 'progression'
time = 'PFS'
y = Surv.from_dataframe(event=event, time=time, data=df[survival_columns])

# Random SUrvival Forest 만들기
rsf = RandomSurvivalForest(n_estimators=100,
                           max_depth=None,  # You can specify the max depth or leave it as None for unlimited
                           random_state=42)
rsf.fit(X, y)

 

 

 

랜덤생존포레스트의 성능 평가 - Concordance Index

predictions = rsf.predict(X)

# Evaluate the model
score = rsf.score(X, y)
print("Concordance index:", score)

 

위 코드를 이용하여 Concordance index를 계산할 수 있다.

 

Concordance index는 다음과 같이 계산하는 index이다.

Patient Time Event Predicted Risk
A 10 1 0.8
B 15 1 0.6
C 12 0 0.3
D 20 1 0.5
E 8 1 0.7

 

1. Patient 쌍을 만든다. 반드시 Event = 1인 환자가 한명은 포함되어 있어야 한다.

2. Concordance 한지 Discordant 한지, tie인지 확인한다.

- Concordance: Predicted risk가 높은 환자가 실제로 일찍 event가 발생하면 concordant

- Discordance: Predicted risk가 높은 환자가 더 늦게 event가 발생하면 discordant

- Tie: Event 발생 시점 유무와 상관없이 predicted risk가 같으면 tie로 계산한다.

 

예) A, C의 경우 A는 10개월째 사망, C는 절단된 자료지만 최소한 10개월째까진 사망 event가 발생하지 않은 것으로 볼 때 A보다 생존 기간이 길다. A의 risk가 C보다 높으므려 이건 concordant한 자료이다.

 

전체 쌍 중에서 (Concordant 쌍의 수 + 1/2 x tie 된 쌍의 수)의 비율이 얼마인지가 Concordance index이다.