일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 공부
- NIA
- nvidia
- MAE
- 데이터불균형
- 2D CNN
- 회귀분석
- 정보화진흥원
- CNN
- 데이터
- R
- 엣지컴퓨팅
- 빅데이터
- 회귀
- 1D CNN
- 알고리즘
- Jetson
- Data Imbalance
- GE B650
- 데이터분석
- 생체신호
- 머신러닝
- Undersampling
- 딥러닝
- VitalDB
- VitalRecorder
- 나이브베이즈
- 의료데이터
- edge computing
- 경진대회
- Today
- Total
Doyun-lab
[Project] 마취 중 저혈압 환자 예측 본문
Subject : Prediction of Patients with Low Blood Pressure during Anesthesia
Language : R
Data : ‘수술 중 마취한 환자의 혈압과 정보’ 데이터
Model : Random Forest, SVM, Boosting
1. Data parsing & preprocessing
# total 이라는 리스트에 모든 엑셀 파일을 불러와 저장
setwd("C:\\r_temp\\homework")
total <- lapply(Sys.glob("homework*.csv"), read.csv, stringsAsFactors = F)
# total 리스트 요소들을 하나씩 뽑아 전처리 하는 과정
for(i in 1:length(total)){
total[[i]]$date1 <- strptime(total[[i]]$date1, "%Y-%m-%d %H:%M") # date를 POSIxt 형으로 변환
# 집도의, 마취의, 신체적상태만 따로 추출하여 새로운 변수에 저장
x <- subset(total[[i]], total[[i]]$item == "집도과1")
y <- subset(total[[i]], total[[i]]$item == "마취의1")
z <-subset(total[[i]], total[[i]]$item == "신체적상태")
# 마취시작전 시간대 데이터만 추출하고 중복된 값 제거
total[[i]] <- subset(total[[i]], total[[i]]$date1 <= total[[i]]$date1[14])
total[[i]] <- total[[i]][-which(duplicated(total[[i]]$item)),]
# 마취시작전 시간대 데이터에 집도의, 마취의, 신체적 상태 행으로 붙이기
total[[i]] <- rbind(total[[i]], x, y, z)
# class가 열 2개로 이루어져 있는 데이터 1개 열 제거
total[[i]]$class.1 <- NULL
# 필요없는 열 빼고 다시 저장
total[[i]] <- total[[i]][, -c(1,7,8,9,10,11)]
# value1 값이 공백인 것 빼고 불러오기
total[[i]] <- total[[i]][!(total[[i]]$value1 == ""), ]
# 마취일반정보와 V/S 정보만 빼기
total[[i]] <- subset(total[[i]], total[[i]]$group == "V/S" | total[[i]]$group == "마취일반정보")
}
- 파일을 불러와 리스트에 저장 후, 전처리 진행
- (1) date1 변수를 POSIxt형으로 변환해 줍니다.
- (2) 집도과1, 마취의1, 신체적상태는 subset 하여 변수에 따로 저장해줍니다.
- (3) 마취시작 전 시간대 데이터만 추출한 후, 중복된 행을 제거합니다.
- (4) [단계 (3)] 데이터에 [단계 (2)]에서 추출한 변수들을 rbind 하여 행을 추가해줍니다.
- (5) class가 열이 2개로 이루어져 있는 열을 하나로 만들어 줍니다.
- (6) 분석에 필요하지 않은 열을 빼줍니다.
- (7) value1 변수에 공백으로 이루어져 있는 것을 제외하고 다시 저장해줍니다.
- (8) 마취일반정보와 V/S 정보만 빼서 저장을 마칩니다.
# 행과 열을 바꿔주는 작업
for(i in 1:length(total)){
# class 값을 따로 저장
class1 <- total[[i]]$class[1]
# item과 value1 값만 빼기
total[[i]] <- total[[i]][,c(3, 4)]
# 행과 열 바꿔주기
total[[i]] <- t(total[[i]])
# 데이터프레임으로 형 변환
total[[i]] <- as.data.frame(total[[i]])
# item 행을 열의 이름으로 바꿔주기
colnames(total[[i]]) <- unlist(total[[i]][row.names(total[[i]]) == "item",])
# item 값들 옆에 class 행 붙여주기
total[[i]] <- cbind(total[[i]], class1)
}
- Before Modeling, 행과 열 바꾸기
- (1) 행과 열을 바꾸기 전에 class 값을 따로 저장해줍니다.
- (2) item, value1 값만 빼서 저장해줍니다.
- (3) 행과 열을 바꿔줍니다. [ t() 함수 사용 ]
- (4) [단계 (3)]을 거친 데이터를 데이터프레임 형으로 변환해줍니다.
- (5) item 행을 [단계 (4)]의 데이터프레임 열 이름으로 바꿔줍니다.
- (6) 모든 과정을 마친 후, class 값을 새로운 열으로 붙여줍니다.
# 312명의 사람 데이터 합쳐주기
library(dplyr)
result <- total[[6]]
for(i in 1:length(total)) {
result <- bind_rows(result, total[[i]][2,])
}
# 필요없는 행과 중복된 행 제거
result <- result[-1,]
result <- unique(result)
# NA 값이 너무 많은 열 13 부터 열 22까지 지우기
result <- result[,-c(13:22)]
# 열 1 ~ 8 가 모두 NA 인 행 지우기
result <- result[(rowSums(is.na(result)) < 8),]
# 신체적 상태 숫자로 표현 ( 1 ~ 3)
result$신체적상태 <- substr(result$신체적상태, 1, 1)
# 형 변환
result[,1:8] <- as.numeric(unlist(result[,1:8]))
result$집도과1 <- as.factor(result$집도과1)
result$마취의1 <- as.factor(result$마취의1)
result$신체적상태 <- as.factor(result$신체적상태)
result$class1 <- as.factor(result$class1)
- 리스트 요소를 모두 합쳐 데이터 프레임 생성 (bind_rows 함수 이용)
- 만들어진 데이터 프레임을 다시 한 번 전처리
- (1) 필요없는 행과 중복되는 행을 제거해줍니다.
- (2) NA 값이 너무 많이 존재하는 열13 ~ 열22까지 지워줍니다
- (3) [단계 (2)]를 끝낸 데이터에서 NA 값이 8개 이상 존재하는 행을 지워줍니다.
- (4) “신체적상태”를 1 ~ 3으로 표현해줍니다
- (5) 모든 열들을 모델링하기 위해 형을 변환해줍니다.
2. Modeling
# train / test set 나누기
set.seed(123)
index <- sample.int(nrow(result), nrow(result)*0.7)
re_train <- result[index,]
re_test <- result[-index,]
# NA 처리안한 rpart 모델
library(rpart)
fit <- rpart(formula = class1 ~., data = re_train)
pred <- predict(fit, re_test, type = "class")
tb <- table(re_test$class1, pred)
sum(diag(tb))/sum(tb) # 정확도 = 58.6%
- NA 값을 처리하지 않은 rpart 모델의 정확도는 58.6%
# library
library(DMwR)
library(caret)
library(randomForest)
library(e1071)
library(C50)
library(adabag)
library(class)
# knn Imputation 으로 NA 값 대체 해보기
# 1 ~ 100 => 최적의 k = 50
set.seed(123)
a <- knnImputation(result, 50)
names(a) <- c("nbps", "nbpd", "nbpm", "hr", "spo2", "bis", "tofratio", "tofcount", "집도과", "마취의", "신체적상태", "class")
- k-nn imputation을 이용해 NA 값 처리
- (1) k-nn Imputation을 실시한 후, 열의 이름을 재지정해줍니다.
*k Nearest Neighbor Imputation = knn을 사용해 찾은 k개 주변 이웃의 값을 주변 이웃까지의 거리를 고려해 가중 평균한 값으로 대체하는 것.
- MODEL = 사용한 변수
-“NBP-S, NBP-D, NBP-M, HR, SPO2, BIS, TOF ratio, TOF count, 집도과, 마취의, 신체적상태”
- Random Forest
# 랜덤 포레스트 모델
a.fit <- randomForest(class ~ ., data = a_train,
mtry = floor(sqrt(11)), ntree = 500, importance = T)
a.pred <- predict(a.fit, a_test)
tb.a <- table(a.pred, a_test$class)
sum(diag(tb.a))/sum(tb.a) # 정확도 = 73.9%
- (1) 랜덤포레스트 모형 — mtry(분류 문제이기 때문에 sqrt(변수의 개수) 실시)는 각각의 tree마다 몇 개의 feature를 사용할 것인지 정하는 것이며, ntree는 tree의 총 개수를 의미합니다.
- (2) 정확도는 73.9% 정도로 나오는 것을 볼 수 있습니다.
- SVM
# SVM 모델
b.fit <- svm(class ~ ., data = a_train)
b.pred <- predict(b.fit, a_test)
tb.b <- table(b.pred, a_test$class)
sum(diag(tb.b))/sum(tb.b) # 정확도 = 66.3%
- 정확도는 66.3% 정도로 나오는 것을 볼 수 있습니다.
- Boosting
# 부스팅
# trials => 50, 100 결과 비슷함
c_bst <- C5.0(class ~ ., data = a_train, trials = 100)
c_c50 <- C5.0(class ~ ., data = a_train)
summary(c_c50) # Errors = 17.3% / 정확도 = 82.6%
set.seed(300)
m_ada <- boosting(class ~ ., data = a_train)
p_ada <- predict(m_ada, a)
p_ada$confusion
sum(diag(p_ada$confusion))/sum(p_ada$confusion) # 89.2%
- (1) 과적합 문제로 채택하지 않았습니다.
- 최종 Model로 Random Forest 채택
'Project > On campus' 카테고리의 다른 글
[Project] FIFA19 등록 선수 가치 예측 (0) | 2021.06.23 |
---|---|
[Project] 고혈압 & 당뇨 분류 모델 개발 (0) | 2021.06.23 |
[Project] 전력 수요 예측 (0) | 2021.06.23 |
[Project] 한국 부동산 가격 예측 (0) | 2021.06.23 |