(X축) 시간의 흐름에 따른 (Y축) 값의 추세, 변화 분석 및 탐색을 하는데 시계열 선 그래프(time series plot, line graph)를 많이 이용합니다. 


 이번 포스팅에서는 R ggplot2 패키지로 시계열 선그래프를 그리고, 거기에 세로선을 추가하는 작업을 해보겠습니다. 


ggplot2 에서 세로선을 추가할 때 geom_vline() 함수를 사용하는데요, 이게 시계열 데이터의 경우는 as.numeric() 함수를 사용해서 시계열 데이터를 숫자형 데이터로 변환을 해주어야 에러가 안나고 제대로 세로선이 그려집니다. 


이거 몰라서 한참을 구글링하면서 애 좀 먹었습니다. ^^;


간단한 시계열 데이터를 만들어서 예를 들어보겠습니다. 




> ##======================================================

> ## adding multiple vertical lines at time-series plot using R ggplot2

> ##======================================================

> # making time series data

> dt <- c("20170609100000", "20170609100100", "20170609100200", 

+         "20170609100300", "20170609100400", "20170609100500")

> val <- c(5.2, 3.4, 3.9, 6.3, 4.7, 5.6)

> dt_val <- data.frame(dt, val)

> dt_val <- transform(dt_val, 

+                     dt = as.POSIXct(dt, 

+                                     format = '%Y%m%d%H%M%S', 

+                                     origin = "1970-01-01", 

+                                     tz = "UTC"))

> dt_val

                   dt val

1 2017-06-09 10:00:00 5.2

2 2017-06-09 10:01:00 3.4

3 2017-06-09 10:02:00 3.9

4 2017-06-09 10:03:00 6.3

5 2017-06-09 10:04:00 4.7

6 2017-06-09 10:05:00 5.6

 




R ggplot2 패키지의 geom_line() 함수를 사용해서 시계열 선그래프를 그려보겠습니다. 



> # making time series plot

> library(ggplot2)

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size=1, color = "blue") + 

+   ggtitle("Time-series plot")

 




R ggplot2로 세로선을 추가할 때는 geom_vline(xintercept = x) 함수를 추가해주면 됩니다. 하지만 xintercept 에 들어가는 값이 날짜, 시간 포맷의 데이터일 경우 아래 처럼 에러가 납니다. 



> # To add vertical line at time series plot

> # Error in Ops.POSIXt((x - from[1]), diff(from)) : '/' not defined for "POSIXt" objects

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size = 1, color = "blue") +

+   geom_vline(xintercept = dt_val$dt[3], color =  "red", linetype = 2) +

+   ggtitle("Adding vertical line at time-series plot using geom_vline()")

Error in Ops.POSIXt((x - from[1]), diff(from)) : 

  '/' not defined for "POSIXt" objects

 




R ggplot2 시계열 선그래프에 X축이 날짜, 시간 포맷의 시계열 데이터인 경우 특정 날짜/시간에 세로선을 추가하기 위해서는 as.numeric(x) 함수를 사용해서 숫자형 데이터로 포맷을 바꾸어 주어야 합니다



> # Use as.numeric() function at xintercept

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size = 1, color = "blue") +

+   geom_vline(xintercept = as.numeric(dt_val$dt[3]), color = "red", linetype = 2) + # as.numeric() transformation

+   ggtitle("Adding vertical line at time-series plot using geom_vline() and as.numeric() transformation")

 







만약 복수의 세로선을 추가하고 싶다면 아래의 예제를 참고하세요. 만약 3번째와 5번째 x변수의 날짜/시간에 세로선을 추가하고 싶다면 dataset$variable[c(3, 5)] 처럼 indexing을 해서 xintercept 에 넣어주면 됩니다. 

(세로선 2개가 그려지기는 했는데요, 하단에 빨간색으로 "HOW_BACKTRACK environmental varialbe"이라는 경고메시지가 떴습니다. -_-; )



> # adding "Multiple" vertical lines

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size = 1, color = "blue") +

+   geom_vline(xintercept = as.numeric(dt_val$dt[c(3,5)]), color = "red", linetype = 2) +

+   ggtitle("Adding multiple vertical lines at time-series plot using geom_vline()")

HOW_BACKTRACE environmental variable.


 




이번에는 세로선을 그릴 기준 날짜/시간 데이터를 다른 데이터프레임에서 가져와야 하는 경우를 예로 들어보겠습니다. 먼저 세로선의 기준이 되는 xintercept 에 들어갈 날짜/시간 정보가 들어있는 data frame 을 만들어보죠. 



> # adding multiple vertical lines with another data frame

> dt_2 <- c("20170609100150", "20170609100430")

> val_2 <- c("yes", "yes")

> dt_val_2 <- data.frame(dt_2, val_2)

> dt_val_2 <- transform(dt_val_2, 

+                       dt_2 = as.POSIXct(dt_2, 

+                                         format = '%Y%m%d%H%M%S', 

+                                         origin = "1970-01-01", 

+                                         tz = "UTC"))

> dt_val_2

                 dt_2 val_2

1 2017-06-09 10:01:50   yes

2 2017-06-09 10:04:30   yes

 




R ggplot2 시계열 선그래프를 그린 원본 데이터프레임(아래 예제에서는 dt_val)과는 다른 데이터프레임(아래 예제에서는 dt_val_2)의 날짜/시간 데이터를 사용해서 복수의 세로선을 그려보겠습니다.  두 개의 세로선이 그려지기는 했는데요, "HOW_BACKTRACE environmental variable"이라는 빨간색 경고 메시지가 떴습니다. 그런데, 예전에는 에러 메시지 뜨면서 안그려졌었는데, 블로그 쓰려고 다시 해보니 그려지기는 하는군요. ^^; 



> # time series plot with multiple vertical lines from another data frame

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size = 1, color = "blue") +

+   geom_vline(xintercept = as.numeric(dt_val_2$dt_2), color = "red", linetype = 2) +

+   ggtitle("Time-seires plot with multiple vertical line from another dataframe")

HOW_BACKTRACE environmental variable.




위의 예제처럼 했는데 혹시 Error: Aesthetics must be either length 1 or the same as the data (6): xintercept 와 같은 에러 메시지가 뜨고 그래프가 안그려진다면 아래처럼 geom_vline(data = dataframe, xintercept = ... ) 처럼 데이터를 가져오는 데이터프레임을 명시해주면 문제가 해결됩니다.  이걸 몰라서 또 한참을 고민하고, 구글링하고, 참 애먹었던 적이 있습니다. -_-;



> # time series plot with multiple vertical lines from another data frame(2)

> ggplot(dt_val, aes(x = dt, y = val)) +

+   geom_line(size = 1, color = "blue") +

+   geom_vline(data = dt_val_2, xintercept = as.numeric(dt_val_2$dt_2), color = "red", linetype = 2) +

+   ggtitle("Time-series plot with multiple vertical lines from another dataframe 2")



 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾸욱 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

지난번 포스팅에서는 범주형 특성 데이터, 텍스트 문서의 거리를 측정하는 지표 중에서 


 - 자카드 거리 (Jaccard distance)


 - 코사인 거리 (Cosine distance)


에 대해서 알아보았습니다. 


이번 포스팅에서는 두 문자열의 거리(distance between two strings of characters), 비유사도(dissimilarity)를 측정하는데 사용하는 편집 거리(edit distance), 혹은 다른 이름으로 Levenshtein metric 에 대해서 알아보겠습니다. 


편집거리(edit distance)는 데이터 항목이 놓인 순서(order)가 중요한 문자열(strings of characters, 예: 주소, 전화번화, 이름 스펠링)이나 서열(sequence, 예 : 염색체 염기서열)의 (비)유사도를 측정하는데 유용하게 사용할 수 있습니다. 


편집거리 (edit distance, Levenshtein metric) 는 두 문자열에서 하나의 문자열을 다른 문자열과 똑같게 만들기 위해서 최소로 필요로 하는 편집 회수(문자 추가, 제거, 위치 변경)를 계산합니다. 


아래에 간단한 예를 들어서 설명해보겠습니다. 



[ 편집 거리 예시 (example of edit distance, Levenshtein Metric) ]




아래처럼 사람 이름을 입력한 두 개의 문자열이 있다고 가정해보겠습니다. 

  • 문자열 1 (character string 1): Shawn Henry
  • 문자열 2 (character string 2): Shan Hennyy


'문자열 2'를 편집해서 '문자열 1'로 변환할 때 필요한 최소한의 조치를 생각해보면, 


(편집 조치 1) '문자열 2'의 4번째 위치에 'w'를 추가 (insert a 'w')

(편집 조치 2) '문자열 2'의 8번째 위치에 'n'을 'r'로 교체 (replace an 'n' with a 'r')

(편집 조치 3) '문자열 2'의 10번째 위치에 있는 'y'를 삭제 (delete the last 'y')


와 같이 3번의 편집 조치가 필요합니다.  따라서 '문자열 1'과 '문자열 2'의 편집 거리는 3입니다. 



'문자열 1'을 편집해서 '문자열 2'로 변환할 때 필요한 최소한의 조치를 생각해보면, 


(편집 조치 1) '문자열 1'의 4번째 위치의 'w'를 삭제 (delete a 'w')

(편집 조치 2) '문자열 1'의 9번째 위치의 'r'을 'n'으로 교체 (replace a 'r' with an 'n')

(편집 조치 3) '문자열 1'의 11번째 위치에 'y'를 추가 (insert an 'y')


이므로, 이렇게 계산해도 역시 '문자열 1'과 '문자열 2'의 편집 거리는 3입니다. 





이제 R 의 stringdist package를 사용해서 편집 거리 (edit distance, Levenshtein metric)를 계산해보겠습니다. 


(1) stringdist 패키지 설치 및 불러오기



# installing and loading of stringdist package

install.packages("stringdist")

library(stringdist)

 




(2) 문자열 편집 거리(edit distance, Levenshtein metric) 계산: stringdist()


문자열 "shawn henry"와 "shan hennyy", "show hurry" 문자열 간의 편집거리를 각각 계산해보겠습니다. 



> # to compute string edit distances

> # default method is 'osa', which is Optimal string alignment, (restricted Damerau-Levenshtein distance)

> stringdist(c("shawn henry"), c("shan hennyy", "show hurry"))

[1] 3 4

 



"shawn henry"와 "show hurry"의 편집거리를 계산하기 위해, 'show hurry'를 'shawn henry'로 변환하기 위한 최소 편집 조치를 살펴보면


(편집 조치 1) 'o'를 'a'로 변경 =>  shaw hurry

(편집 조치 2) 'n'을 추가   => shawn hurry

(편집 조치 3) 'u'를 'e'로 변경 => shawn herry

(편집 조치 4) 'r'을 'n'으로 변경 => shawn henry  (끝)


이므로, 편집거리는 4가 됩니다. 




(3) 여러개의 문자열 간의 편집 거리 (edit distance) 계산 결과를 행렬로 만들기: stringdistmatrix()


R stringdist 패키지에 들어있는 간단한 예제를 인용해서 예를 들어보겠습니다. 



> # to compute a dist object of class dist

> # => can be used by clustering algorithms such as stats::hclust

> stringdistmatrix(c("foo","bar","boo","baz"))

  1 2 3

2 3    

3 1 2  

4 3 1 2

> str_dist_mat <- as.matrix(stringdistmatrix(c("foo","bar","boo","baz")))

> str_dist_mat

  1 2 3 4

1 0 3 1 3

2 3 0 2 1

3 1 2 0 2

4 3 1 2 0

 




(4) 가장 유사한 문자열의 위치 찾기: amatch()


stringdist 패키지에는 'hello' 문자열과 편집 거리(edit distance, Levenshtein metric)가 가장 짧은 문자열의 위치를 찾아주는 amatch() 함수가 있습니다.  아래 예처럼 maxDist=2 라고 설정하면 편집 거리가 2를 넘어서는 문자열은 무시하게 됩니다.  동일 최소 편집거리 문자열이 여러개 있으면 앞에 위치한 문자열의 위치를 제시해줍니다. 



> # Approximate string matching

> # amatch returns the position of the closest match of x in table

> # by default, the OSA algorithm is used 

> # : Optimal string aligment (restricted Damerau-Levenshtein distance)

> amatch(c("hello"),c("hillu","hala","hallo", "hi"),maxDist=2)

[1] 3

 


- 'hello' 문자열과 'hillu' 문자열 간 편집 거리는 2 ('i'를 'e'로 교체, 'u'를 'o'로 교체), 

- 'hello' 문자열과 'hala' 문자열 간의 편집 거리는 3 ('a'를 'e'로 교체, 'l' 추가, 'a'를 'o'로 교체, 단, maxDist=2 이므로 고려 대상에서 제외됨), 

- 'hello' 문자열과 'hallo' 문자열 간의 편집 거리는 1 ('a'를 'e'로 교체)


이므로 편집 거리가 가장 짧은 'hallo' 의 3 을 반환합니다. 



* reference: stringdist package manual ( https://cran.r-project.org/web/packages/stringdist/stringdist.pdf)



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾸욱 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

예전 포스팅에서는 연속형 변수들 간의 거리를 측정하는 Measure로서 맨하탄 거리, 유클리드 거리, 표준화 거리, 마할라노비스 거리 등에 대해서 소개하였습니다. 


이전 포스팅에서는 명목형 데이터를 원소로 가지는 두 집합 X, Y의 특징들 간의 공통 항목들의 비율 (교집합의 개수 / 합집합의 개수)을 가지고 두 집합 간 유사성을 측정하는 Jaccard Index 와 (1 -  Jaccard Index)로 두 집합 간 거리(비유사성)을 측정하는 Jaccard Distance에 대해서 알아보았습니다. 


이번 포스팅에서는 문서를 유사도를 기준으로 분류 혹은 그룹핑을 할 때 유용하게 사용할 수 있는 코사인 거리(Cosine Distance)에 대해서 소개하겠습니다. 


코사인 거리를 계산할 때는 먼저 문서(Document, Text)에 포함된 단어들을 단어별로 쪼갠 후에, 단어별로 개수를 세어 행렬로 만들어주는 전처리가 필요합니다. (대소문자 처리라든지, 일상적으로 쓰이는 별로 중요하지 않은 단어 처리라든지... 이게 좀 시간이 오래걸리고, 단어 DB랑 처리 노하우가 필요한 부분입니다)


이번 포스팅에서는 이런 전처리가 다 되어있다고 가정하고, 코사인 거리 (혹은 코사인 유사도)의 정의와 계산 방법, R로 자동계산하는 방법을 소개하는데 집중하겠습니다. 


아래의 '참고 1'에서와 같이 코사인 유사도(Cosine Similarity)는 두 개의 문서별 단어별 개수를 세어놓은 특징 벡터 X, Y 에 대해서 두 벡터의 곱(X*Y)을 두 벡터의 L2 norm (즉, 유클리드 거리) 의 곱으로 나눈 값입니다. 


그리고 코사인 거리(Cosine Distance)는 '1 - 코사인 유사도(Cosine Similarity)' 로 계산합니다. 

(유사도 측정 지표인 Jaccard Index 와 비유사도 측정 지표인 Jaccard Distance 와 유사합니다)



[ 참고 1 : 코사인 유사도 (Cosine Similarity) vs. 코사인 거리 (Cosine Distance) ]





위의 공식만 봐서는 쉽게 이해가 안갈 수도 있을 것 같은데요, 아주 간단한 예를 가지고 좀더 자세하게 설명해 보겠습니다. 


Document 1, Document 2, Document 3 라는 3개의 문서가 있다고 해보겠습니다. 

그리고 각 문서에 'Life', 'Love', 'Learn' 이라는 3개의 단어가 포함되어 있는 개수를 세어보았더니 다음과 같았습니다. 



[ Table 1 : 3개의 문서별 단어별 출현 회수 (number of presence by words in each documents) ]


                           Corpus 

 Text

Life

Love 

Learn 

 Document 1

 1

0

 Document 2

 4

7

 Document 3

 40

70 

30

(예 : Document 2에서는 'Life'라는 단어가 4번, 'Love'라는 단어가 7번, 'Learn'이라는 단어가 3번 출현함(포함됨))



위의 'Table 1'의 각 문서별 출현하는 단어별 회수를 특징 벡터로 하는 벡터를 가지고 'Document 1'과 'Document 2' 간의 코사인 거리(Cosine Distance)를 사용해서 각 문서 간 비유사도를 계산해보겠습니다. 



[ 참고 2 : 'Document 1'과 'Document 2' 간의 코사인 거리 (cosine distance b/w doc. 1 and doc. 2) ]





코사인 거리(Cosine Distance)를 계산할 때 사용하는 코사인 유사도(Cosine Similarity) 의 분자, 분모를 보면 유추할 수 있는데요, 두 특징 벡터의 각 차원이 동일한 배수로 차이가 나는 경우에는 코사인 거리는 '0'이 되고 코사인 유사도는 '1'이 됩니다. 


위의 'Table 1'의 예에서 'Document 2'와 'Document 3'의 각 단어 (Life, Love, Learn)별 출현 회수가 동일하게 '10배'씩 차이가 나고 있는데요, 바로 이런 경우를 말하는 것입니다. Document 23 가 Document 2보다 쪽수가 더 많고 두꺼워서 각 단어별 출현 빈도는 더 높을 지 몰라도 각 단어가 출현하는 비율은 좀더 얇은 Document 2나 더 두꺼운 Document 3가 동일(유사)하므로 두 문서는 유사한 특성을 가지고 있다고 코사인 거리는 판단하는 것입니다. 이처럼 단위에 상관없이 코사인 거리를 사용할 수 있으므로 꽤 편리하고 합리적입니다. 



[ 참고 3 : 'Document 2'과 'Document 3' 간의 코사인 거리 (cosine distance b/w doc. 2 and doc. 3]






이제부터는 R의 proxy package의 dist(x, method = "cosine") 함수를 사용해서 코사인 거리를 구하는 방법을 소개합니다



(1) proxy 패키지를 설치하고 불러오기



## installing and loading proxy package

install.packages("proxy")

library(proxy)

 




(2) 문서별 단어별 출현 회수를 특징 벡터로 가지는 행렬 (Term Document Matrix) 만들기


위에서 설명했던 3개 문서의 'Life', 'Love', 'Learn'의 3개 단어 예제를 그대로 사용합니다. 



> # making Term Document Matrix

> Doc_1 <- c(1, 0, 5)

> Doc_2 <- c(4, 7, 3)

> Doc_3 <- c(40, 70, 30)

> Doc_corpus <- rbind(Doc_1, Doc_2, Doc_3) # matrix

> colnames(Doc_corpus) <- c("Life", "Love", "Learn")

> Doc_corpus

      Life Love Learn

Doc_1    1    0     5

Doc_2    4    7     3

Doc_3   40   70    30

 




(3) proxy 패키지의 dist(x, method = "cosine") 함수로 코사인 거리 계산하고, as.matrix() 함수를 사용해서 코사인 거리 계산 결과를 행렬로 반환하기



> # calculating cosine distance between documents using proxy package

> cosine_dist_Doc_mat <- as.matrix(dist(Doc_corpus, method = "cosine"))

> cosine_dist_Doc_mat

          Doc_1     Doc_2     Doc_3

Doc_1 0.0000000 0.5668373 0.5668373

Doc_2 0.5668373 0.0000000 0.0000000

Doc_3 0.5668373 0.0000000 0.0000000

 





proxy package를 사용하지 않을 거면, 위의 '참고 1'의 공식을 사용하여 아래처럼 함수를 직접 짜서 코사인 거리를 계산할 수도 있습니다. 참고하세요. 



> # cosine distance function

> cosine_Dist <- function(x){

+   as.dist(1 - x%*%t(x)/(sqrt(rowSums(x^2) %*% t(rowSums(x^2))))) 

+ }

> cosine_Dist(Doc_corpus)

          Doc_1     Doc_2

Doc_2 0.5668373          

Doc_3 0.5668373 0.0000000

 



많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감 ~ '를 꾸욱 눌러주세요. ^^


다음 포스팅에서는 문자열 편집거리(edit distance, Levenshtein metric)에 대해서 알아보겠습니다. 



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

연속형 변수에 대한 비유사성 측도(dissimilarity measure)로서 매우 다양한 측도가 있는데요, 예전 포스팅에서 맨하탄 거리(Manhattan distance), 유클리드 거리(Euclidean distance), 표준화 거리(Standardized distance), 마할라노비스 거리(Mahalanobis distance) 에 대해서 알아보았습니다. (=> http://rfriend.tistory.com/199 , http://rfriend.tistory.com/201)


이번 포스팅에서는 범주형 데이터에 대해서 비유사성을 측정하는 지표로 Jaccard distance 를 소개하겠습니다. 


Jaccard distance 는 비교 대상의 두 개의 객체를 특징들의 집합(sets of characteristics)으로 간주합니다. 기본 개념이나 표기법이 집합론(set theory)에 기반을 두고 있습니다. 


Jaccard Index는 유사성 측도이고, 1에서 Jaccard Index값을 뺀 Jaccard distance는 비유사성 측도입니다. 


특징들의 두 개의 집합 X, Y가 있다고 했을 때, Jaccard Index는 집합 X와 집합 Y의 교집합(Intersection)의 원소의 개수()를 집합 X와 집합 Y의 합집합(Union)의 원소의 개수()로 나눈 값입니다.   따라서 Jaccard Index는 0~1 사이의 값을 가집니다. 


참고로, 표기는 집합론에서는 원소의 개수를 나타낼 때 사용하는 표기법이며, 다 아시겠지만, 는 교집합, 는 합집합을 의미합니다. 

Jaccard Distance 는 1 에서 Jaccard Index를 뺀 값입니다. ()


만약 두 집합의 합집합과 교집합이 서로 비슷하다면 자카드 지수는 거의 1에 근접(즉, 매우 유사)할 것이구요, 자카드 거리는 거의 0에 근접(즉, 매우 거리가 가깝다는 뜻, 즉 유사)할 것입니다. 


자카드 거리는 "두 집합에 공통으로 공유되는 항목은 중요한 반면에, 두 집합에서 모두 존재하지 않는 항목에 대해서는 무시해도 되는 상황, 문제"에 적합한 비유사성 측도입니다. 비교 대상이 되는 두 집합의 합집합, 교집합에 해당되는 않는 항목(item)은 그냥 제껴버리고 무시해버립니다. 


그 동안 군집분석을 소개하면서 비유사성 측도로서 거리(Distance)를 사용해왔는데요, 여기서도 Jaccard Distance를 가지고 예를 들어서 소개하고, R 로 실습도 해보겠습니다.  



[그림 1] 자카드 지표 & 자카드 거리 (Jaccard Index & Jaccard Distance)





이해를 쉽게 하기 위해서 아주 간단한 예를 하나 들어보겠습니다. 


5개의 상자가 있는데요, 거기에는 빨강, 노랑, 파랑 색깔의 공이 들어있다고 해봅시다. 그리고 각 상자별로 들어있는 공의 색깔을 가지고 상자들 끼리의 비유사성을 Jaccard 거리로 재보도록 하겠습니다. 



 -. 상자 1 = {노랑}

 -. 상자 2 = {노랑}

 -. 상자 3 = {빨강, 노랑, 파랑}

 -. 상자 4 = {빨강, 노랑}

 -. 상자 5 = {파랑}

 



(1) '상자 1'과 '상자 2'의 합집합(union)의 개수는 |{노랑}| = 1 이구요, 교집합(intersection)의 개수는 |{노랑}| =  1 이므로, 자카드 거리(상자 1, 상자 2) = 1 - (1/1) = 0 입니다. 


(2) '상자 1'과 '상자 3'의 합집합의 개수는 |{빨강, 노랑, 파랑}| = 3 이구요, 교집합의 개수는 |{노랑}| =  1 이므로, 자카드 거리(상자 1, 상자 3) = 1 - (1/3) = 약 0.667 입니다. 


(3) '상자 1'과 '상자 4'의 합집합의 개수는 |{빨강, 노랑}| = 2 이며, 교집합의 개수는 |{노랑}| =  1 이므로, 자카드 거리(상자 1, 상자 4) = 1 - (1/2) = 0.5 입니다. 


(4) '상자 1'과 '상자 5'의 합집합의 개수는 |{노랑, 파랑}| =  2 이며, 교집합의 개수는 |{NA}| = 0 이므로, 자카드 거리(상자 1, 상자 5) = 1 - (0/2) = 1 입니다. 


(5) '상자 3'과 '상자 4'의 합집합의 개수는 |{빨강, 노랑, 파랑}| = 3 이구요, 교집합의 개수는 |{빨강, 노랑}| = 2 이므로, 자카드 거리(상자 3, 상자 4) = 1 - (2/3) = 약 0.333 입니다. 


(6) '상자 3'과 '상자 5'의 합집합의 개수는 |{빨강, 노랑, 파랑}| = 3, 교집합의 개수는 |{파랑}| =  1 이므로, 자카드 거리(상자 3, 상자 5) = 1 - (1/3) = 약 0.667 입니다. 


(7) '상자 4'와 '상자 5'의 합집합의 개수는 |{빨강, 노랑, 파랑}| =  3 이며, 교집합의 개수는 |{NA}| = 0 이므로, 자카드 거리(상자 4, 상자 5) = 1 - (0/3) = 1 입니다. 






이를 R의 proxy package를 사용해서 풀어보겠습니다. 


먼저 proxy package를 설치하고 불러오도록 합니다. 



#===========================================

# distance(dissimilarity) calculation using proxy package

#===========================================


> install.packages("proxy")

> library(proxy)

 




proxy package는 2017년 초에 CRAN에 등록이 된 따끈따근한 패키지인데요, 총 49개의 proximity 지표(similarity measures, distance measures) 가 들어있습니다. 



> # show available proximities

> pr_DB

An object of class "registry" with 49 entries.

> summary(pr_DB)

* Similarity measures:

Braun-Blanquet, Chi-squared, Cramer, Dice, Fager, Faith, Gower, Hamman, Jaccard,

Kulczynski1, Kulczynski2, Michael, Mountford, Mozley, Ochiai, Pearson, Phi, Phi-squared,

Russel, Simpson, Stiles, Tanimoto, Tschuprow, Yule, Yule2, correlation, cosine, eDice,

eJaccard, simple matching


* Distance measures:

Bhjattacharyya, Bray, Canberra, Chord, Euclidean, Geodesic, Hellinger, Kullback,

Levenshtein, Mahalanobis, Manhattan, Minkowski, Podani, Soergel, Wave, Whittaker,

divergence, fJaccard, supremum





proxy package의 Jaccard 클래스에 대해서 간략한 설명을 살펴보면 아래와 같습니다. binary 형태의 데이터에 대한 (비)유사성 척도라고 되어 있습니다.  그리고 (FALSE, FALSE) pairs 에 대해서는 고려하지 않고 무시하며, 비교 대상의 두 객체 집합의 합집합과 교집합을 비교한다고 되어 있습니다. 


> names(pr_DB)

 [1] "get_field"              "get_fields"             "get_field_names"       

 [4] "set_field"              "entry_exists"           "get_entry"             

 [7] "get_entries"            "get_entry_names"        "set_entry"             

[10] "modify_entry"           "delete_entry"           "n_of_entries"          

[13] "get_field_entries"      "get_permissions"        "restrict_permissions"  

[16] "seal_entries"           "get_sealed_entry_names" "get_sealed_field_names"


> pr_DB$get_entry("Jaccard")

      names Jaccard, binary, Reyssac, Roux

        FUN R_bjaccard

   distance FALSE

     PREFUN pr_Jaccard_prefun

    POSTFUN NA

    convert pr_simil2dist

       type binary

       loop FALSE

      C_FUN TRUE

    PACKAGE proxy

       abcd FALSE

    formula a / (a + b + c)

  reference Jaccard, P. (1908). Nouvelles recherches sur la distribution florale. Bull.

            Soc. Vaud. Sci. Nat., 44, pp. 223--270.

description The Jaccard Similarity (C implementation) for binary data. It is the proportion

            of (TRUE, TRUE) pairs, but not considering (FALSE, FALSE) pairs. So it compares

            the intersection with the union of object sets.

 




위의 상자 5개의 공 색깔 예제를 R로 실습해 보기 위해서 아래 처럼 5개의 행(row)은 상자를 나타내고, 3개의 열(column)은 색깔(순서대로 빨강, 노랑, 파랑)을 나타내는 걸로 하겠습니다. 그리고 각 상자별 빨강, 노랑, 파랑 색깔의 공이 있으면 ' 1(TRUE)'을 입력하고, 공이 없으면 '0(FALSE)'을 입력해서 행렬(matrix)을 만들어보겠습니다. proxy package가 타카드 거리를 계산할 수 있도록 binary 형태의 데이터셋을 만드는 것입니다. 



> # making binary dataset as a matrix

> x <- matrix(c(0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1), 

+             byrow = TRUE, 

+             ncol = 3)

> x

     [,1] [,2] [,3]

[1,]    0    1    0

[2,]    0    1    0

[3,]    1    1    1

[4,]    1    1    0

[5,]    0    0    1 





dist(x, method = "Jaccard") 함수를 사용해서 Jaccard distance를 계산해보겠습니다.  위의 예에서 손으로 푼 결과와 동일한 값들이 나왔습니다. 



> # Jaccard distance

> dist(x, method = "Jaccard")

          1         2         3         4

2 0.0000000                              

3 0.6666667 0.6666667                    

4 0.5000000 0.5000000 0.3333333          

5 1.0000000 1.0000000 0.6666667 1.0000000

 




아래처럼 cross Jaccard distances 를 계산하려면 dist(x, x, method = "Jaccard") 처럼 행렬 x 를 두번 입력해주면 됩니다. 



> # cross Jaccard distances

> dist(x, x, method = "Jaccard")

     [,1]      [,2]      [,3]      [,4]      [,5]     

[1,] 0.0000000 0.0000000 0.6666667 0.5000000 1.0000000

[2,] 0.0000000 0.0000000 0.6666667 0.5000000 1.0000000

[3,] 0.6666667 0.6666667 0.0000000 0.3333333 0.6666667

[4,] 0.5000000 0.5000000 0.3333333 0.0000000 1.0000000

[5,] 1.0000000 1.0000000 0.6666667 1.0000000 0.0000000

 




proxy package에 비해서는 조금 비효율적이기는 하지만 stats package 의 dist(x, method = "binary")함수를 사용해서도 Jaccard distance를 계산할 수 있습니다. 



> # using stats package (less efficient than proxy package)

> as.matrix(stats::dist(x, method = "binary"))

          1         2         3         4         5

1 0.0000000 0.0000000 0.6666667 0.5000000 1.0000000

2 0.0000000 0.0000000 0.6666667 0.5000000 1.0000000

3 0.6666667 0.6666667 0.0000000 0.3333333 0.6666667

4 0.5000000 0.5000000 0.3333333 0.0000000 1.0000000

5 1.0000000 1.0000000 0.6666667 1.0000000 0.0000000

 



많은 도움 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~' 단추를 꾸욱 눌러주세요. ^^


다음번 포스팅에서는 코사인 거리(Cosine Distance),  문자열 편집 거리(edit distance, Levenshtein metric)를 알아보겠습니다. 




저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

프로젝트 과제, 세부 업무 별로 시작 시점과 끝 시점을 선으로 그어서 한 눈에 일정 관리를 할 수 있도록 도와주는 시각화 기법으로 간트 차트(Gantt Chart)를 많이 사용합니다. 


간트 차트가 일정 관리 측면에서는 매우 강력한 시각화 도구이다 보니 간트 차트를 쉽고 빠르게 그릴 수 있도록 도와주는 '뉴간트메이커 간트 차트', '차트 스쿨 2.0', 'GanttProject', 'Online Gantt Chart' 등의 전문 소프트웨어가 있습니다. 


R을 가지고도 간트 차트를 그릴 수 있는데요, 이번 포스팅에서는 R의 timevis 패키지를 사용해서 간트 차트를 그리는 방법을 알아보겠습니다. 


R로 간트 차트를 그리려고 반나절 이상을 골머리를 앓다가 timevis 패키지를 발견하고서 얼마나 반가웠는지 모릅니다. 그리고 timevis 패키지를 사용해보니 제공하는 기능이 매우 놀라웠습니다. 들인 노력 대비 산출물이 매우 세련되 보이거든요. interactive 기능도 제공합니다. ^^b  timevis 패키지는 vis.js 의 timeline module 과 htmlwidgets R package 를 근간으로 해서 만들어졌다고 하는걸 보니 java script 기반의 패키지를 가지고 R 바인딩해놓은 같습니다. 


timevis 패키지는 Dean Attali 라는 분이 오픈 소스로 개발했는데요, R-Shiny founder라고 자기소개에 나와있네요. 요즘 탐색적 데이터 분석(Exploratory Data Analysis)하는데 R-Shiny 사용해보면서 감탄하고 있는데요, R-Shiny app에 timevis 로 그린 간트차트도 추가해서 이쁘게 app하나 만들었더니 간지 나더라구요. Dean Attali 개발자님께 이래저래 고마운 마음 전합니다. ^^b


아래 포스팅은 Deam Attali의 Git-Hub(https://github.com/daattali/timevis) 페이지와 R ?timevis 도움말의 예제 코드를 거의 수정없이 인용해서 작성하였구요, 그래프의 화면 캡쳐와 동영상을 추가해서 처음 사용하시는 분의 이해를 조금 더 돕는다는 취지로 작성을 해보았습니다. 



1. timevis 패키지 설치 및 로딩



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

## gantt chart by timevis package

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


# reference : https://github.com/daattali/timevis


# install timevis package

install.packages("timevis")

 




2. 날짜 데이터 입력 없는 상태에서 timeline 형태 살펴보기 


아래 timeline의 가운데 빨간 선은 시스템 날짜(Sys.Date) 입니다. 



# minimum view of timeline without any data at system time

library(timevis)

timevis()

 






3. 특정 날짜(Item), 혹은 기간(Range) 데이터를 입력한 간트 차트 (Gantt Chart) 그리기


timevis 패키지에서 사용하는 데이터셋이 데이터프레임(DataFrame)이라는 점이 원천 데이터를 거의 손볼 필요없이 그대로 사용할 수 있어서 저는 매우 좋더군요.  아래의 R script 처럼 'id', 'content', 'start', 'end'라는 칼럼이 데이터프레임에 포함되어 있으면 됩니다. 


  • id : 인덱싱(indexing) 할 때 사용
  • content : 간트 차트에 포함될 내용
  • start : 시작 시간 (년-월-일, 혹은 년-월-일 시간:분:초 포맷)
  • end : 끝 시간 (년-월-일, 혹은 년-월-일 시간:분:초 포맷)


start은 반드시 날짜, 혹은 날짜&시간 데이터가 들어가야만 에러가 안나구요, end 칼럼에는 NA 결측값으로 비워두어도 상관없습니다. end 칼럼에도 일시 데이터가 들어가면 start ~ end 의 기간(range)의 timeline 이 선으로 길게 그려집니다. 



# adding data to timevis() by DataFrame

data <- data.frame(

  id      = c(1:4),

  content = c("Item_First"  , "Item_Second"  ,"Ranged_First", "Ranged_Second"),

  start   = c("2017-05-26", "2017-05-27 01:30:00", "2017-05-27 05:00:00", "2017-05-30"),

  end     = c(NA          , NA                   , "2017-05-28 15:00:00", "2017-05-31 03:10:00")

)


# view of Gantt chart

timevis(data)

 






4. 데이터프레임의 각 칼럼 데이터 형태


input으로 사용되는 DataFrame의 각 칼럼의 데이터 행태를 살펴보면 id는 정수형(integer), content, start, end는 요인형(factor) 입니다.  혹시 데이터프레임 만들어서 timevis() 함수 적용했는데 그래프가 안그려지고 에러가 나면 content, start, end 칼럼의 데이터 형태가 요인형(factor)인지 확인해보시기 바라며, 혹시 문자형(character)으로 되어 있으면 as.factor() 를 사용해서 요인형으로 변환 후에 timevis() 를 다시 적용해보시기 바랍니다. 



> # checking data type

> sapply(data, class)

       id      content      start        end 

"integer"  "factor"  "factor"  "factor"

 




5. Zoom-in, Zoom-out, 좌-우 이동하는 동적 시각화


우측 상단에 있는 '+' 단추를 누르면 'Zoom-in'이 되어 더 짧은 기간으로 현미경의 눈으로 심화해서 간트 차트를 그려줍니다 (아래 그림 예시).  반대로 '-' 단추를 누르면 'Zoom-out'이 되어 높은 하늘 위의 새의 눈으로 더 넓은 기간의 간트 차트를 보여줍니다. 


 





커서로 timeline 을 클릭한 후에 좌, 우로 끌고 가면 간트 차트가 동적으로 움직이며, 마우스 휠을 사용해서도 Zoom-in, Zoom-out 을 할 수가 있습니다.  동적으로 움직이는 신기한(?) 그래프를 단 한 줄의 R script (즉, timevis(data) 로 끝) 로 만든 것입니다.  말로 설명하려니 감흥이 덜할 것 같은데요, 아래 동영상 참고하세요. 





6. Zoom 단추 숨기기, 편집 기능 설정, timeline 높이 설정


  • showZoom = FALSE   : 우측 상단의 Zoom 단추 숨기기  ( <= 이거 없어도 마우스 휠 사용하면 됨)
  • options = list(editable = TRUE)  :  TRUE 이면 timeline bar를 커서로 선택했을 때 색이 바뀌며, 'X' 표시를 누르면 간트 차트에서 사라짐 
  • options = list(height = "300px")  : timeline 높이를 하드 코딩으로 설정 ( <= 이거 굳이 하드코딩 안해줘도 알아서 유동적으로 높이 잘 조정해 줌) 


# hide the zoom buttons, options for editable, height

timevis(data, 

            showZoom = FALSE, 

            options = list(editable = TRUE, 

                                  height = "300px"))


 




7. %>% chain operator, 일정 추가(add Item), 디폴트 일정 선택(set Selected Item)


  • timevis() %>% : chain operator  (dplyr 패키지 사용해본 분이라면 익숙하실 듯)
  • setItems(data.frame(id, content, start, end)) : id, content, start, end(optional) 로 이루어진 원본 데이터셋
  • addItem(list(id, content, start, end)) : 개별 일정을 추가하고 싶을 때 사용
  • setSelection("1") : 간트 차트가 화면에 떴을 때 처음 선택이 되게 하고 싶은 id 를 지정 (아래 예에서는 "1"번의 "one" item 이 색깔이 바뀌어 있고, editable = TRUE 로 설정했으므로 'X' 표시가 같이 나타남)


# %>% operator, set editable Options, add Item, set Selected Item

timevis() %>%

  setItems(data.frame(

    id = 1:2,

    content = c("one", "two"),

    start = c("2017-05-28", "2017-05-30")

  )) %>%

  setOptions(list(editable = TRUE)) %>%

  addItem(list(id = 3, content = "three", start = "2017-05-29")) %>%

  setSelection("1") 





8. 그룹(group)으로 묶어서 간트 차트 구성하기


업무의 특성(예: 컨설팅, 개발), 프로젝트 단계(예 : Phase 1, Phase 2), 조직(예: 설계팀, 개발팀, 지원팀) 등 특정 기준에 따라서 Item 들을 그룹으로 묶어서 간트 차트를 그리고 싶을 때가 있습니다.  이 기능을 잘 사용하면 간트 차트를 좀더 구조화해서 보여줄 수 있으므로 일목요연하게 시각화하는데 매우 유용합니다. 



# using the groups feature to group together multiple items into different buckets

timevis(

  data = data.frame(

    start = c(Sys.Date(), Sys.Date(), Sys.Date() + 1, Sys.Date() + 2),

    content = c("one", "two", "three", "four"), 

    group = c(1, 2, 1, 2)),

  groups = data.frame(id = 1:2, content = c("Group_1", "Group_2"))

)

 




9. timevis() 간트 차트를 RShiny 에 연동


RShiny 에도 timevis() 패키지를 사용해서 간트 차트, timeline을 삽입할 수 있습니다.  RShiny 문법에 대해서는 이 포스팅에서 설명하자면 너무 길어지게 되므로 생략하겠구요, 동적 문서(Dynamic Document) 카테고리에서 별도로 나중에 포스팅하겠습니다. 



# RShiny


library(shiny)


data <- data.frame(

  id = 1:3,

  start = c("2015-04-04", "2015-04-05 11:00:00", "2015-04-06 15:00:00"),

  end = c("2015-04-08", NA, NA),

  content = c("<h2>Vacation!!!</h2>", "Acupuncture", "Massage"),

  style = c("color: red;", NA, NA)

)


ui <- fluidPage(

  timevisOutput("appts"),

  div("Selected items:", textOutput("selected", inline = TRUE)),

  div("Visible window:", textOutput("window", inline = TRUE)),

  tableOutput("table")

)


server <- function(input, output) {

  output$appts <- renderTimevis(

    timevis(

      data,

      options = list(editable = TRUE, multiselect = TRUE, align = "center")

    )

  )

  

  output$selected <- renderText(

    paste(input$appts_selected, collapse = " ")

  )

  

  output$window <- renderText(

    paste(input$appts_window[1], "to", input$appts_window[2])

  )

  

  output$table <- renderTable(

    input$appts_data

  )

}


shinyApp(ui, server)


 



[Reference] https://github.com/daattali/timevis


많은 도움 되었기를 바랍니다. 


이번 포스팅이 도움이 되셨다면 아래의 '공감~'를 꾸욱 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

이번 포스팅에서는 ggplot2로 그린 그래프에서 


 - (1) 범례 위치 바꾸기

        (changing the position of legend)


 - (2) 범례 글자 크기 및 색깔 바꾸기

        (changing the size and color of the legend)


 - (3) 범례 항목 순서 바꾸기

        (changing the order of legend label)


 - (4) 범례 없애기

        (removing the legend)


등 범례(legend)를 다루는 방법에 대해서 알아보겠습니다. 



MASS package의 Cars93 데이터프레임에 있는 '차종(Type)별 고속도로 연비(MPG.highway)' 박스 그래프를 가지고 예를 들어보겠습니다. 


박스 그래프 디폴트 옵션으로 그리면 아래와 같은 결과가 나옵니다. 



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

# ggplot2 : legend 

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

library(MASS)

library(ggplot2)


# Boxplot of MPG.highway per Car Type

mpg <- ggplot(Cars93, aes(x = Type, y = MPG.highway, fill = Type)) +

  geom_boxplot() +

  theme_bw() +

  ggtitle("MPG.highway per Car Type")


mpg

 






 (1) 범례 위치 바꾸기 (changing the position of legend) : theme(legend.position = "bottom")


디폴트 세팅에서는 오른쪽("right")에 범례가 있습니다.  

theme(legend.position) argument를 사용해서 범례 위치를 그래프 바깥쪽으로 해서 아래("bottom"), 왼쪽("left"), 위쪽("top")으로 차례대로 바꾸어 보겠습니다. (범례를 위쪽에 배치하는 것은 이상하게 보이네요. ^^;)



# (1) Changing the legend position

# (1-1) outside the plot by using theme(legend.position = "right", "bottom", "left", "top")


# bottom

mpg + theme(legend.position = "bottom")




# left

mpg + theme(legend.position = "left")



# top

mpg + theme(legend.position = "top") 





범례를 놓고 싶은 위치의 x, y 좌표를 숫자 벡터로 입력을 해주면 그래프의 안쪽에도 범례를 집어넣을 수 있습니다. 이때 x, y 좌표는 0~1 사이의 실수 값을 넣어주면 됩니다. x 좌표에서는 0이 그래프 안쪽의 가장 왼쪽이고 1은 가장 오른쪽이 되며, y 좌표에서 0은 그래프 안쪽의 가장 아래쪽이고 1은 가장 위쪽 방향이 되겠습니다. 아래 예에서는 그래프의 오른쪽 상단에 여유 공간이 많이 있으므로 c(0.9, 0.8)의 숫자 벡터를 입력해서 범례를 우측 상단에 놓아 보겠습니다. 



# (1-2) inside the plot by using the location vector c(x coordinate, y coordinate) 

mpg + theme(legend.position = c(0.9, 0.8)) # coordinate value : between 0 and 1





 (2) 범례 글자 크기 및 색깔 바꾸기 (changing the size and color of the legend)

      : theme(legend.title = element_text(color, size, face))

      : theme(legend.text = element_text(color, size, face))


범례의 글자 크기와 색깔, 폰트도 바꿀 수가 있습니다. 자유도가 높아 그래프를 예쁘게 꾸미고 싶은 분에게는 유용할 것입니다. 범례의 제목(title)과 레이블(label text)의 색을 파란색(color = "blue)으로 바꾸고, 범례 제목은 12 크기(size = 12)로 더 키우고, 범례 레이블은 8 크기로 좀더 작게 조정하겠습니다. 그리고 범례 제목은 굵게(face = "bold"), 범례 레이블은 이탤릭체(face = "italic")로 바꾸어 보겠습니다. 



# (2) Changing the legend title and label size and color

mpg + 

  theme(legend.title = element_text(color = "blue", size = 12, face = "bold")) + # legend title

  theme(legend.text = element_text(color = "blue", size = 8, face = "italic")) # legend label





 (3) 범례 항목 순서 바꾸기 (changing the order of legend label)

      : factor(Type, levels = ("Compact", "Small", "Midsize", "Large", "Sporty", "Van")


범례의 레이블 순서를 차종(Type)의 크기에 맞게 바꾸고 싶을 때는 ggplot2 에서 무얼 하는 것은 아니구요, 데이터너 전처리 단계에서 transform() 함수를 사용해서 factor(Type, levels = c("Compact", "Small", "Midsize", "Large", "Sporty", "Van") 처럼 요인(factor)의 levels 의 순서를 바꾸어 주면 됩니다. (ie, ordered factor)


이렇게 해주면 범례의 레이블 순서도 바뀌고, x 축의 항목들의 순서도 역시 바뀌게 됩니다. 



> # (3) Changing the order of legend labels

> # checking the levels and class of 'Type' variable

> attributes(Cars93$Type)

$levels

[1] "Compact" "Large"   "Midsize" "Small"   "Sporty"  "Van"    


$class

[1] "factor"


> # changing the level's order of factor 'Type'

> Cars93 <- transform(Cars93, 

+                  Type = factor(Type, levels = c("Compact", "Small", "Midsize", 

+                                                                    "Large", "Sporty", "Van")))

> attributes(Cars93$Type)

$levels

[1] "Compact" "Small"   "Midsize" "Large"   "Sporty"  "Van"    


$class

[1] "factor"


> mpg_legend_order_change <- ggplot(Cars93, aes(x = Type, y = MPG.highway, fill = Type)) +

+   geom_boxplot() +

+   theme_bw() +

+   ggtitle("Changing the order of legend labels by Car Size")

> mpg_legend_order_change

 




 (4) 범례 없애기 (removing the legend) 

        : theme(legend.title = element_blank())

        : theme(legend.position = 'none')


범례를 아예 없애고 싶을 때는 범례의 제목을 없애는 theme(legend.title = element_blank())와 범례의 레이블을 없애는 theme(legend.position = 'none') 의 두 개의 arguments 를 추가해주면 됩니다. 



# (4) Removing the legend title and labels

mpg + 

  theme(legend.title = element_blank()) +   # remove legend title

  theme(legend.position = 'none')                # remove legend labels


 



이상으로 ggplot2로 그린 그래프의 범례(legend)를 설정하는 여러가지 방법을 알아보았습니다. 

많은 도움 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾸욱 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

개발 프로젝트에 가보면 서버와 클라이언트 간 데이터 전송할 때 XML 보다 기능은 적지만 보다 간단하고 파싱도 빠른 JSON(JavaScript Object Notation, (/ˈsən/ JAY-sən)) 데이터 포맷을 많이 사용합니다. 


JSON 은 JavaScript Object Notation 이라는 이름처럼 JavaScript 에서 유래하기는 했습니다만, 프로그래밍 언어에 독립적으로 기능하는 데이터 포맷입니다. 


JSON 이 무엇인가를 이해하는데 있어, 어떤 사람을 기술하는데 JSON 표기를 사용한 아래의 예제를 참고하시면 도움이 될 듯 합니다. 



[ 사람을 기술하는데 사용한 JSON 표기 예시 (JSON representation describing a person) ]


{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    },
    {
      "type": "mobile",
      "number": "123 456-7890"
    }
  ],
  "children": [],
  "spouse": null
}

 * source : https://en.wikipedia.org/wiki/JSON




개발하는 분이라면 위 예제의 JSON 데이터 포맷이 아주 익숙할 것입니다만, 개발 경험이 없는 분석가의 경우 매우 생소하게 느낄 수 있습니다.  R에서 사용하는 데이터 구조로 스칼라, 벡터, 행렬, 배열, 데이터프레임, 리스트 등이 있는데요, 특히 행렬, 데이터프레임의 경우 2차원의 행(row)과 열(column)로 데이터셋이 구성이 되어 있습니다. JSON과는 많이 다르기 때문에 처음 JSON을 본 분석가는 아마 '이거 뭐지?' 하고 당황할 것 같습니다 (제가 그랬어요. ^^;).


그나마 위의 SJON 데이터는 들여쓰기(indentation)이 이쁘게 되어 있어서 가독성이 좋은 것이구요, 개발자들이 건네주는 SJON 파일을 보면 아래처럼 들여쓰기 없이 옆으로 죽~ 이어져 있어서 가독성이 매우 떨어지다 보니 더 당황하게 되는거 같습니다. @@~


{"firstName":"John","lastName":"Smith","isAlive":true,"age":25,"address":{"streetAddress":"21 2nd Street","city":"New York","state":"NY","postalCode":"10021-3100"},"phoneNumbers":[{"type":"home","number":"212 555-1234"},{"type":"office","number":"646 555-4567"},{"type":"mobile","number":"123 456-7890"}],"children":[],"spouse":null} 



그래서 보통은 JSON parser 의 도움을 받아서 들여쓰기(indentation)을 해서 데이터 구조, 위계체계를 살펴보곤 합니다. 

아래는 http://www.jsonparseronline.com/ 이라는 사이트에 들어가서 JSON 데이터(왼쪽)를 parsing (오른쪽) 해본 것입니다. 


[ JSON parser (http://www.jsonparseronline.com) ]





위의 데이터를 자세히 보시면 "address""phoneNumbers"는 다른 항목과는 달리 하위에 nested data 들을 가지고 있습니다. 일종의 데이터 위계체계가 있는 셈인데요, 아래 예시처럼 어떤 사람에 대한 데이터를 JSON 데이터 포맷으로 구조화하는 방식이 합리적이고 효율적으로 보입니다. 다만, R이나 Python (numpy, pandas 모듈), SAS, SPSS 등의 분석 툴을 사용하는 분석가라면 생소할 수 있다는점을 빼면 말이지요. 





서론이 길었습니다. 


이번 포스팅에는 R의 jsonlite 패키지를 사용해서 


(1) JSON 포맷의 데이터를 R DataFrame 으로 변환

     (converting from JSON to R DataFrame)


(2) R DataFrame 을 JSON 포맷의 데이터로 변환

     (converting from R DataFrame to JSON)


하는 방법에 대해서 알아보겠습니다. 


jsonlite 패키지를 사용하면 JSON 데이터 포맷을 구조를 R이 알아서 잘 이해를 해서 R 분석가가 익숙한 R DataFrame으로 자동으로 바꾸어 주며, 그 반대로 R DataFrame을 JSON 데이터 포맷으로도 바꾸어주니 매우 편리한 패키지입니다. 



먼저, jsonlite 패키지와 (웹에서 JSON 데이터를 호출할 때 사용하는) httr 패키지를 설치하고 불러와 보겠습니다. 



install.packages("jsonlite")

library(jsonlite)


install.packages("httr")

library(httr)




 (1) JSON 포맷의 데이터를 R DataFrame 으로 변환 (converting from JSON to R DataFrame)

      : fromJSON() 함수


아래는 jsonlite 패키지의 fromJSON() 함수를 사용해서 "https://api.github.com/users/hadley/repos" 의 github API 로부터 JSON 데이터를 요청(request)해서 R DataFrame으로 변환해 본 예제입니다. 



[ (R로 불러오기 전의) JSON 원본 데이터 포맷 (https://api.github.com/users/hadley/repos) ]





자세히 보면 "owner" 는 nested data 로 login, id 등의 데이터를 가지고 있습니다. 






30개의 관측치와 69개의 변수를 가지고 있는 DataFrame으로 잘 변환이 되었음을 알 수 있습니다. 


[ R jsonlite package를 사용해서 JSON 데이터를 R DataFrame 으로 변환한 모습 ]



> # (1) converting JSON to R DataFrame

> df_repos <- fromJSON("https://api.github.com/users/hadley/repos")

> str(df_repos)

'data.frame': 30 obs. of  69 variables:

 $ id               : int  40423928 40544418 14984909 12241750 5154874 9324319 20228011 82348 888200 3116998 ...

 $ name             : chr  "15-state-of-the-union" "15-student-papers" "500lines" "adv-r" ...

 $ full_name        : chr  "hadley/15-state-of-the-union" "hadley/15-student-papers" "hadley/500lines" "hadley/adv-r" ...

 $ owner            :'data.frame': 30 obs. of  17 variables:

  ..$ login              : chr  "hadley" "hadley" "hadley" "hadley" ...

  ..$ id                 : int  4196 4196 4196 4196 4196 4196 4196 4196 4196 4196 ...

  ..$ avatar_url         : chr  "https://avatars0.githubusercontent.com/u/4196?v=3" "https://avatars0.githubusercontent.com/u/4196?v=3" "https://avatars0.githubusercontent.com/u/4196?v=3" "https://avatars0.githubusercontent.com/u/4196?v=3" ...

  ..$ gravatar_id        : chr  "" "" "" "" ...

  ..$ url                : chr  "https://api.github.com/users/hadley" "https://api.github.com/users/hadley" "https://api.github.com/users/hadley" "https://api.github.com/users/hadley" ...

  ..$ html_url           : chr  "https://github.com/hadley" "https://github.com/hadley" "https://github.com/hadley" "https://github.com/hadley" ...

  ..$ followers_url      : chr  "https://api.github.com/users/hadley/followers" "https://api.github.com/users/hadley/followers" "https://api.github.com/users/hadley/followers" "https://api.github.com/users/hadley/followers" ...

  ..$ following_url      : chr  "https://api.github.com/users/hadley/following{/other_user}" "https://api.github.com/users/hadley/following{/other_user}" "https://api.github.com/users/hadley/following{/other_user}" "https://api.github.com/users/hadley/following{/other_user}" ... 

 ...이하 생략 ...


> names(df_repos)

 [1] "id"                "name"              "full_name"         "owner"             "private"          

 [6] "html_url"          "description"       "fork"              "url"               "forks_url"        

[11] "keys_url"          "collaborators_url" "teams_url"         "hooks_url"         "issue_events_url" 

[16] "events_url"        "assignees_url"     "branches_url"      "tags_url"          "blobs_url"        

[21] "git_tags_url"      "git_refs_url"      "trees_url"         "statuses_url"      "languages_url"    

[26] "stargazers_url"    "contributors_url"  "subscribers_url"   "subscription_url"  "commits_url"      

[31] "git_commits_url"   "comments_url"      "issue_comment_url" "contents_url"      "compare_url"      

[36] "merges_url"        "archive_url"       "downloads_url"     "issues_url"        "pulls_url"        

[41] "milestones_url"    "notifications_url" "labels_url"        "releases_url"      "deployments_url"  

[46] "created_at"        "updated_at"        "pushed_at"         "git_url"           "ssh_url"          

[51] "clone_url"         "svn_url"           "homepage"          "size"              "stargazers_count" 

[56] "watchers_count"    "language"          "has_issues"        "has_projects"      "has_downloads"    

[61] "has_wiki"          "has_pages"         "forks_count"       "mirror_url"        "open_issues_count"

[66] "forks"             "open_issues"       "watchers"          "default_branch"   





nested data 를 가진 "owner" 에 딸린 데이터 항목으로 login, id 등 총 17개 데이터 항목이 있군요. 



> # nested DataFrame in owner

> names(df_repos$owner)

 [1] "login"               "id"                  "avatar_url"          "gravatar_id"        

 [5] "url"                 "html_url"            "followers_url"       "following_url"      

 [9] "gists_url"           "starred_url"         "subscriptions_url"   "organizations_url"  

[13] "repos_url"           "events_url"          "received_events_url" "type"               

[17] "site_admin"

 




nested data 를 가진 "owner" 변수에 대해 하위 변수까지 위계 구조를 반영해서 데이터를 indexing 해오는 방법은 아래를 참고하세요. 4가지 방법 모두 동일한 결과를 반환합니다. 



> # different indexing, the same results

> df_repos[1:3,]$owner$login

[1] "hadley" "hadley" "hadley"

> df_repos[1:3,"owner"]$login

[1] "hadley" "hadley" "hadley"

> df_repos$owner[1:3,"login"]

[1] "hadley" "hadley" "hadley"

> df_repos$owner[1:3,]$login

[1] "hadley" "hadley" "hadley"

 




 (2) R DataFrame 을 JSON 포맷의 데이터로 변환 (converting from R DataFrame to JSON)

       : toJSON() 함수


위에서 JSON 포맷 데이터를 웹에서 호출해서 "df_repos"라는 이름의 R DataFrame으로 변환을 했었는데요, 이번에는 jsonlite패키지의 toJSON() 함수를 사용해서 거꾸로 R DataFrame 을 원래의 JSON 데이터 포맷으로 변환해보겠습니다. 



> # (2) converting R DataFrame to JSON

> json_repos <- toJSON(df_repos)

 




R DataFrame 데이터를 JSON 데이터 포맷으로 변환한 결과를 cat() 함수, prettify() 함수, minify() 함수를 사용해서 차례대로 살펴보겠습니다. 


cat() 함수, minify() 함수는 R의 head() 함수와 기능이 비슷합니다. 

 


> cat(json_repos)

[{"id":40423928,"name":"15-state-of-the-union","full_name":"hadley/15-state-of-the-union","owner":{"login":"hadley","id":4196,"avatar_url":"https://avatars0.githubusercontent.com/u/4196?v=3","gravatar_id":"","url":"https://api.github.com/users/hadley","html_url":"https://github.com/hadley","followers_url":"https://api.github.com/users/hadley/followers","following_url":"https://api.github.com/users/hadley/following{/other_user}","gists_url":"https://api.github.com/users/hadley/gists{/gist_id}","starred_url":"https://api.github.com/users/hadley/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hadley/subscriptions","organizations_url":"https://api.github.com/users/hadley/orgs","repos_url":"https://api.github.com/users/hadley/repos","events_url":"https://api.github.com/users/hadley/events{/privacy}","received_events_url":"https://api.github.com/users/hadley/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hadley/15-s... <truncated>

 




# not including indentation, whitespace

minify(json_repos)

 






prettify() 함수는 들여쓰기, 공백을 사용해서 JSON 데이터를 파싱해서 표기해줌으로써 아래에 화면캡쳐해 놓은 것처럼 가독성이 매우 좋습니다.  nested data 를 가진 "owner" 데이터에 대해서 아래처럼 정확하게 원래의 JSON 데이터포맷으로 변환을 해놨습니다. jsonlite 패키지 참 똑똑하지요? ^^



# including indentation, whitespace

prettify(json_repos, indent = 4)




JSON 데이터 포맷 관련해서 serializeJSON, stream_in, stream_out 등 추가적인 기능이 필요한 분은 아래 [Reference]의 jsonlite package 매뉴얼을 참고하시기 바랍니다. 


[Reference] https://cran.r-project.org/web/packages/jsonlite/jsonlite.pdf


많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

R ggplot2 패키지로 box-plot 을 그렸을 때 조금 더 손을 보고 싶을 때가 있습니다.  


가령, 배경색을 흰색으로 바꾸어서 좀더 깔끔하게 보이게 하고 싶을 수 있습니다. 혹은 라벨 길이가 너무 길거가 요인 개수가 너무 많아서 가로의 X축이 모자라서 라벨명이 짤리는 상황이 발생했을 때 라벨을 45도나 90도 돌려 줌으로써 긴 라벨을 온전히 그래프에 다 제시를 해줄 수도 있겠지요. 아니면 아예 라벨을 가로축이 아니라 세로축으로 제시를 해주는 것도 방법이겠구요. 


이에 이번 포스팅에서는 아래의 3가지 소소한 팁을 공유하고자 합니다. 



(1) ggplot 배경을 흰색으로 바꾸기 


(2) ggplot x축 라벨 각도를 90도 돌리기


(3) ggplot x축과 y축 바꾸기 (x축 라벨을 세로 축으로 옮기기)



예제로 사용한 데이터는 MASS 패키지의 Cars93 데이터프레임에 들어있는 '차종(Type)'과 '고속도로연비(MPG.highway)' 입니다. 



> library(ggplot2)

> library(MASS)

> str(Cars93)

'data.frame': 93 obs. of  27 variables:

 $ Manufacturer      : Factor w/ 32 levels "Acura","Audi",..: 1 1 2 2 3 4 4 4 4 5 ...

 $ Model             : Factor w/ 93 levels "100","190E","240",..: 49 56 9 1 6 24 54 74 73 35 ...

 $ Type              : Factor w/ 6 levels "Compact","Large",..: 4 3 1 3 3 3 2 2 3 2 ...

 $ Min.Price         : num  12.9 29.2 25.9 30.8 23.7 14.2 19.9 22.6 26.3 33 ...

 $ Price             : num  15.9 33.9 29.1 37.7 30 15.7 20.8 23.7 26.3 34.7 ...

 $ Max.Price         : num  18.8 38.7 32.3 44.6 36.2 17.3 21.7 24.9 26.3 36.3 ...

 $ MPG.city          : int  25 18 20 19 22 22 19 16 19 16 ...

 $ MPG.highway       : int  31 25 26 26 30 31 28 25 27 25 ...

 $ AirBags           : Factor w/ 3 levels "Driver & Passenger",..: 3 1 2 1 2 2 2 2 2 2 ...

 $ DriveTrain        : Factor w/ 3 levels "4WD","Front",..: 2 2 2 2 3 2 2 3 2 2 ...

 $ Cylinders         : Factor w/ 6 levels "3","4","5","6",..: 2 4 4 4 2 2 4 4 4 5 ...

 $ EngineSize        : num  1.8 3.2 2.8 2.8 3.5 2.2 3.8 5.7 3.8 4.9 ...

 $ Horsepower        : int  140 200 172 172 208 110 170 180 170 200 ...

 $ RPM               : int  6300 5500 5500 5500 5700 5200 4800 4000 4800 4100 ...

 $ Rev.per.mile      : int  2890 2335 2280 2535 2545 2565 1570 1320 1690 1510 ...

 $ Man.trans.avail   : Factor w/ 2 levels "No","Yes": 2 2 2 2 2 1 1 1 1 1 ...

 $ Fuel.tank.capacity: num  13.2 18 16.9 21.1 21.1 16.4 18 23 18.8 18 ...

 $ Passengers        : int  5 5 5 6 4 6 6 6 5 6 ...

 $ Length            : int  177 195 180 193 186 189 200 216 198 206 ...

 $ Wheelbase         : int  102 115 102 106 109 105 111 116 108 114 ...

 $ Width             : int  68 71 67 70 69 69 74 78 73 73 ...

 $ Turn.circle       : int  37 38 37 37 39 41 42 45 41 43 ...

 $ Rear.seat.room    : num  26.5 30 28 31 27 28 30.5 30.5 26.5 35 ...

 $ Luggage.room      : int  11 15 14 17 13 16 17 21 14 18 ...

 $ Weight            : int  2705 3560 3375 3405 3640 2880 3470 4105 3495 3620 ...

 $ Origin            : Factor w/ 2 levels "USA","non-USA": 2 2 2 2 2 1 1 1 1 1 ...

 $ Make              : Factor w/ 93 levels "Acura Integra",..: 1 2 4 3 5 6 7 9 8 10 ...

 




  (1) ggplot 그래프 배경을 흰색으로 바꾸기 : theme_bw() 


기본 설정값을 사용해서 박스 그래프를 그려보면 아래와 같은 배경색으로 그래프가 나타납니다. 



# box-plot by default

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot()

 






ggplot 의 배경을 흰색으로 바꾸려면 theme_bw() 를 추가해주면 됩니다. 


 

# box-plot with white background

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot() +

  theme_bw() # white background 






 (2) ggplot x축 라벨 각도를 90도 돌리기 : theme(axis.text.x=element_text(angle=90, hjust=1))


이번에는 x축에 있는 '차종(Type)' 라벨을 90도 회전시켜서 세로로 세워보겠습니다.  

라벨이 길다거나 라벨 개수가 많아서 x축에 다 안들어가는 바람에 라벨이 짤리는 경우에 사용하면 유용합니다. 



# box-plot with axis label's angle of 90 degrees

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot() +

  theme_bw() +

  theme(axis.text.x=element_text(angle=90, hjust=1))




 




물론 라벨을 눕히는 각도를 'angle' 옵션을 사용해서 원하는 만큼 조절할 수도 있습니다.  

아래는 x축 라벨의 각도를 45도 회전시켜본 예제입니다. 



# box-plot with x axis label's angle of 45 degrees

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot() +

  theme_bw() +

  theme(axis.text.x=element_text(angle=45, hjust=1))


 





x축 라벨을 회전시킬 수 있으면 y축 라벨도 회전시킬 수 있겠지요? 

아래 예제는 왼쪽 세로의 y축 라벨을 45도 회전 시켜본 것입니다. 



# box-plot with y axis label's angle of 45 degrees

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot() +

  theme_bw() +

  theme(axis.text.y=element_text(angle=45, hjust=1))


 






 (3) ggplot x축과 y축의 위치를 바꾸기 : coord_flip()


아래는 coord_flip() 을 사용해서 x축의 '차종(Type)'을 세로축으로 옮기고, y축의 '고속도로연비(MPG.highway)'를 가로축으로 옮겨본 것입니다. 


x축의 라벨이 너무 많거나 길 경우에 이처럼 x축과 y축을 바꿔주면 라벨이 짤리는 경우 없이 세로로 길게 볼 수 있어서 유용합니다. 



# box-plot with the label at vertical axis

ggplot(Cars93, aes(x=Type, y=MPG.highway)) +

  geom_boxplot() +

  theme_bw() +

  coord_flip()






많은 도움이 되었기를 바랍니다. 


이번 포스팅이 도움이 되셨다면 아래의 '공감~'를 꾹 눌러주세요. ^^





저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

이번 포스팅에서는 외부의 엑셀(Excel) 파일로 존재하는 데이터를 RStudio 를 사용해서 R로 불러오기 하는 방법을 소개하겠습니다. 


저는 주로 DB에 직접 connect해서 데이터를 내리거나, 아니면 csv 나 txt 형태의 데이터를 R로 불러와서 분석에 사용하곤 합니다만(read.table() 함수 참고), 엑셀이 워낙 숫자 다루는데 강력하고 편리하다 보니 엑셀 데이터를 가져다가 R에서 사용해야 하는 경우도 있을 것입니다. 그리고 RStudio 에서 GUI로 Excel, SAS, SPSS, Stata 포맷을 데이터를 불러올 수 있는 기능이 있으니 클릭 몇 번으로 해결할 수 있으니 편리합니다. 


예제로 사용할 'cust_profile.xlsx'라는 이름의 엑셀 자료는 아래처럼 생겼습니다. 

(주의사항 1) 여러개의 sheet 중에서 'cust_profile' 라는 이름의 첫번재 sheet에 있는 데이터를 불러오고 싶습니다. 

(주의사항 2) 1~2번째 행(row)는 사용하지 않을 것이구요, 3번째 행부터 데이터를 불러오고 싶습니다.  1번째 열은 사용하지 않고 2번째 열부터 데이터를 불러오고 싶습니다. (정확히는 B3:E8 range)

(주의사항 3) 'gender' 열의 세번째 관측치 값이 결측값(missing value) 인데요, R로 불러왔을 때 결측값( 'NA')으로 잘 인식해서 불러오게 하고 싶습니다.  


[ 엑셀 예제 파일 ] 

* 실습 예제 엑셀 파일 첨부 ☞   cust_profile.xlsx



우선 R에서 "readex" package를 설치하고 로딩해보겠습니다. 


(1) {readxl} package 설치 및 로딩하기 



# installing and loading readxl package 

install.packages('readxl')

library(readxl)

 



엑셀 데이터를 R로 불러오는 방법에는 (a) R script를 이용하는 방법과,  (b) RStudio GUI 를 이용하는 방법의 2가지가 있습니다.  차례대로 소개하겠습니다. 


  (2) R script를 사용해서 엑셀 데이터 불러오기


엑셀 파일이 들어있는 경로(path), 사용할 sheet 이름, 불러올 데이터의 범위(range), 칼럼 이름(column name), 칼럼 유형(column type), cell 에 값이 비어있는 결측값에 사용할 문자열(비어 있으면 디폴트로 결측값으로 인식함)을 입력해주면 됩니다. 

> # importing excel file by using read_excel() function

> cust_profile <- read_excel("C:/Users/Administrator/Documents/cust_profile.xlsx", # path

+                            sheet = "cust_profile", # sheet name to read from

+                            range = "B3:E8", # cell range to read from

+                            col_names = TRUE, # TRUE to use the first row as column names

+                            col_types = "guess", # guess the types of columns

+                            na = "NA") # Character vector of strings to use for missing values

> str(cust_profile)

Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 5 obs. of  4 variables:

 $ ID    : chr  "c1" "c2" "c3" "c4" ...

 $ gender: chr  "F" "M" NA "M" ...

 $ age   : num  30 28 46 65 38

 $ name  : chr  "Kim" "Lee" "Park" "Moon" ...


> cust_profile

# A tibble: 5 × 4

     ID gender   age  name

  <chr>  <chr> <dbl> <chr>

1    c1      F    30   Kim

2    c2      M    28   Lee

3    c3   <NA>    46  Park

4    c4      M    65  Moon

5    c5      F    38  Choi






엑셀 데이터 크기가 커지면 행과 열의 범위(range)를 찾아서 정확히 입력하기가 번거로운 경우도 있을 텐데요, 아래처럼 처음의 2개의 행(row)은 무시하고(skip), 3번재 행부터 엑셀에서 데이터를 불러오라고 설정을 해주어도 결과는 똑같게 데이터를 불러올 수 있습니다. 


> # importing excel file using 'skip' option

> cust_profile_2 <- read_excel("C:/Users/Administrator/Documents/cust_profile.xlsx", # path

+                            sheet = "cust_profile", # sheet name to read from

+                            skip = 2, # Minimum number of rows to skip before reading anything

+                            col_names = TRUE, # TRUE to use the first row as column names

+                            col_types = "guess", # guess the types of columns

+                            na = "NA") # Character vector of strings to use for missing values

> cust_profile_2

# A tibble: 5 × 4

     ID gender   age  name

  <chr>  <chr> <dbl> <chr>

1    c1      F    30   Kim

2    c2      M    28   Lee

3    c3   <NA>    46  Park

4    c4      M    65  Moon

5    c5      F    38  Choi

 



다음으로 RStudio GUI 를 사용해서 클릭 몇 번으로 간단하게 엑셀 데이터 불러오는 방법을 소개하겠습니다. 


  (3) RStudio GUI 를 사용해서 엑셀 데이터 불러오기


(3-1) RStudio 우측 상단의 'Environments' 창에서 'Import Dataset' 메뉴를 선택한 후에, 'From Excel...' 하위 메뉴를 선택해보세요. 



(3-2) RStudio 의 'Import Excel Data' 창에서 왼쪽 하단의 'Import Options:' 화면에서 옵션을 입력하여 엑셀 데이터 불러오기



'Import Options:' 화면이 잘 안보일 것 같아서 아래에 확대해서 R Script 와 비교할 수 있도록 번호를 같이 표기해보았습니다. 


많은 도움 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~♡'를 꾸욱 눌러주세요. ^^



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend

지난번 포스팅에서는 

- RStudio 에 내장되어 있는 .Rmd 소스파일을 가지고 HTML 문서를 만들기와 

- servr 패키지의 rmdv2() 함수를 사용해서 .Rmd 소스파일을 렌더링해서 로컬 웹 서버(포트 4321)로 올리는 방법을 알아보았습니다. 


이번 포스팅부터는 .Rmd 소스파일 안으로 들어가서 하나씩 더 자세히 알아보도록 하겠습니다. 

.Rmd 소스파일은 (1) YAML Header, (2) Code Chunk, (3) Markdown text 로 구성됩니다.  이중에서 이번 포스팅에서는 먼저 (1) YAML Header부터 시작해보겠습니다. 


[ .Rmd source file 구성 ]


YAML Header에는 title, author, date, output 등의 메타정보를 지정합니다.  특히, output 필드에는  rmarkdown 문서의 포맷으로서 HTML, pdf, MS word, Beamer Presentation 등을 지정할 수가 있는데요, 이번 포스팅에서는 HTML output format 에 대해서 소개하겠습니다. 




YAML Header 작성에 지켜야하는 문법이 몇가지 있습니다. 


(1) YAML Header는 '---' 로 시작해서 안에 문서에 대한 메타정보를 작성하고 '---'로 끝을 냅니다. 

(2) 상하관계는 space bar 로 들여쓰기(보통 2칸)를 해서 구분합니다. 

(3) 각 필드는 colon (':') 을 이용해서 key : value 형태로 입력합니다. (예 title: "My_First_R_MarkDown")

(4) value 는 큰 따옴표(" ")나 작은 따옴표(' ')를 사용하거나 혹은 그냥 아무런 표시 없이 입력합니다.

(5) key : value 쌍에서 value가 2개 이상일 경우 (5-1) 대괄호([ ]) 안에 value를 나열하고 comma(,) 로 구분하거나, 또는 (5-2) 한 줄에 한개의 value를 hyphen ('-')을 사용해서 나열합니다. 

---

Seoul: [Jonro, Gangnam, Ganak]

Sungnam:

  - Bungdang

  - Suwon

  - Anyang

---  




이제 YAML Header 의 output: html_document 를 사용해서 HTML 문서의 옵션을 설정하는 방법을 소개하겠습니다.  그리 어렵지 않습니다. 


 (1) 목차 만들기 (Table of Contents) > toc: true


toc: true 옵션을 설정해주면 목차를 자동으로 생성해줍니다. 

toc_depth: 2 옵션을 설정해주면 목차를 자동 생성할 때 목차의 깊이(depth)를 어디까지 할지 지정해줄 수 있습니다. '2'로 하면 '##', '3'으로 하면 '###' 수준까지 목차를 알아서 만들어줍니다. 

---

title: "My_First_R_MarkDown"

author: "RFriend"

date: '2017.05.02'

output

  html_document

    toc: true

    toc_depth: 2

--- 



 (2) 문서 단락 번호 자동부여 하기 (section numbering) > number_sections: true

문서의 단락('#', '##', '###' 등으로 구분)에 따라서 자동으로 문서 번호를 부여하기 위해서는 number_sections: true 옵션을 지정해주면 됩니다.  문서 작성할 때 알아서 스마트하게 번호를 따주면 실수할 염려도 없고 신경쓸 일도 없어서 아주 유용하겠지요?!

---

title: "My_First_R_MarkDown"

author: "RFriend"

date: '2017.05.02'

output: 

  html_document: 

    toc: true

    toc_depth: 2

    number_sections: true

--- 



  (3) 유동적인 목차 만들기 (Floating TOC) > toc_float: true

만약 문서가 길다면 커서로 HTML 문서를 scrolling 하게 되면 상단에 위치한 목차(Table of Contents)가 시야에서 사라지게 됩니다.  그래서 목차를 보려면 다시 scroll up 해야 하는 불편이 있습니다.  이럴때 유용하게 사용할 수 있는 옵션이 toc_float: true 옵션입니다.  scroll 하면 목차가 현재 화면으로 따라다니면서 항상 목차를 볼 수 있도록, 그래서 목차의 특정 하위 목차를 선택하면 바로 그 목차 부분으로 직행할 수 있는 인터페이스를 제공해줍니다. 

---

title: "My_First_R_MarkDown"

author: "RFriend"

date: '2017.05.02'

output: 

  html_document: 

    toc: true

    toc_depth: 2

    toc_float: true

    number_sections: true

---


toc_float: 옵션의 디폴트 설정은 collapsed: true (목차에 최상위 수준만 나타남), smooth_scroll: true (특정 목차를 마우스로 선택했을 때 웹 화면이 부드럽게 움직이면서 해당 목차로 이동) 인데요, 이걸 바꾸고 싶다면 아래처럼 설정을 바꾸면 됩니다. 상하 위계를 고려해서 들여쓰기(indentation) 주의해서 하시기 바랍니다. 

---

title: "My_First_R_MarkDown"

output:

  html_document:

    toc: true

    toc_float:

      collapsed: false

      smooth_scroll: false

---



  (4) 탭으로 구분하여 부분별 내용 만들기 (Tabbed Sections) > {.tabset} class


{.tabset} class attribute 을 사용하면 HTML 본문 내용을 탭(Tab) 으로 구분하고, 탭을 선택하면 그 부분의 내용이 나타나도록 할 수도 있습니다. 가령, 국가나 지역별로 매출, 수익 등을 표로 작성한 후에 국가나 지역을 탭(tba)으로 구분해 주면 원하는 국가나 지역 탭을 선택해서 볼 수 있어 편리할 것입니다. 

---

title: "My_First_R_MarkDown"

author: "RFriend"

date: '2017.05.02'

output: 

  html_document: 

    toc: true

    toc_depth: 2

    toc_float:

      collapsed: true

      smooth_scroll: true

    number_sections: true

---


## Tab by country {.tabset}

### Korea

this tab is for Korea


### China

this tab is for Chian


### Japan

this tab is for Japan




  (5) HTML 문서 모습과 스타일 (Appearance and Style) > theme: cerulean

HTML 문서의 전체적인 모습과 스타일을 지정해줄 수 있는 theme 옵션에는 "default",  "cerulean", "journal", "flatly", "readable", "spacelab", "united", "cosmo", "lumen", "paper", "sandstone", "simplex", "yeti" 등이 있습니다.  

---

title: "My_First_R_MarkDown"

author: "RFriend"

date: '2017.05.02'

output: 

  html_document: 

    toc: true

    toc_float: true

    number_sections: true

    theme: journal

---


다양한 theme 중에서 아래 화면 캡쳐 예시를 참고해서 원하는 취향의 theme을 선택해서 지정해주면 됩니다. 


[ 다양한 HTML 문서 스타일 theme ]






많은 도움 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~♡'를 꾸욱 눌러주세요. ^^







저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by R Friend R_Friend


티스토리 툴바