Skip to content

Commit

Permalink
Script & Data for KDI 20161229 Workshopo
Browse files Browse the repository at this point in the history
  • Loading branch information
ChangdongOh committed Dec 29, 2016
0 parents commit ed24d76
Show file tree
Hide file tree
Showing 19 changed files with 98,269 additions and 0 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3,140 changes: 3,140 additions & 0 deletions Data/eng/Health Management Industry/merged.txt

Large diffs are not rendered by default.

200 changes: 200 additions & 0 deletions Data/kor/minjoo2016.csv

Large diffs are not rendered by default.

94,457 changes: 94,457 additions & 0 deletions Result/healthmgmt.graphml

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions beginnersR.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
title: "biginnersR"
output: html_document
---

R은 근래 데이터 분석 분야에서 널리 사용되고 있는 통계 분석 솔루션이자 프로그래밍 언어입니다. 이번 워크샵은 R을 사용해서 텍스트 데이터를 처리하고, 이를 바탕으로 단어와 단어 사이의 공출현 빈도를 측정한 다음 이를 의미연결망 네트워크로 만드는 것까지 진행할 예정입니다. 시간이 제한되어 있는 관계로, R의 기초만 간단하게 다룬 다음에 바로 의미연결망 분석에 필요한 단계로 넘어가도록 하겠습니다.

이번 강의에 사용되는 프로그램은 RStudio로, 프로그래밍 언어 R을 유저가 좀 더 사용하기 편하고 작업 효율을 올려줄 수 있도록 만들어진 Integrated Development Environment(IDE)입니다. 여러분이 보고 계신 글이 쓰여져 있는 공간은 '에디터'라고 불리며, 코드를 작성하고 수정하며 한 눈에 볼 수 있게 만들어진 공간입니다. 그 아래에 있는 것은 '콘솔'인데, 실행한 코드와 함께 그 결과물이 출력되는 공간입니다. 에디터에 입력한 코드를 드래그해서 선택한 다음, Ctrl+Enter/R 을 해주면 에디터의 코드가 그대로 콘솔에서 실행되는 것을 알 수 있습니다. 예를 들어 a라는 변수에 "hello world"라는 문자열을 할당하고, 이를 콘솔에 출력하는 코드를 짜서 실행해 봅시다.

a="hello world"
a
print(a)

이를 실행하면 콘솔 화면에 코드가 그대로 실행되고, "hello world"라는 문자열이 출력된 것을 알 수 있습니다. 변수로 할당된 데이터의 경우 굳이 print 명령어를 입력하지 않아도 그대로 출력되는 것을 알 수 있습니다.

오른쪽을 보도록 합시다. Environment라는 패널이 있고, 그 아래의 values라는 항목에 변수 a와 그 a에 할당된 "hello world"라는 문자열을 확인할 수 있습니다. 이는 현재 프로그램 내에 할당된 변수와 함수 등을 유저가 쉽게 찾아보고 살펴볼 수 있도록 해 주는 패널입니다.

그 아래를 살펴보면 Files라는 패널이 있습니다. 말 그대로 파일을 다룰 수 있는 패널인데, 작업 디렉토리인 kdiworkshop2016과 그 하위 폴더인 Script, Result, Data가 보입니다. 각각을 클릭해서 안에 있는 파일을 살펴보고, 스크립트의 경우 에디터로 그대로 띄워서 살펴볼 수도 있습니다.

다만 이번 워크샵에서는 RMarkdown이라는 형태의 문서 작성 툴을 활용해 진행하려 합니다. RMD를 사용하면 굳이 콘솔 없이도 직접 코드를 작성하고 바로바로 그 실행 결과를 확인할 수 있습니다. RMD에서 코드를 입력하고 실행하기 위해서는 Chunk를 만들어야 합니다. 키보드의 esc키 아래에 있는 `를 세 번 입력하고 뒤에 {r}을 붙이면 chunk가 생기며 이를 닫아줄 때에는 다시 세 번 입력하면 됩니다. 아니면 에디터 위쪽 상단의 Insert를 눌러서 R을 선택해도 됩니다.

예를 들어서 다음 예시를 통해 방금 실행해 본 변수 할당과 출력을 실험해 보도록 합시다. chunk에 있는 코드를 실행하려면 오른쪽의 녹색 화살표를 누르거나, Ctrl+Alt+C를 누르면 됩니다.

```{r}
a="hello world"
a
print(a)
```

chunk의 아래에 결과값 출력을 위한 공간이 생기고, 여기에 결과값이 그대로 출력되는 것을 알 수 있습니다. RMD를 사용하면 굳이 콘솔이 필요하지 않으므로, 콘솔 창의 상단부를 드래그해서 내린 다음 에디터만 가지고 워크샵을 진행하도록 하겠습니다. 다음은 R의 데이터 타입에 대해서 설명해 드리도록 하겠습니다.


Scalar & Vector

위에서 a에 hello world라는 문자열을 할당했던 것처럼, R에서는 숫자나 문자열, 불리언(True/False)등의 데이터를 변수에 할당할 수 있습니다.

```{r}
a=5
b="I like R"
c=TRUE
a
b
c
```

문자열 데이터의 경우 반드시 작은 따옴표나 큰 따옴표를 붙여야 합니다. 변수에 이러한 데이터를 여러 개 할당할 때에는 '벡터'라는 가장 기초적인 데이터 타입을 사용할 수 있습니다. 벡터 형식으로 변수를 할당할 때에는 c()라는 형식으로 묶어 줘야 합니다. 이렇게 벡터 안에 들어간 데이터들은 대괄호 안에 숫자를 붙임으로써 호출할 수 있습니다. 하나만을 호출할 경우엔 숫자를 넣어주고, 특정한 범위로 불러올 때에는 콜론을 사용해 범위를 설정합니다. 한 변수에 저장된 여러 데이터 가운데 특정 요소만 빼고 불러오려 할 경우 그 순서의 숫자에 -를 붙이며, 범위를 설정할 경우에도 가능합니다.

```{r}
a <- c(1,2,5.3,6,-2,4) # numeric vector
b <- c("one","two","three") # character vector
c <- c(TRUE,TRUE,TRUE,FALSE,TRUE,FALSE) #logical vector
a
b
c
a[1]
b[1:3]
c[-1:-3]
```

이러한 단순한 형태의 데이터가 아니라 설문지 데이터와 같은 구조화된 자료를 다루기 위한 데이터 타입으로는 데이터 프레임이 있습니다.

```{r}
d <- c(1,2,3,4)
e <- c("red", "white", "red", NA)
f <- c(TRUE,TRUE,TRUE,FALSE)
df <- data.frame(d,e,f)
print(df)
```

4*3 행렬 형식의 표가 만들어지며, 각각의 행과 열 안에는 다른 타입의 데이터를 포함시킬 수 있습니다.

```{r}
names(df)=c("numeric","character","bool")
df$numeric
df[1]
df[[1]]
df[1,]
df[1,3]
df[1:2]
```

행마다 이름을 지정해 주려면 names라는 함수를 사용하면 되며, 이렇게 이름을 지정하면 데이터 프레임 변수 뒤에 $를 붙이고 행 이름을 지정해서 그대로 불러올 수 있습니다. 대괄호 안에 여러 가지 숫자를 넣어서 특정 셀의 데이터를 불러오거나 행, 열, 혹은 범위를 지정해서 불러오는 것 역시 가능합니다. 다만 행 이름을 지정해서 불러오거나 대괄호를 두 번 쓰는 경우(벡터로 변환)를 제외하면 모두 데이터 프레임 형식을 유지하고 있습니다.

데이터 프레임은 장점이 많고 다루기 편리하지면 n*m 표의 개별 셀에는 하나의 데이터만을 집어넣을 수 있으며, 결과적으로 길이가 다른 데이터를 다루기에는 무리가 있습니다. 그래서 온갖 종류의 데이터를 다 넣거나 길이가 애매한 경우 리스트를 씁니다.

```{r}
w <- list(name="Kim", mynumbers=a, mymatrix=df, bool=c)
w
w$name
w[[1]]
w[1]
w[[3]][1:3,2:3]
```

RMD의 결과창에는 잘려서 나오지만, 실제로 4가지 다른 타입의 데이터(문자열 스칼라, 숫자 벡터, 데이터 프레임, 불리언 벡터)가 각각 잘 저장되었음을 확인할 수 있습니다. 이를 호출할 때에는 데이터 프레임과 같은 방식을 사용하면 됩니다. 마지막 예시의 경우 변수 df가 저장된 세 번째 구간을 불러오고, df에 대해서 대괄호를 사용해 그 안의 데이터를 불러온 것입니다.

마지막으로 반복문을 살펴보아야 합니다. 반복문은 말 그대로 반복적인 명령어를 수행하게 해 주는 것인데요, R의 반복문은 다음과 같은 구조를 갖고 있습니다.

```{r}
for(i in 1:10){
print(i)
}
a <- c("one","two","three")
for(i in b){
print(i)
}
```

(i in 1:10)의 경우 반복문을 수행할 때 활용하는 데이터로, 일정한 길이를 가진 변수를 뒤 쪽에 입력하면 그 변수의 값이 하나씩 순서대로 i라는 변수에 할당되어 반복문 속에서 변수로 작동하게 됩니다. 위의 예제의 경우 1:10이라는 숫자 벡터와 "one","two","three"라는 문자열 벡터가 for문 속에서 i변수에 할당되어 출력된 것을 알 수 있습니다. 그 다음으로는 조건문을 살펴보겠습니다.


```{r}
if(a[1]=="two"){
print("TRUE")
} else{
print("FALSE")
}
```

조건문은 괄호 안에 있는 문장이 참일 경우에 중괄호 안의 명령어를 실행하는 형식입니다. 위의 예시에서는 a[1]에 있는 데이터는 "two"가 아니라 "one"이기 때문에 a[1]=="two"라는 조건은 거짓이며, 따라서 if문 뒤의 중괄호에 있는 "TRUE"가 아니라 그것이 틀릴 경우에 실행되는 else 뒤의 괄호가 출력되었습니다.

이제 바로 데이터 분석 단계로 넘어가도록 하겠습니다. 오른쪽 파일 패널에서 preprocess.Rmd를 열어주세요.
107 changes: 107 additions & 0 deletions korean.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: "korean"
output: html_document
---

앞서 살펴본 데이터 전처리와 네트워크 분석 코드는 모두 영어를 대상으로 하고 있었습니다. R은 물론 한글 문자열 처리 역시 완벽하게 지원합니다. 여기서는 데이터가 한국어일 경우화데이터 전처리와 공출현 빈도 행렬 생성, 그리고 네트워크 데이터로의 전환을 어떻게 하면 되는지 간단하게 다룹니다.

여기에서 예제로 사용할 데이터는 제가 수집했던 민주당의 2016년 논평 200여 개입니다. 데이터 크롤링 단계에서부터 한글을 제외한 숫자, 영문자, 특수문자 등은 모두 제거되어 있는 상태입니다.

먼저 데이터를 읽어와야 합니다. 제 데이터는 csv 파일 형식으로 1열에는 논평의 url, 2열에는 발표된 날짜, 3열에 논평 본문을 저장해 놓았습니다. R에서 데이터 프레임 형식으로 이 파일을 읽어온 다음, 3열에 있는 본문 텍스트만을 분석 대상으로 사용하면 됩니다. 먼저 파일을 읽어오도록 하겠습니다. csv 파일을 저장할 때에는 크게 문제가 안 되나, 읽어올 때에는 readr 패키지를 불러와서 read_csv(.이 아니라 _입니다) 함수를 사용하는 것이 좋습니다.

```{r}
library(readr)
data <- read_csv("~/Git/kdiworkshop2016/Data/kor/minjoo2016.csv", col_names = FALSE)
data[1,]
```

data 변수에 데이터를 불러왔습니다. 이제 이 데이터 프레임의 3열에 있는 자료만을 변수에 할당합니다.

```{r}
data<-data[[3]]
data[1]
```

총 200개의 논평 데이터가 모였습니다. 이 논평 데이터를 활용해서 아까와 같은 단어의 공출현 빈도 행렬을 만들 것입니다. 그런데 여기에서 한 가지 문제가 생깁니다. 영어의 경우 tm 패키지를 사용해서 같은 의미를 가진 단어들을 골라냈지만, 한글의 경우에는 어떻게 그러한 작업을 수행할 수 있을까요. 여기에서는 KoNLP 패키지를 사용하면 됩니다.

```{r}
library(KoNLP)
t="이재정 원내대변인 오전 현안 추가 서면 브리핑 의원총회 결과 서면 브리핑 박근혜 대통령 탄핵소추안 발의 일정과 담길 내용에 관한 논의들이 있었다"
extractNoun(t)
SimplePos22(t)
SimplePos09(t)
```


KoNLP 패키지는 텍스트 데이터를 받아서 형태소 단위로 분리해 주는 유용한 함수를 제공합니다. 명사만을 추출하는 extractNoun, 형용사나 부사 등 다른 문장 성분들까지 추출하고 형태소 단위로 분리해 주는 SimplePos09,22 함수가 있습니다. 보통 텍스트의 의미를 파악할 때에는 명사만을 추출해서 사용하는 경우가 대부분입니다. 동사나 형용사, 부사의 경우 부분적으로 의미가 있는 경우도 있지만 한국어 서술어는 대부분 '명사 + 하다'와 같은 형식으로 결합되어 있기 때문입니다.

그런데 여기에서 한 가지 문제가 있습니다. 이는 고유명사 처리에 관한 것인데, 예를 들어서 다음과 같은 텍스트를 명사 추출 함수로 처리해 보겠습니다.

```{r}
w='선거관리위원회.'
extractNoun(w)
```

고유명사에 해당하는 선거관리위원회라는 단어가 분리된 단어로 취급되어 나뉘어진 것을 알 수 있습니다. 이러한 상황을 방지하기 위해서는 KoNLP 패키지에 내장된 말뭉치와 유저 사전을 만들어야 합니다. 내장 사전과 말뭉치 데이터를 불러오기 위해선 다음과 같은 함수를 사용해야 합니다.

```{r}
useNIADic()
term=c("선거관리위원회")
tag=rep("ncn",times=length(term))
user_dic=data.frame(term=term, tag=tag)
buildDictionary(ext_dic = c('sejong','insighter', 'woorimalsam'), user_dic=user_dic,replace_usr_dic = T)
extractNoun(w)
```

유저 사전을 통해 '선거관리위원회'라는 단어를 고유명사로 등록하자 명사를 추출해도 단어가 나뉘어지지 않고 그대로 남겨지는 것을 알 수 있습니다. 단어를 추가하려 할 경우 유저 사전의 term이라는 변수에 할당하는 문자열 벡터에 새로운 단어들을 추가하면 됩니다. 그러면 이러한 KoNLP의 함수를 사용해서 본격적으로 co-occurence matrix를 만들어 보도록 하겠습니다. 영어 자료를 처리할 때에는 stemDocument라는 함수를 사용했다면, 여기서는 extractNoun함수를 사용하게 됩니다. extractNoun 함수를 활용해

```{r}
ko.words <- function(doc){
token=""
library(stringr)
splited=str_split(doc, " ")[[1]]
for(i in splited){
extracted=extractNoun(paste0(i,"."))
token=c(token, extracted)
}
token[nchar(token)>=1]
}
```


```{r}
t=data[1:100]
cps=Corpus(VectorSource(t))
stopwords=c("")
tdm <- TermDocumentMatrix(cps,
control=list(tokenize=ko.words,
removePunctuation=T,
removeNumbers=T,
#weighting=weightTf,
#stopwords=stopwords,
wordLengths=c(2, 15)))
```

이렇게 co-occurence matrix를 만든 다음의 과정은 이전의 네트워크 만들기 과정과 완전히 동일합니다.

```{r}
mat<-as.matrix(tdm)
mat2<-mat %*% t(mat)
```

term-document matrix를 adjacency matrix로 바꿔주고,

```{r}
library(igraph)
gra <- graph.adjacency(mat2, weighted=TRUE, mode="undirected")
gra<-simplify(gra)
```

igraph 패키지를 활용해 그래프 파일 형식으로 바꿔주시면 됩니다.

```{r}
write.graph(gra, 'Result/partyannouncement.graphml', format="graphml")
```
Loading

0 comments on commit ed24d76

Please sign in to comment.