본문 바로가기
R

[R.아르] 문장에서 명사 추출하기

by LightBlogger 2016. 11. 22.

자주 쓰이는 명사만 보아도 대략 글의 요지를 알 수 있다고 한다.


한국 저작권협회에서 제공하는 이상의 <날개> 에서 명사를 뽑아보자.


(주소: https://gongu.copyright.or.kr/gongu/wrt/wrt/view.do?wrtSn=9000973&menuNo=200030)


'박제가 되어 버린 천재'를 아시오? 나는 유쾌하오. 이런 때 연애까지가 유쾌하오.

육신이 흐느적흐느적하도록 피로했을 때만 정신이 은화처럼 맑소. 니코틴이 내 횟배 앓는 뱃속으로 스미면 머릿속에 으레 백지가 준비되는 법이오. 그 위에다 나는 위트와 파라독스를 바둑 포석처럼 늘어놓소. 가증할 상식의 병이오.

나는 또 여인과 생활을 설계하오. 연애기법에마저 서먹서먹해진 지성의 극치를 흘깃 좀 들여다본 일이 있는, 말하자면 일종의 정신분일자말이오. 이런 여인의 반-그것은 온갖 것의 반이오.-만 을 영수하는 생활을 설계한다는 말이오. 그런 생활 속에 한 발만 들여놓고 흡사 두 개의 태양처럼 마주 쳐다보면서 낄낄거리는 것이오. 나는 아마 어지간히 인생의 제행이 싱거워서 견딜 수가 없게 끔 되고 그만둔 모양이오. 굿바이.

굿바이. 그대는 이따금 그대가 제일 싫어하는 음식을 탐식하는 아이로니를 실천해 보는 것도 놓을 것 같소. 위트와 파라독스와…….

그대 자신을 위조하는 것도 할 만한 일이오. 그대의 작품은 한번도 본 일이 없는 기성품에 의하여 차라리 경편하고 고매하리다.

19세기는 될 수 있거든 봉쇄하여 버리오. 도스토예프스키 정신이란 자칫하면 낭비일 것 같소. 위 고를 불란서의 빵 한 조각이라고는 누가 그랬는지 지언인 듯싶소. 그러나 인생 혹은 그 모형에 있어서 '디테일' 때문에 속는다거나 해서야 되겠소?

화를 보지 마오. 부디 그대께 고하는 것이니……

"테이프가 끊어지면 피가 나오. 상채기도 머지 않아 완치될 줄 믿소. 굿바이." 감정은 어떤 '포우즈'. (그 '포우즈'의 원소만을 지적하는 것이 아닌지 나도 모르겠소.) 그 포우즈가 부동자세에까지 고도화할 때 감정은 딱 공급을 정지합네다.

나는 내 비범한 발육을 회고하여 세상을 보는 안목을 규정하였소.

여왕봉과 미망인-세상의 하고 많은 여인이 본질적으로 이미 미망인이 아닌 이가 있으리까? 아니, 여인의 전부가 그 일상에 있어서 개개'미망인'이라는 내 논리가 뜻밖에도 여성에 대한 모험이 되오? 굿바이.


위 텍스트를 wing.txt 로 저장하고 시작한다. 이때 인코딩을 UTF-8 으로 하는 편이 좋다.


텍스트를 읽어들일 때는 readLines() 함수를 사용한다.



에러메시지가 나올 수 있지만 대부분 텍스트는 별 이상 없이 저장된다.



명사를 추출할 때는 KoNLP 라이브러리의 extractNoun() 함수를 사용한다. (KoNLP: Korean Natural Language Package)


첫 번째 문장의 명사를 추출해 보자.



'박제가' 나 '하오' 등은 사실 명사가 아니므로 이는 KoNLP가 잘못 파악한 것이다.


100% 완벽을 기대하기는 어렵다. 원한다면 나중에 추출 결과에서 제거하여도 되고,


문서 전체를 놓고 볼 때 큰 영향이 없을 것 같다면 그대로 진행하는 것도 방법이다.



참고로 KoNLP가 어떻게 명사를 파악했는지를 알고 싶다면, 단어를 크게 9개의 갈래로 분석하는 SimplePos09() 함수를 사용한다.



paste()나 cat()은 출력 방식을 위해 덧붙인 것이고, SimplePos09() 함수가 문장을 어떻게 분석했는지 볼 수 있다. 


표시되는 알파벳은 각각 다음에 대응한다.


S: 기호


F: 외국어


N: 체언(명사, 대명사, 수사)


P: 용언(동사, 형용사)


M: 수식언(관형사, 부사)


I: 독립언(감탄사)


J: 관계언(조사)


E: 어미


X: 접사


다시 돌아가서, 두 번째 문장의 명사를 추출하면



위와 같이 나온다. 


역시 옳지 않은 부분들이 간혹 보이지만 대체로 양호하다.



이제 명사들을 출현빈도에 따라 정리해 보자. 이렇게 정리된 문서를 Term Document Matrix 라고 하며,


작업을 위해서는 tm 패키지의 TermDocumentMatrix() 함수가 사용된다.



야심차게 적용하면! 에러 메시지가 난다.


이는 TermDocumentMatrix() 함수가 인자로 말뭉치(Corpus)라는 특별한 형태만 받기 때문이다.


그러므로 text를 일단 Corpus 형태로 바꾸어 주자. Corpus(VectorSource())라는 함수를 사용한다.



그 후에 TermDocumentMatrix() 함수를 사용하면



대략 무언가 나오기는 한 것 같은데 조금 이상하다.


일단 문장이 명사 단위로 끊어져 있지 않다.


이는 Term Document Matrix 를 만들 때 명사만 추출하여 만들라는 옵션을 주지 않았기 때문이다.



TermDocumentMatrix() 함수의 [control=list()] 라는 벡터를 만들어 [tokenize=] 옵션을 주면 문장을 원하는 단위로 잘라 준다.


다만 이때 조금 까다로운 것이 extractNoun()은 인자로 character 벡터만을 받는다.


그러므로 doc를 ①캐릭터 벡터로 전환 후 ②extractNoun()을 적용하는 커스텀 함수를 하나 제작하자.



이제 다음과 같이 TermDocumentMatrix()를 적용하면



각 명사들이 몇 번째 문장에서 등장하는지를 표로 나타내 준다.


우리에게 필요한 것은 실제로 몇 번째 문장에 등장했는지보다, 총 몇 번 나왔는지이므로


tdm에서 표 부분만 추출한 뒤, rowSums() 함수를 통해 각 행의 합계를 구해 보자.



이상의 과정을 <날개> 전문으로 시행한 결과는 다음과 같다.



처음에 나오는 useSejongDic() 은 레퍼런스가 될 사전으로 SystemDic대신 SejongDic을 사용하겠다는 의미다.


또한 options(mc.cores=1) 은 연산시 멀티코어를 사용하지 않겠다는 선언이다. 


멀티코어 사용시 가끔 오류가 나는 경우가 있다고 한다.















반응형

댓글