본문 바로가기
## 오래된 게시글 (미관리) ##/R

18. 다차원척도법 (Multidimensional Scaling, MDS)

by #Glacier 2018. 11. 21.
반응형

안녕하세요~ 오늘은 다차원척도법을 알아 보겠습니다.

다차원척도법은 여러 대상 간의 관계에 관한 수치적 자료를 이용해 유사성에 대한 측정치를 상대적 거리로 구조화하는 방법입니다.

따라서 다차원척도법은 2차원 혹은 3차원에서의 특정 위치에 관측치를 배치게 눈에 보기 쉽게 척도화 하는 거죠~

한번 알아볼까요???


1. 전통적 다차원척도법(Classical MDS)은 Numeric data로만 이루어진다.

  cmdscale 함수를 사용한다 (stats 패키지)


2. 비계량적 다차원척도법(nonmetric MDS)은 투입변수로 numeric이 아닌 data를 포함한다.

  isoMDS함수를 사용한다 (MASS 패키지)


##----R분석 사례----##


(1) 전통적 다차원 척도법 (Classical MDS)

#전통적 다차원 척도법을 실습하기 위해서 watervoles(영국 14개 지역의 물쥐의 13개 특성 발현 비율 data)를 사용하겠습니다.


install.packages("HSAUR")
data(watervoles, package="HSAUR")


#데이터를 한번 확인해보죠.
head(watervoles,5)


           Surrey Shropshire Yorkshire Perthshire Aberdeen Elean Gamhna  Alps
Surrey      0.000      0.099     0.033      0.183    0.148        0.198 0.462
Shropshire  0.099      0.000     0.022      0.114    0.224        0.039 0.266
Yorkshire   0.033      0.022     0.000      0.042    0.059        0.053 0.322
Perthshire  0.183      0.114     0.042      0.000    0.068        0.085 0.435
Aberdeen    0.148      0.224     0.059      0.068    0.000        0.051 0.268
           Yugoslavia Germany Norway Pyrenees I Pyrenees II North Spain
Surrey          0.628   0.113  0.173      0.434       0.762       0.530
Shropshire      0.442   0.070  0.119      0.419       0.633       0.389
Yorkshire       0.444   0.046  0.162      0.339       0.781       0.482
Perthshire      0.406   0.047  0.331      0.505       0.700       0.579
Aberdeen        0.240   0.034  0.177      0.469       0.758       0.597
           South Spain
Surrey           0.586
Shropshire       0.435
Yorkshire        0.550
Perthshire       0.530
Aberdeen         0.552


# cmdscale 함수 적용. cmdscale 함수는 Matrix데이터 상의 데이터들의 값을 거리로 생각하고, 2차원상으로 나타내주는 역할을 합니다.


voles_mds<-cmdscale(watervoles)

voles_mds


                          [,1]             [,2]
Surrey        -0.240788133  0.233677162
Shropshire   -0.113656033  0.116786026
Yorkshire    -0.239359809  0.076003132
Perthshire   -0.212934123  0.060479017
Aberdeen     -0.249489548 -0.069331766
Elean Gamhna -0.148728549 -0.077835691
Alps             0.051393974 -0.162305986
Yugoslavia   -0.011536211 -0.344631490
Germany       0.003932616  0.005908733
Norway       -0.038569294 -0.008874157
Pyrenees I    0.042115821 -0.056555465
Pyrenees II   0.515830349  0.029097752
North Spain   0.318027269  0.150096450
South Spain   0.323761671  0.047486283


#이제 cmdscale 함수의 eigenvalue를 생성해주는 옵션을 적용합니다. 따라서.. eigenvalue가 참 뭐랄까.. 

 저한테는 이해하기 어려운 의미랄까?.

#그런 건데요~ 일종의 고유값을 생성해주는 겁니다. 얼만큼 거리를 이동할지 이런 것들이겠죠.



vole_mds<-cmdscale(watervoles, eig=TRUE)
> vole_mds
$points
                     [,1]         [,2]
Surrey       -0.240788133  0.233677162
Shropshire   -0.113656033  0.116786026
Yorkshire    -0.239359809  0.076003132
Perthshire   -0.212934123  0.060479017
Aberdeen     -0.249489548 -0.069331766
Elean Gamhna -0.148728549 -0.077835691
Alps          0.051393974 -0.162305986
Yugoslavia   -0.011536211 -0.344631490
Germany       0.003932616  0.005908733
Norway       -0.038569294 -0.008874157
Pyrenees I    0.042115821 -0.056555465
Pyrenees II   0.515830349  0.029097752
North Spain   0.318027269  0.150096450
South Spain   0.323761671  0.047486283

$eig
 [1]  7.359910e-01  2.626003e-01  1.492622e-01  6.990457e-02  2.956972e-02
 [6]  1.931184e-02  1.249001e-16 -1.139451e-02 -1.279569e-02 -2.849924e-02
[11] -4.251502e-02 -5.255450e-02 -7.406143e-02 -1.097833e-01

$x
NULL

$ac
[1] 0

$GOF
[1] 0.6248056 0.7883784



# Eigenvalue가 생성되었죠? 이제 시각화를 해보겠습니다.

# 책에 있는 내용으로치면 오류가 나서, 제가 계속 뒤적이면서 만들어본 결과 성공했습니다.

plot(voles_mds, type="n", xlab="Dim1", ylab="Dim2", main = "cmdscale(watervoles)")
segments(-1, -0, 1, 0, lty="dotted")
segments(0, -1, 0, 1, lty="dotted")
text(voles_mds, rownames(voles_mds), cex=0.8, col="red")


#voles_mds를 플랏을 찍는데 , "n"은 찍지 않는다입니다 아무것도 표시가 남지 않죠. 그리고, x축이름을 Dim1, y축이름을 Dim2라고 짓구요,

#main이름을 cmdscale(watervoles)라고 지은겁니다.

#segments는 나눠주는 역할을 하는데요~ 좌표점선을 이어주고, dotted는 점선으로 표시한다는 의미입니다.

#text는 이제 저렇게 이름을 띄워주는 역할을 하는데요~ voles_mds의 데이터로 행의 이름들을 빨간색으로 나타내준 겁니다!



#자 그럼 이제 두 번째 사례로 넘어가볼까요!?

#친족 : 15가지 친족(colnames)에 대해 6개의 그룹(sourceid)이 각각이 정한 기준에 의해 분류한 결과데이터를 사용할 것입니다.

#책에는 이렇게 써있지만 이해가 안되는군요 그럼 데이터를 직접 살펴보져~ 데이터도 보면 실행이 안되는게 많아서, 또 고쳤네요 ㅠㅠ.;


library(foreign)

kinship.1 <- read.spss("http://www.unt.edu/rss/class/Jon/R_SC/Module9/MDS/kinship_dat.sav", to.data.frame=T)
kinship.1


#데이터를 보니까 aunt.brother.cousin등 15가지의 친족이 variable로 나타나있군요.

#sourceid (source identification?) 이게 6개의 그룹으로 나누어져 있군요.

#그 중에서 저희는 sourceid가 1인 행만 사용하겠습니다.


kinship.2<-kinship.1[1:15, 1:15]

kinship.2


   aunt brother cousin daughter father gdaugh gfather gmother gson mother
1     0       0      0        0      0      0       0       0    0      0
2    83       0      0        0      0      0       0       0    0      0
3    38      77      0        0      0      0       0       0    0      0
4    79      61     83        0      0      0       0       0    0      0
5    79      55     84       43      0      0       0       0    0      0
6    79      82     82       69     83      0       0       0    0      0
7    84      76     84       83     73     48       0       0    0      0
8    78      83     84       74     82     38      11       0    0      0
9    85      73     81       80     74     13      38      48    0      0
10   72      63     84       34     13     84      82      73   83      0
11   49      74     53       81     77     80      78      84   73     83
12   42      83     53       74     85     72      85      79   79     79
13   77      10     78       52     63     73      83      76   82     55
14   85      52     82       14     34     80      74      83   69     43
15   10      77     39       85     72     85      78      84   79     79
   nephew niece sister son uncle
1       0     0      0   0     0
2       0     0      0   0     0
3       0     0      0   0     0
4       0     0      0   0     0
5       0     0      0   0     0
6       0     0      0   0     0
7       0     0      0   0     0
8       0     0      0   0     0
9       0     0      0   0     0
10      0     0      0   0     0
11      0     0      0   0     0
12     12     0      0   0     0
13     81    76      0   0     0
14     74    81     61   0     0
15     42    49     83  79     0


#요렇게 되었죠. 이제 다차원척도화하기위해서 거리형태로 나타내야하기때문에 distance matrix형태로 변환해야합니다.

kin.dist<-dist(kinship.2)

           1         2         3         4         5         6         7
2   83.00000                                                            
3   85.86617  89.18520                                                  
4  129.81140 103.08249  93.94679                                        
5  134.79985 109.29776 105.21407  43.42810                              
6  177.02825 158.47397 141.70392 109.96363  91.09336                    
7  185.49933 165.39347 153.93180 121.54423  98.48350  51.62364          
8  183.83144 166.53828 149.85660 119.37755 100.17485  39.96248  21.63331
9  186.83683 166.39411 156.77691 126.40016 105.50355  65.09224  70.72482
10 208.64324 196.13516 189.02645 165.45996 162.36071 180.38015 162.94784
11 234.38003 231.70887 217.22569 214.98139 203.35437 183.69268 169.09169
12 235.45488 235.27856 216.42089 216.17123 206.33953 183.07376 172.24111
13 242.62316 230.15864 242.58401 222.22286 214.93022 214.41315 202.18309
14 243.18306 227.85302 228.12935 206.40494 207.79557 217.93348 206.44612
15 264.76593 274.46311 254.66841 263.63611 253.69273 239.06903 227.58075
           8         9        10        11        12        13        14
2                                                                       
3                                                                       
4                                                                       
5                                                                       
6                                                                       
7                                                                       
8                                                                       
9   62.57795                                                            
10 161.77763 143.54790                                                  
11 165.78299 147.28883 122.71104                                        
12 166.62833 148.88586 125.03999  24.02082                              
13 201.20139 182.87154 145.56098 141.00355 138.86324                    
14 204.71444 189.14545 138.26786 162.32683 159.92186  91.73876          
15 224.58183 212.81682 189.30663 138.34377 134.98148 166.93412 157.46428


#이렇게 거리형태로 변환되었습니다.

#이제 cmdscale을 적용합니다.

mds2<-cmdscale(kin.dist)

mds2

         [,1]       [,2]
1   -97.80831 -85.075706
2  -101.87481 -66.945503
3   -94.36266 -45.877589
4   -89.20892 -10.308259
5   -81.10522   9.223326
6   -55.28806  72.413885
7   -36.65867  74.393169
8   -34.91551  74.768978
9   -15.32028  63.421025
10   52.05353 -13.482851
11   99.52892  23.504895
12  102.23585  22.731125
13  109.91109 -38.743797
14  100.49770 -56.351359
15  142.31537 -23.671339


#요렇게 디스턴스 매트릭스가 되었죠.

#3차원 결과 도출 option을 적용해봅니다.


mds3<-cmdscale(kin.dist, k=3)

mds3


         [,1]       [,2]        [,3]
1   -97.80831 -85.075706  47.1807477
2  -101.87481 -66.945503   0.4102747
3   -94.36266 -45.877589  38.2830477
4   -89.20892 -10.308259 -31.9847857
5   -81.10522   9.223326 -25.1540513
6   -55.28806  72.413885  -1.5747893
7   -36.65867  74.393169  -7.3687134
8   -34.91551  74.768978  -3.1528163
9   -15.32028  63.421025  -8.0731192
10   52.05353 -13.482851 -29.5897200
11   99.52892  23.504895  42.4181065
12  102.23585  22.731125  43.1990617
13  109.91109 -38.743797 -59.4977184
14  100.49770 -56.351359 -70.5707395
15  142.31537 -23.671339  65.4752149
 

#이렇게 3차원도 되지요.

#이제 2차원 결과를 먼저 시각화해봅니다.

#요번 부분에서 제가 아까 고쳤다는 부분이 이해가 되네요. 생략해버렸군요 책이..ㅠㅠ

Dim1<-mds2[,1]

Dim2<-mds2[,2]

plot(Dim1, Dim2, type="n", xlab="", ylab="", main="cmdscale(kin.dist)")

segments(-1500, -0, 1500, 0, lty="dotted")
segments(0, -1500, 0, 1500, lty="dotted")

text(Dim1, Dim2, colnames(kinship.2), cex=0.8, col="blue")




#요렇게 보니까 2차원상에서 15개의 친족들이 다 거리상으로 표시되었죠.  엄마는 가까운데 아빠는 머네요 생각보다 ㅋㅋ(아빠들 슬픔)

#3차원결과 시각화를 해보겠습니다.

install.packages("scatterplot3d")
library(scatterplot3d)
scatterplot3d(mds3, color="dark blue", pch=1, main="Mulitmensional Scaling 3-D Plot",
 sub="Three Dimensional Solution", grid=TRUE, box=TRUE)




#요렇게 3차원으로 나타낼 수도 있습니다. 이름을 뜨게 하고 싶은데 이 방법은 잘 모르겠네요 Discription을 찾아보았는데도;;ㅠㅠ

#3차원으로 늘여서 이름을 어떻게 지정해줘야할지..ㅠ0ㅠ


##----------##


(2) 비계량적 다차원척도법(nonmetric MDS)

# 이번에는 비계량적 다차원척도법을 해볼건데요~

# swiss ( 1888년 스위스 47개 불어권 도시에서의 demographic 정보. 출산율 저하에 따라 Data를 수집하였다고 합니다.) data를 이용합니다.


library(MASS)

data(swiss)

summary(swiss)


   Fertility      Agriculture     Examination      Education    
 Min.   :35.00   Min.   : 1.20   Min.   : 3.00   Min.   : 1.00  
 1st Qu.:64.70   1st Qu.:35.90   1st Qu.:12.00   1st Qu.: 6.00  
 Median :70.40   Median :54.10   Median :16.00   Median : 8.00  
 Mean   :70.14   Mean   :50.66   Mean   :16.49   Mean   :10.98  
 3rd Qu.:78.45   3rd Qu.:67.65   3rd Qu.:22.00   3rd Qu.:12.00  
 Max.   :92.50   Max.   :89.70   Max.   :37.00   Max.   :53.00  
    Catholic       Infant.Mortality
 Min.   :  2.150   Min.   :10.80   
 1st Qu.:  5.195   1st Qu.:18.15   
 Median : 15.140   Median :20.00   
 Mean   : 41.144   Mean   :19.94   
 3rd Qu.: 93.125   3rd Qu.:21.70   
 Max.   :100.000   Max.   :26.60  


# 생식력, 유아 사망률, 교육수준, 농업, 카톨릭, 조사? 등등이 variable로 나타나있네요.

# 도시별로 조사한 결과인것 같습니다. 음..그럼 examination이 조사한 수? 이런 것을 나타내려나요~

# distance matrix형태로 나타내야겠죠~


swiss.dist<-dist(swiss)

swiss.mds<-isoMDS(swiss.dist)


initial  value 5.463800 
iter   5 value 4.499103
iter   5 value 4.495335
iter   5 value 4.492669
final  value 4.492669 
converged


#그 결과, 시작 값은 5.46부터 시작해서 iteration하여 4.492669로 수렴하였군요

swiss.mds


$points
                   [,1]        [,2]
Courtelary    38.850496 -16.1546743
Delemont     -42.676573 -13.7209890
Franches-Mnt -53.587659 -21.3357627
Moutier        6.735536  -4.6041161
Neuveville    35.622307   4.6339724
Porrentruy   -44.739479 -25.4957015
Broye        -55.301247   2.9985892
Glane        -61.510950  -0.5029742
Gruyere      -56.196434 -11.5873817
Sarine       -47.880261 -18.4937959
Veveyse      -60.573600  -3.3177231
Aigle         28.500730  18.4040743
Aubonne       31.622253  26.0543764
Avenches      31.955939  19.3455733
Cossonay      32.951993  27.2866822
Echallens     11.653211  24.5294932
Grandson      39.623322  -0.1906417
Lausanne      40.455512 -24.2790922
La Vallee     51.099610 -23.2691859
Lavaux        30.753053  29.7236322
Morges        32.051544  18.1638440
Moudon        33.349605  17.2202105
Nyone         26.363999   7.9625625
Orbe          35.822440  15.4595563
Oron          29.301157  31.3756933
Payerne       30.448866  19.5104430
Paysd'enhaut  30.389346  26.4350474
Rolle         29.595391  18.6942289
Vevey         30.316991 -16.0544171
Yverdon       33.168755  11.4999792
Conthey      -67.045836  16.9000059
Entremont    -66.130908  14.2235838
Herens       -67.831773  19.3460319
Martigwy     -63.493801   8.8769860
Monthey      -59.675844  -1.3044352
St Maurice   -63.678801   7.2356724
Sierre       -69.462428  17.6354948
Sion         -57.385309  -4.8572223
Boudry        37.667244   0.0118818
La Chauxdfnd  40.842274 -29.0069374
Le Locle      38.285582 -17.6212453
Neuchatel     35.745340 -30.5746402
Val de Ruz    37.226824   2.1006842
ValdeTravers  41.086622 -15.3626392
V. De Geneve  24.329270 -73.1278621
Rive Droite   -4.756696 -17.5026420
Rive Gauche   -3.887613 -37.2642199

$stress
[1] 4.492669


# 이렇게 변환되었습니다. 참 이걸 거리형태로 만드는 것 자체가. 참 대단하죠? 엄청난 수식이 들어가있을 것만 같은 느낌입니다.

# 이제 시각화해보겠습니다.

# 시각화1

plot(swiss.mds$points, type="n")

text(swiss.mds$points, labels = as.character(1:nrow(swiss)))



#시각화2(segment와 text포함)

plot(swiss.mds$points, type="n")

segments(-75, -0, 55, 0 lty="dotted")

segments(0, -75, 0, 35, lty="dotted")

text(swiss.mds$points, labels = row.names(swiss), col="red")



# 요렇게 전통적 다차원척도법과 비계량적 다차원척도법을 시각화해보는 것까지 한 번 해봤는데요~ 조~금 까다롭죠 ㅠㅠ

# 신기하지 않나요? 그래도..ㅎㅎ; 무튼 다음 시간에는 주성분분석(Principal Component Analysis, PCA)을 알아보도록 하겠습니다.

반응형