brunch

You can make anything
by writing

C.S.Lewis

by 첨물 May 19. 2021

빅분기 실기 연습(8)

R프로그램_파생변수/지터함수

지난번에 했던 iris 데이터의 군집화, Kmeans를 이용한 분류가 영 찝찝하다. Setosa는 100% 제대로 분류가 되었는데, versicolor는 2/50개, virginica는 14/50개가 오분류되었다.


> table(iris$Species,kc$cluster)

            

              1  2  3

  setosa     50  0  0

  versicolor  0 48  2

  virginica   0 14 36


어떻게 하면 좀 분류가 잘 되도록 만들 수 있을까?

Kmeans의 변숫값이 꽃잎의 길이, 너비, 꽃받임의 길이, 너비로만 되어 있었는데 좀 더 변수를 만들어서 넣으면 오분류를 줄일 수 있지 않을까? 이때 나온 개념이 파생변수이다.


이때 유용한 패키지가 dplyr이다. 여기엔 유용한 함수 5개가 있다.


IRIS의 4개의 변수 조합을 만들어서 열추가 해보려고 한다. 이때 필요한 함수는 mutate()


일단 IRIS 데이터를 한 화면에 정리를 해 보고 생각해보자. 매번 head() 함수를 썼는데, 이번엔 tbl_df()라는 함수를 써서 정리했다.


iris_df<-tbl_df(iris) #자료를 한 화면에 정리

iris_df

> iris_df

# A tibble: 150 x 5

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species

          <dbl>       <dbl>        <dbl>       <dbl> <fct>  

 1          5.1         3.5          1.4         0.2 setosa

 2          4.9         3            1.4         0.2 setosa

 3          4.7         3.2          1.3         0.2 setosa

 4          4.6         3.1          1.5         0.2 setosa

 5          5           3.6          1.4         0.2 setosa

 6          5.4         3.9          1.7         0.4 setosa

 7          4.6         3.4          1.4         0.3 setosa

 8          5           3.4          1.5         0.2 setosa

 9          4.4         2.9          1.4         0.2 setosa

10          4.9         3.1          1.5         0.1 setosa


# ... with 140 more rows


다음엔 mutate() 함수를 써서 꽃받임의 길이/너비 비율과 꽃잎의 길이/너비 비율을 가지고 새로운 변수를 만들어 넣어보자. 그러면 새로운 열인 Sepal.Ratio와 Petal.Ratio가 생겼음을 알 수 있다.


aa<-mutate(iris_df, Sepal.Ratio=Sepal.Length/Sepal.Width,Petal.Ratio=Petal.Length/Petal.Width)

colnames(aa)

> colnames(aa)


[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"      "Sepal.Ratio"  "Petal.Ratio"


다음엔 이걸로 Kmeans 분류를 해보자. 오히려 악영향을 주었다. setosa도 분류를 완전히 못하고, 나머지 두종도 한종으로만 분류함.


aa$Species = NULL

kc1<-kmeans(aa,3) #종류가 3개인 군집분석 (비지도 학습)

table(iris$Species,kc1$cluster)

> table(iris$Species,kc1$cluster)

            

              1  2  3

  setosa     31 19  0

  versicolor  0  0 50

  virginica   0  0 50


그러면 꽃잎은 길이*너비로 새로운 변수를 넣어보자.


aa<-mutate(iris_df, Petal.multiply=Petal.Width*Petal.Length)

> table(iris$Species,kc1$cluster)

            

              1  2  3

  setosa      0 50  0

  versicolor  0  0 50

  virginica  42  0  8


versicolor는 100% 제대로 분류를 했고, virginica는 8/42 개 오분류가 되었다.

이 정도면 꽤 잘 분류를 한 게 아닐까, 파생변수 하나를 넣어서 확실히 좋은 결과물을 낼 정도면...

다른 조합도 해 보았지만 이 정도로 좋아지지 않았다.


그러면 이전 변수 4개만 한 것과 비교해서 새로운 파생변수로 분류한 것을 산점도로 나타내 보자. 오른쪽 위 두 그룹 경계면이 파생변수 넣었을 때가 좀 더 잘 분류됨을 알 수 있다.


plot(aa[c("Petal.Length", "Petal.Width")], col=kc1$cluster)

파생변수 넣어서 분류(좌), 기존 변수로 분류(우)




뭔가 제대로 분류되었다는 걸 다른 방식으로 보여줄 수는 없을까?

R의 강점을 살려서 한 걸음 더 나아가보자.


t<-as.factor(kc1$cluster)

tt<-iris$Species

plot(tt,t)

음. setosa와 versicolor는 잘 분류가 되었는데, vierginica가 일부 오분류가 된 듯한 느낌이 든다. x, y 모두factor로 되어 있을 때 plot으로 그리면 이렇게 나온다.


그럼 다른 방식으로 약간 변형해 보자. 3종의 꽃을 1~3으로 분류한 것을 나타낸다.


y<-as.integer(t)

x<-as.integer(tt)

plot(tt,y)


그런데 뭔가 아쉽다. virginica의 동떨어진 한점이 몇개의 데이터인지 알고 싶다 이때 필요한 것이 jitter()함수, 약간의 noise를 주는 것이다.


y1<-jitter(as.integer(t))

plot(tt,y1)

y값에 약간의 노이즈를 주니, 뜬금없이 boxplot이 그려진다. 그래서 viginica 윗쪽에 찍힌 점의 숫자가 대략 8개가 됨을 알 수 있다. 위 파생변수를 넣어서 분류한 결과이다.


x 값에도 jittter를 넣어서 마지막으로 그려보자.


x1<-jitter(as.integer(tt))

plot(x1,y1,xlab="iris$Species", ylab="kmeans$Classification")



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari