[R] 로지스틱 회귀분석을 통한 유방암 예측(분류) (3/4): 1차 변수 선택 및 목표변수와 설명변수 간 관계 분석
이번 포스팅은 로지스틱 회귀분석을 통한 유방암 예측(분류) 포스팅의 세번째 순서로서 '1차 변수 선택 및 목표변수와 설명변수 간 관계 분석' 차례입니다.
|
사실, 이번 포스팅도 '2. 탐색적 데이터 분석 및 전처리'에 포함시켜도 되는데요, 두번째 포스팅이 미친듯이 내용이 많고 포스팅이 길어져서 스크롤 압박이 너무 심했던지라 가독성을 위해서 세번째 포스팅으로 분리를 했습니다.
(1) t-test 를 통한 1차 변수 선별 |
진단 결과(악성 M, 양성 B) 그룹별로 설명변수 간의 차이가 존재하는지 t-test 검정을 해보고, p-value가 0.05 를 초과하는 설명변수는 1차 제거하는 것으로 하겠습니다.
특히 연속형 설명변수 개수가 상당히 많고, 종속변수가 2개의 범주(class)를 가지는 경우 t-test 를 활용해서 1차로 별 효용성이 없는 설명변수를 screening out 하는데 활용할 수 있습니다.
> # Variable selection (1st round) > # Multiple t-tests of explanatory variables between diagnosis > X_names <- names(data.frame(X_3)) > X_names [1] "texture_mean" "smoothness_mean" "concave.points_mean" [4] "symmetry_mean" "fractal_dimension_mean" "texture_se" [7] "perimeter_se" "smoothness_se" "compactness_se" [10] "concavity_se" "concave.points_se" "symmetry_se" [13] "fractal_dimension_se" "area_worst" "smoothness_worst" [16] "symmetry_worst" "fractal_dimension_worst" > > t.test_p.value_df <- data.frame() # blank data.frame for saving > > for (i in 1:length(X_names)) { + t.test_p.value <- t.test(wdbc[,X_names[i]] ~ wdbc$diagnosis, var.equal = TRUE)$p.value + + t.test_p.value_df[i,1] <- X_names[i] + t.test_p.value_df[i,2] <- t.test_p.value + } > > colnames(t.test_p.value_df) <- c("x_var_name", "p.value") > t.test_p.value_df x_var_name p.value 1 texture_mean 4.058636e-25 2 smoothness_mean 1.051850e-18 3 concave.points_mean 7.101150e-116 4 symmetry_mean 5.733384e-16 5 fractal_dimension_mean 7.599368e-01 6 texture_se 8.433320e-01 7 perimeter_se 1.651905e-47 8 smoothness_se 1.102966e-01 9 compactness_se 9.975995e-13 10 concavity_se 8.260176e-10 11 concave.points_se 3.072309e-24 12 symmetry_se 8.766418e-01 13 fractal_dimension_se 6.307355e-02 14 area_worst 2.828848e-97 15 smoothness_worst 6.575144e-26 16 symmetry_worst 2.951121e-25 17 fractal_dimension_worst 2.316432e-15
|
위의 17개 설명변수별 t-test 결과를 좀더 보기에 편하도록 p.value를 기준으로 작은 것부터 큰 순서대로 dplyr 패키지의 arrange() 함수를 사용하여 정렬해보겠습니다.
> # sorting by p.value in ascending order > install.packages("dplyr") > library(dplyr) > arrange(t.test_p.value_df, p.value) x_var_name p.value 1 concave.points_mean 7.101150e-116 2 area_worst 2.828848e-97 3 perimeter_se 1.651905e-47 4 smoothness_worst 6.575144e-26 5 symmetry_worst 2.951121e-25 6 texture_mean 4.058636e-25 7 concave.points_se 3.072309e-24 8 smoothness_mean 1.051850e-18 9 symmetry_mean 5.733384e-16 10 fractal_dimension_worst 2.316432e-15 11 compactness_se 9.975995e-13 12 concavity_se 8.260176e-10 13 fractal_dimension_se 6.307355e-02 14 smoothness_se 1.102966e-01 15 fractal_dimension_mean 7.599368e-01 16 texture_se 8.433320e-01 17 symmetry_se 8.766418e-01
|
t-test의 p-value가 0.05 보다 큰 값을 가지는 설명변수인 'symmetry_se', 'texture_se', 'fractal_dimension_mean', 'smoothness_se', 'fractal_dimension_se' 의 5개 설명변수는 1차로 제거하고, 나머지 12개 설명변수만 로지스틱 회귀모형 적합하는데 사용하도록 하겠습니다. (말그대로 1차 선별이구요, 나중에 후진소거법으로 추가로 더 변수 선택할 예정입니다)
위의 1차 선별된 12개 설명변수만을 포함한 데이터프레임 X_4를 만들었습니다.
> # select x_variables only if p.value < 0.05 > t.test_filtered <- t.test_p.value_df$p.value < 0.05 > X_names_filtered <- X_names[t.test_filtered] > > X_4 <- data.frame(X_3[, X_names_filtered]) > str(X_4) 'data.frame': 569 obs. of 12 variables: $ texture_mean : num -2.072 -0.353 0.456 0.254 -1.151 ... $ smoothness_mean : num 1.567 -0.826 0.941 3.281 0.28 ... $ concave.points_mean : num 2.53 0.548 2.035 1.45 1.427 ... $ symmetry_mean : num 2.21557 0.00139 0.93886 2.86486 -0.00955 ... $ perimeter_se : num 2.831 0.263 0.85 0.286 1.272 ... $ compactness_se : num 1.3157 -0.6923 0.8143 2.7419 -0.0485 ... $ concavity_se : num 0.723 -0.44 0.213 0.819 0.828 ... $ concave.points_se : num 0.66 0.26 1.42 1.11 1.14 ... $ area_worst : num 2 1.89 1.46 -0.55 1.22 ... $ smoothness_worst : num 1.307 -0.375 0.527 3.391 0.22 ... $ symmetry_worst : num 2.748 -0.244 1.151 6.041 -0.868 ... $ fractal_dimension_worst: num 1.935 0.281 0.201 4.931 -0.397 ... |
(2) 목표변수와 설명변수 간 관계 분석 (시각화) |
(2-1) 박스 그림 (Box Plot)
다음으로 12개 설명변수에 대해서 진단결과(악성: M, 1 vs. 양성: B, 0) 별로 집단을 분리해서 박스 그림(Box Plot)을 그려서 비교를 해보겠습니다.
그래프로 보기에 편리하도록 표준화한 데이터셋을 p.value 기준으로 변수의 순서를 정렬한 후에 Y값(diagnosis)과 합쳐서 새로운 데이터셋을 만들었습니다.
> # sorting by p.value in descending order > # t.test_p.value_df.sorted <- arrange(t.test_p.value_df[t.test_filtered,], p.value) > # t.test_p.value_df.sorted > > t.test_p.value_df.sorted_2 <- arrange(t.test_p.value_df[t.test_filtered,], desc(p.value)) > t.test_p.value_df.sorted_2 x_var_name p.value 1 concavity_se 8.260176e-10 2 compactness_se 9.975995e-13 3 fractal_dimension_worst 2.316432e-15 4 symmetry_mean 5.733384e-16 5 smoothness_mean 1.051850e-18 6 concave.points_se 3.072309e-24 7 texture_mean 4.058636e-25 8 symmetry_worst 2.951121e-25 9 smoothness_worst 6.575144e-26 10 perimeter_se 1.651905e-47 11 area_worst 2.828848e-97 12 concave.points_mean 7.101150e-116 > x_names_sorted <- t.test_p.value_df.sorted_2$x_var_name > x_names_sorted [1] "concavity_se" "compactness_se" "fractal_dimension_worst" [4] "symmetry_mean" "smoothness_mean" "concave.points_se" [7] "texture_mean" "symmetry_worst" "smoothness_worst" [10] "perimeter_se" "area_worst" "concave.points_mean" > > X_5 <- X_4[x_names_sorted] # rearrange column order for plotting below > head(X_5,2) concavity_se compactness_se fractal_dimension_worst symmetry_mean smoothness_mean 1 0.7233897 1.3157039 1.9353117 2.215565542 1.5670875 2 -0.4403926 -0.6923171 0.2809428 0.001391139 -0.8262354 concave.points_se texture_mean symmetry_worst smoothness_worst perimeter_se area_worst 1 0.6602390 -2.0715123 2.7482041 1.3065367 2.8305403 1.999478 2 0.2599334 -0.3533215 -0.2436753 -0.3752817 0.2630955 1.888827 concave.points_mean 1 2.5302489 2 0.5476623 > > > #----- > # combine Y and X > wdbc_2 <- data.frame(Y, X_5) > str(wdbc_2) 'data.frame': 569 obs. of 13 variables: $ Y : num 1 1 1 1 1 1 1 1 1 1 ... $ concavity_se : num 0.723 -0.44 0.213 0.819 0.828 ... $ compactness_se : num 1.3157 -0.6923 0.8143 2.7419 -0.0485 ... $ fractal_dimension_worst: num 1.935 0.281 0.201 4.931 -0.397 ... $ symmetry_mean : num 2.21557 0.00139 0.93886 2.86486 -0.00955 ... $ smoothness_mean : num 1.567 -0.826 0.941 3.281 0.28 ... $ concave.points_se : num 0.66 0.26 1.42 1.11 1.14 ... $ texture_mean : num -2.072 -0.353 0.456 0.254 -1.151 ... $ symmetry_worst : num 2.748 -0.244 1.151 6.041 -0.868 ... $ smoothness_worst : num 1.307 -0.375 0.527 3.391 0.22 ... $ perimeter_se : num 2.831 0.263 0.85 0.286 1.272 ... $ area_worst : num 2 1.89 1.46 -0.55 1.22 ... $ concave.points_mean : num 2.53 0.548 2.035 1.45 1.427 ...
|
그 다음으로 reshape2 패키지의 melt() 함수를 사용해서 데이터를 세로로 길게 재구조화한 다음에, ggplot2패키지의 ggplot() + geom_boxplot() 함수를 사용하여 박스 그림을 그렸습니다.
> #----- > # Box plot of X per Y(M, B) > install.packages("reshape2") > library(reshape2) > wdbc_2_melt <- melt(wdbc_2, id.var = "Y") > > install.packages("ggplot2") > library(ggplot2) > ggplot(data = wdbc_2_melt[wdbc_2_melt$value < 3,], aes(x=variable, y=value)) + + geom_boxplot(aes(fill=as.factor(Y))) + + theme_bw() + # white background + coord_flip() # flip the x & y-axis
|
이 박스그림은 위의 t-test 결과 p-value 가 작았던 설명변수 순서대로 위에서 부터 아래로 그려진 것인데요, 역시나 p-value가 작을 수록 박스그림에서 보면 진단결과 Malignant(악성)인 그룹과 Benign(양성) 간의 차이가 크게 나고 있음을 눈으로 재확인할 수 있습니다.
(2-2) 산점도 그림 (Scatter Plot)
다음으로 p-value가 가장 작게 나왔던 상위 변수들 중에서 일부인 'concave.points_mean', 'area_worst', 'texture_mean'를 조합해서 사용해서 예시로 산점도를 그려보았습니다. 이때 진단결과(악성: 'M', 1, vs. 양성: 'B', 0) 별로 색깔을 다르게 해서 산점도를 그렸습니다.
아래 예시의 2개 산점도를 봐서는 로지스틱 회귀모형으로 분류모델을 적합해도 잘 될 것으로 예상이 되네요.
> # scatter plot of x=concave.points_mean, y=area_worst > ggplot(data=wdbc_2, aes(x=concave.points_mean, y=area_worst, colour=as.factor(Y), alpha=0.5)) + + geom_point(shape=19, size=3) + + ggtitle("Scatter Plot of concave.points_mean & area_worst by Y") > > ggplot(data=wdbc_2, aes(x=area_worst, y=texture_mean, colour=as.factor(Y), alpha=0.5)) + + geom_point(shape=19, size=3) + + ggtitle("Scatter Plot of area_worst & texture_mean by Y") |
이상으로 세번째 포스팅인 't-test를 활용한 1차 변수 선별 및 목표변수와 설명변수간 관계 (탐색적) 분석'을 마치겠습니다.
다음번 포스팅은 마지막인 '로지스틱 회귀모형 적합 및 모델 평가, 해석'에 대해서 다루겠습니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾸욱 눌러주세요. ^^