59doit

[ R ] R과 python을 활용한 데이터 분석 시각화 #2 (1) 본문

portfolio

[ R ] R과 python을 활용한 데이터 분석 시각화 #2 (1)

yul_S2 2022. 12. 29. 13:56
반응형

 [ 분류분석 / 시각화 ]

wdbc_data.csv
0.12MB

 

 

 

위스콘신 유방암 데이터셋을 대상으로 분류기법 2개를 적용하여 기법별 결과를 비교하고 시각화하시오. (R과 python 버전으로 모두 실행)

* 종속변수는diagnosis: Benign(양성), Malignancy(악성)

 

 

  • 해당 데이터는 유방암으로 의심되는 종양의 모양에 따라 양성과 악성을 구분하는 데이터
  • 종속변수 diagnosis 에 해당되는 값을 범주형 변수로 바꿔주기 위해서 B(Benign) 양성을 0 으로, M(Malignancy) 음성을 1 로 변경
  • 분석하기에 앞서 먼저 데이터를 R 과 python 에서 발생 난수의 순서까지 동일하지 않기 때문에 동일하게 가질 수 있도록 패키지 SyncRNG 를 사용하여 동일한 난수를 통해 분류
  • R 에서는 데이터프레임이 1 부터 시작하기 때문에 python 에서 0 행과 R 에서 1 행이 같게 되므로 같은 인덱스 번호를 가진다면 -1 을 해주어 train 과 test 에 같은 데이터를 담았다.

 

 

< R >

#1 필요한 패키지 로딩

library(car)
library(lmtest)
library(ROCR)
library(SyncRNG)
library(rpart.plot)

 

 

#2 데이터 불러오기

wdbc <- read.csv("C:/wdbc_data.csv")
  • wdbc : 위스콘신 유방암 데이터 프레임

 

 

#3 diagnosis 변수를 1, 0 으로 변경  및 필요없는 변수 제거

wdbc$diagnosis_sub <-ifelse(wdbc$diagnosis == 'M', 1, 0)
wdbc <- subset(wdbc, select = -c(diagnosis, id))

str(wdbc)
  • diagnosis_sub : diagnosis 에 담긴 변수들이 char 형이므로 factor 형으로 변환하여 샘플링
  • 종속변수 diagnosis 에 해당되는 값을 범주형 변수로 바꿔주기 위해서 B(Benign) 양성을 0 으로, M(Malignancy) 음성을 1 로 변경

 

 

 

#4 학습 & 테스트 데이터 생성

#4-1)

v <- 1:nrow(wdbc)
s <- SyncRNG(seed=42)
#s$shuffle(v)[1:5]       - python 코드에서랑 같은 데이터가 불러와지는지 확인

idx <- s$shuffle(v)[1:round(nrow(wdbc)*0.7)]

#head(idx)         - python 코드에서랑 같은 데이터가 불러와지는지 확인
#length(idx)       - python 코드에서랑 같은 데이터가 불러와지는지 확인
  • 소수점으로 분류되어서 round 함수사용하기
  • idx : 70%

 

#4-2) diagnosis 변수를 1, 0 으로 변경

wdbc$diagnosis_sub <- as.factor(wdbc$diagnosis_sub)
  • diagnosis_sub : 를 factor 형으로 변환

 

#4-3) diagnosis 변수를 1, 0 으로 변경

head(wdbc[-idx[1:length(idx)],])
idx[1:length(idx)]
trData <- wdbc[idx[1:length(idx)],]
teData <- wdbc[-idx[1:length(idx)],]
  • trData : 트레인 데이터
  • teData : 테스트 데이터

 

#### 의사결정 나무 #### 

#1 필요한 패키지 로딩

library(rpart)
library(caret) 

 

 

#2 rpart 활용한 분류분석 데이터 생성

data_lm <- rpart(diagnosis_sub~., data = trData)
  • data_lm : rpart 분류분석 데이터

 

 

#3 예측 tabl생성

rpart_lm <-predict(data_lm, newdata = teData, type = 'class')
table(teData$diagnosis_sub, rpart_lm)

 

 

 

.#4 정확도

teData$diagnosis_sub <- as.factor(teData$diagnosis_sub)
confusionMatrix(rpart_lm, teData$diagnosis_sub)

# Accuracy : 0.9181      

 

 

.

.#5 시각화

rpart.plot(data_lm)

.

 

#### SVM #### 

#1 필요한 패키지 로딩

library(e1071)
library(caret)
library(dplyr)

 

#2 linear 커널 사용 튜닝

result1 <- tune.svm(diagnosis_sub~., data=trData, 
                    gamma=2^(-5:0), cost = 2^(0:4), 
                    kernel="linear")

 

#3 튜닝된 파라미터 확인

result1$best.parameters 

 

 

#4 SVM 실행

normal_svm1 <- svm(diagnosis_sub~., data=trData, 
                   gamma=0.0625, cost=1, 
                   kernel = "linear")

 

 

#5 결과 확인

summary(normal_svm1)
# Call:
#   svm(formula = diagnosis_sub ~ ., data = trData, gamma = 0.0625, 
#       cost = 1, kernel = "linear")


# Parameters:
#   SVM-Type:  C-classification 
# SVM-Kernel:  linear 
# cost:  1 

# Number of Support Vectors:  32

# ( 16 16 )


# Number of Classes:  2 

# Levels: 
#   0 1

 

 

#6 sv index 확인

normal_svm1$index

 

 

#7 SVM으로 예측

normal_svm1_predict <- predict(normal_svm1, teData) 

 

 

#8 테이블 확인

table(teData$diagnosis_sub, normal_svm1_predict)
   normal_svm1_predict
        0  1
  0  97  2
  1   3 69

 

 

#9 정확도

confusionMatrix(normal_svm1_predict, teData$diagnosis_sub)

 

 

 

#10 시각화

wdbc %>% 
  ggplot(aes(x=radius_mean ,y=texture_mean,colour=diagnosis_sub)) + 
  geom_point() +
  theme_minimal(base_family="NanumGothic")

 

 

 

 

 

 

< Python >

데이터의 비어있는 값과 중복값이 있는지, diagnosis 에 담긴 benign 과 malignancy 의 빈도수가 얼마인지 확인

 

#1 필요한 모듈 임포트

import sklearn.datasets as d
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import cross_val_score
from SyncRNG import SyncRNG
from sklearn.tree import DecisionTreeClassifier     # 분류모델 구축-결정트리
from sklearn.tree import DecisionTreeRegressor,plot_tree
from sklearn.tree import export_graphviz

 

 

#2 데이터 로드

wdbccancer = pd.read_csv("wdbc_data.csv")
wdbccancer
            id diagnosis  ...  symmetry_worst  dimension_worst
0     87139402         B  ...          0.2827          0.06771
1      8910251         B  ...          0.2940          0.07587
2       905520         B  ...          0.2998          0.07881
3       868871         B  ...          0.2102          0.06784
4      9012568         B  ...          0.2487          0.06766
..         ...       ...  ...             ...              ...
564  911320502         B  ...          0.2235          0.06925
565     898677         B  ...          0.2434          0.08488
566     873885         M  ...          0.3175          0.09772
567     911201         B  ...          0.2606          0.07810
568    9012795         M  ...          0.2730          0.08666
[569 rows x 32 columns]

 

#3 만들어진 wdbccancer의 결측값 확인

wdbccancer.isnull().sum()

 

 

#4 문자형태인 타기 값을 숫자 형태로 변환

wdbccancer['diagnosis'].unique()
# array(['B', 'M'], dtype=object)


def func1(row):
        if 'M' in row :
                return  1
        else :
                return 0
  • M = 1 (악성종양,암), B = 0 으로 변환

 

 

#5 변환된 결과를 데이터프레임에 새로운 컬럼을 만들기

wdbccancer['diagnosis'] = wdbccancer['diagnosis'].apply(func1)
wdbccancer.head()
  • 'diagnosis' 이라는 새로운 컬럼

 

 

 

#6 필요없는 컬럼 삭제

wdbc = wdbccancer.drop(columns=['id'])
wdbc.head()

 

 

 

#7 데이터 셋  7:3 으로 분할

v=list(range(1,len(wdbccancer)+1))
s=SyncRNG(seed=42)
# s.shuffle(v)[:5]

ord=s.shuffle(v)
idx=ord[:round(len(wdbccancer)*0.7)]
# idx[:5]

 

 

 

#8 인덱스 수정-R이랑 같은 데이터 가져오기

for i in range(0,len(idx)):
    idx[i]=idx[i]-1
  • R에서는 데이터프레임이 1부터 시작하기 때문에 python에서 0행과 R에서 1행이 같은 원리로 같은 인덱스 번호를 가진다면 -1을 해주어 같은 데이터를 가지고 오게 한다.

 

 

#9 학습데이터, 테스트데이터 생성

train=wdbc.loc[idx]                # 70%
train=train.sort_index(ascending=True)
test=wdbc.drop(idx)              # 30%

train_x=train.drop(['diagnosis'],axis=1)
train_y=train['diagnosis']

test_x=test.drop(['diagnosis'],axis=1)
test_y=test['diagnosis']

 

 

 

#### 의사결정 나무 #### 

#1 모델 생성

reg = DecisionTreeRegressor(max_depth=2).fit(train_x,train_y)
  • reg : 
  •  

 

#2 예측

pred=reg.predict(test_x)
p1=pred.round()
p2=np.array(test_y)

 

 

 

#3 정확도

import sklearn.metrics as metrics
metrics.accuracy_score(p2,p1)
# 0.9181286549707602

 

 

 

#4 변수중요도

for i,col in enumerate(train_x.columns):
    print(f'{col} 중요도 : {reg.feature_importances_[i]}')

 

 

#5 시각화

fig = plt.Figure(facecolor="white")
plot_tree(reg,feature_names=train_x.columns,filled=True)

 

 

 

 

#### SVM ####

 

#1 필요한 모듈 임포트

from sklearn.svm import LinearSVC
from sklearn.svm import SVC
import sklearn.svm as svm
import sklearn.metrics as mt
from sklearn.model_selection import cross_val_score, cross_validate

 

 

#2 데이터 로드

wdbccancer_svm = pd.read_csv("wdbc_data.csv")
wdbccancer_svm

 

 

#3 결측값 확인

wdbccancer_svm.isnull().sum()

 

# 아이디는 유방암을 예측하는데 전혀 도움이 되지 않기 때문에 무시
# diagnosis M = 1 (악성종양,암), B = 0

 

 

#4 문자형태인 타기 값을 숫자 형태로 변환

wdbccancer_svm['diagnosis'].unique()
# array(['B', 'M'], dtype=object)


def func1(row):
        if 'M' in row :
                return  1
        else :
                return 0

 

 

#5 변환된 결과를 데이터프레임에 '진단' 이라는 새로운 컬럼을 만들어 넣어준다

wdbccancer_svm['진단'] = wdbccancer_svm['diagnosis'].apply(func1)
wdbccancer_svm.head()

 

#6 필요없는 컬럼 삭제

wdbc = wdbccancer_svm.drop(columns=['id','diagnosis'])
wdbc.head()

 

 

#7 분류보델 구축 - 결정트리 & 훈련 검증용 데이터 분리 임포트

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

 

#8 데이터 셋 7:3으로 분할

X = wdbc.drop(['진단'], axis = 1)    # 목표변수
y = wdbc['진단']                              # 설정변수

X_train,X_test,y_train,y_test = train_test_split (X,y, test_size = 0.3 , random_state = 1004)
  •  test_size: 테스트 셋 구성의 비율

 

#9 kernel = linear 로 선형분리

svm_model = svm.SVC(kernel='linear', random_state=100)

 

#9-1) 교차검증

scores = cross_val_score(svm_model,X,y,cv=5)
scores

pd.DataFrame(cross_validate(svm_model,X,y,cv=5))
print("교차검증 평균: ", scores.mean())
  • 교차검증 평균 : 0.9508461419034312

 

#10 kernel = 'rbf'로 비선형분리 진행

svm_model2 = svm.SVC(kernel='rbf')

 

#10-2) 교차검증

scores2 = cross_val_score(svm_model2, X, y, cv=5)
scores2

pd.DataFrame(cross_validate(svm_model2, X, y, cv=5))
print('교차검증 평균: ', scores2.mean())
  • 교차검증 평균:  0.9156652693681104

 

 

선형 분리에서 높은 평균 SCORE , 선형분리가 적합한 케이스

 

#11 시각화

import matplotlib.pyplot as plt
plt.figure(figsize=(7,7))
X1=np.array(X)
y1=np.array(y)
plt.scatter(X1[:,0],X1[:,1],c = y1)
plt.xlabel("radius_mean")
plt.ylabel("texture_mean")
plt.show()

 

 

 

 

반응형
Comments