[Python mini projects] Python을 활용한 텍스트 속 유의미한 통계 산출하기 -1



Category: Python programming / Data science


예전에는 수많은 책, 잡지, 신문, 논문 등의 텍스트로 된 자료로부터 정보를 추출하고 분석하기 위해서는 일일히 자료를 모아 읽고, 단어를 세야 했을 것이다. 그렇지만 오늘날에는 그 작업이 훨씬 용이해졌다. 수많은 텍스트 형식의 자료들을 텍스트 파일 형태로 접할 수 있으며, 각기 다른 형태, 다른 기호들, 다른 표현 방식을 사용하는 문서들을 깔끔하게 Parse할 수 있는 기술이 발전했기 때문이다. 

이번에는 책, 논문, 등 수많은 텍스트가 포함되어있는 문서를 단어 단위로 쪼개고, 분석하여 유의미한 통계를 산출하는 미니 프로젝트를 진행해 보았다. (사실 이미 이와 유사한 프로젝트는 구글 검색만 해 보아도 충분히 많이 있을거라 생각된다) 모든 텍스트 (글)은 저마다의 주제와 내용을 담고 있다. 그렇다면 주제와 내용은 어떻게 알 수 있을까? 우리가 책을 읽지 않고 주제와 내용을 어떻게 유추할 수 있을까? 모든 책은 글로 구성되어있으며 글은 단락, 문장으로, 그리고 문장은 결국 최소한의 의미를 담은 단어들로 구성된다. 그렇다면 아마 높은 확률로 각기 다른 주제의 책마다 주제와 연관된 단어를 많이 등장시킬 것이다. 만일 한두 페이지가 아닌, 수많은 단어를  담고 있는 긴 텍스트를 분석해서 단어의 통계를 낸다면 그 책의 주제와 연관된 단어들의 빈도가 유의미하게 높음과 동시에, 유사한 주제를 가진 서적의 경우 출현빈도가 높은 단어사이에 연관성이 있지 않을까? 그렇다면 우리는 이 분석을 통해 책들(혹은 논문, 기사, 무엇이 되었건) 사이의 네트워크를 만들 수 있을 것이다. 이와 동시에 분야에 상관없이 많이 쓰이는 단어가 무엇인지도 알 수 있지 않을까? 


기본적인 아이디어는 다음과 같다:


 파이썬을 통해 매우 긴 (책 혹은 적어도 논문 분량 정도는 되는) 텍스트 파일을 통째로 불러와 단어를 구성하는 자모 이외의 특수문자를 모두 제거하며, 대소문자를 통일이키기 위해 모든 단어를 소문자로 통일시키는 작업을 통해 문서를 다듬는 (parse)작업을 진행한다. 그 다음 Counter 모듈을 사용하여 단어의 빈도를 센다. 이 통계를 다듬어 그래프를 그리고, 각기 다른 분야의 여러 텍스트에 대해 같은 과정은 진행해 데이터프레임으로 만든 후 연관성이 높은 단어를 연결점으로 한 네트워크를 만들어본다. 



***
1. 알고리즘 설계 및 통계 만들기 


이번 포스트에서는 텍스트 문서를 parse 하고 분석하는것 까지의 과정에 대해 다뤄보도록 하겠다.

이 부분에서는 주로 코딩을 하는 과정에 대해 다루며 아래의 다음 파트에서 코드를 이용해 문서를 분석하는 과정을 다룰 것이다. 파이썬이나 코딩에 흥미가 도저히 없다면 다음 파트로 과감히 넘어가도 좋다. 



- 텍스트 불러오고 통계 내기 

가장 먼저 문서를 불러오고 특수문자를 제거해보자. (문서로는 원래 가지고 있던 Data science에 관련된 pdf파일을 사용했다.) 이후 특수문자를 제거한 텍스트를 전부 소문자로 만들어서 단어별로 쪼갠 것을 리스트(list)형태로 만들어 보았다.


바로 counter를 사용하려 parse된 문서를 단어별로 세는 통계를 만들었다.

이쯤에서 드는 생각 한 가지는,  이대로 통계를 내어 버리면 상대적으로 모든 영어 문서에 자주 쓰이는 단어들 (예컨데 the, a 같은 관사)가 지배적으로 통계의 상위권을 차지할 것이며, 책의 주제별 유의미한 통계를 한눈에 보기는 어려울 수 있다. 그렇지만 global하게 자주 쓰이는 단어들을 함께 산출하는 것 역시 의미를 가진다. 그래서 이 시점에서 책의 주제와 밀접하게 관련되었을 가능성이 큰 품사의 단어들을 필터링한 통계와, 필터링 없이 전체 통계를 산출하는 것 두 가지를 모두 수행한 후 비교하기로 했다.

단어들을 필터링한다면 어떤 단어들을 걸러내야 할까? 아직 명확한 기준을 생각해내기 여려워 관사(article), 접속사(conjunctions), 대명사 (pronoun)그리고 기타 전치사, be 동사 등으로부터 자주 사용되는 것들을 찾아 필터링할 단어들의 리스트를 (블랙리스트라는 이름으로) 만들어보았다.


이제 전체 단어의 통계를 포함한 count리스트와 대비되는 newcount리스트에 필터링된 단어들이 담겼다. 전체 단어들의 통계와 필터링된 단어들의 통계를 DataFrame으로 만들었다. 추가적으로 각각의 단어가 전체 단어들 중 차지하는 비율 (혹은 필터링된 단어들 중 차지하는 비율)을 구해 DataFrame의 column으로 추가해 보았다.


이제 TOP 30에 대해 DataFrame을 출력하고 그래프를 그려보자



<필터링 된 Top 30개 단어>



<필터링 하지 않은 Top 30개 단어>


모자이크 처리를 한 부분은 이 자료를 출판한 출판사의 홈페이지이다. 아마도 홈페이지의 주소가 책의 이곳저곳에 구석구석 등장하다보니 상위권에 기록된 듯 하다. 필터링하지 않았을 때는 수많은 관사들이 상위권을 차지했지만 한번의 필터링을 거치니 data, function, probability 등 내용과 관련된 단어들이 상위권에 많이 등장함을 알 수 있다. 그러나 여전히 보편적인 부사, 전치사 등의 단어를 걸러내는데 더 많은 노력이 필요할 것으로 보인다. 



- 숫자의 통계도 내보자 

여기서 아이디어가 더 떠올랐다. 과연 책마다 등장하는 숫자의 분포는 어떨까? 예전에 빅데이터를 다룬 카이스트 강의를 담아낸 책 '구글 신은 모든 것을 알고 있다'에서 벤포드 법칙 (Benford's Law)이라는 것에 대해 알게 되었다. 회계 장부, 뉴스, 각종 통계 등 지구 상의 모든 곳에서 나오는 숫자들의 통계를 내어 보면 첫 자리 숫자로 1이 가장 많이 나오며 그 다음으로 2, 3 순으로 9가 가장 적게 등장한다는 것이다. 언뜻보면 말이 안 된다고 생각할 수 있지만 이는 수학적으로 계산해 보았을 때 수많은 숫자들이 더하고 곱해나가는 연산을 진행할 때 자릿수의 숫자가 1이 될 가능성이 가장 높기 때문이다. 마찬가지로 다른 숫자들도 특정한 비율에 따라 첫 자리에 등장하며, 이를 이용하여 회계 장부 등의 조작 여부를 판단하기도 한다. 벤포드 법칙은 물론 숫자의 자릿수를 따로 떼어내서 생각했을 때의 경우이기는 하지만 문득 텍스트 자료 전반적으로 자주 등장하는 숫자가 어떤 것이며, 주제나 내용에 따라 자주 등장하는 숫자가 어떻게 달라질까?

위와 똑같은 방식으로 숫자만을 걸러내어 통계를 내고 DataFrame으로 만들어보았다.


여기서 한가지 주의할 것은, 텍스트 상의 숫자들이 모두 문자열 (string)형식의 데이터로 되어있었기 때문에 문자열 중에서 진짜 '문자'와 '숫자'를 구별해내는 작업이 필요했다. 숫자가 문자열 형식으로 되어있다면 ("1"과 같이), int함수를 통해 숫자로 변환하면 되고, 만일 int함수가 문자에 적용되었을 경우에는 ValueError가 발생한다는 점에 착안해 예외처리를 사용하여 숫자만을 골라내는 작업을 수행했다. 이는 문제없이 작동했지만, 예외처리를 통해 특정 작업을 골라내어 실행하는 것은 좋지 못한 코딩 방식이라는 글을 보았다. 아직 예외처리나, 뛰어난 코드를 작성하는 것이 익숙하지 않아 이 방법 이외에는 생각이 나지 않았지만 추후에 다른 방법을 생각해내게 된다면 수정해볼 예정이다. 



2. 분석

위의 코드를 활용해 실제로 몇 가지 다른 텍스트를 분석해보자. 분석하지 앞서 용의한 분석을 위해 위의 코드를 조금 수정해보았다. 가장 먼저, 위의 코드를 텍스트 소스를 argument로 넣으면 분석을 실행해주는 함수로 만들어 코드의 실행을 더 용이하게 만들어보았다. 필터링을 거치지 않고 분석하는 count_whole 함수, 필터링을 거친 후 분석을 실행하는 count_filtered함수, 숫자만 골라 통계를 내주는 count_number함수를 만든다. 더불어 count_filtered함수의 경우 단어를 필터링하는 기준도 보완했다. 구글링을 통해 가장 많이 쓰이는 접속사, 대명사, 전치사, 조동사, 그리고 기타 부사를 포함시켰다. 

count_whole함수



count_filtered함수




count_number함수



이제 이 함수들을 사용해서 텍스트를 분석해보자. 준비된 텍스트는 총 7개로, 파일명과 주제는 다음과 같다

ds1 - data science
soundpy1 - data science 음성 분석에 대한 글
soundpy2 - data science 음성 분석에 대한 글 2
bible - 성경
Quran - 쿠란
business1 - 경영/비즈니스에 관련된 텍스트
nonprofit business - 비영리 비즈니스에 관한 텍스트


1. ds1

(필터링하지 않은 결과는 위에서 보였던 결과와 같으니 필터링된 결과와 숫자의 통계만 보이겠다)







확실히 아까보다 일반적으로 많이 쓰이는 단어들이 필터링된 모습이다. Data 라는 단어는 책 전체 (필터링 된 단어들 중)의 1프로를 차지할 만큼 가장 많이 등장하며 숫자 1과 0은 data라는 단어 다음으로 많이 등장한다. return과 def는 파이썬의 함수에 사용되는 단어이기 때문에 많이 보이는 듯 하다. 그 되에도, x, p 등 함수에 변수 이름으로 자주 사용된 단어들이 많이 보인다. 숫자의 경우에는 1부터 10까지 1에 가까울수록 빈도가 전체적으로 경향이 있지만 1 다음으로 자주 등장하는 0이나 뒤바뀐 4와 5, 그리고 7이 outlier로 작용한다. 

number_count 의 코드를 조금 수정하여 1부터 순서대로 나열된 숫자의 빈도를 그래프로그려주는 기능을 추가해보자. 


200 이후로는 값이 의미가 없으며 1000은 outlier으로 보인다. 200 이후의 값을 drop한 뒤 다시 그려보자. 


전반적으로 100 안쪽으로 숫자가 몰려있는것을 볼 수 으며 편차는 있지만 숫자가 커질수록 출현빈도가 낮다. 정확히 말하면 한자리 수가 빈도가 월등히 높다고 볼 수 있겠다. 0 부근에서 급격하게 급락하는 지점을 볼 수 있는데, 이것은 인코딩이 잘못된 것인지 숫자 0 이 두 가지로 분류되어 잡혀 발생한 것으로 보인다. 


2. soundpy 1, 2

이번엔 파이썬 음향 데이터 분석 (audio analysis)에 관련된 텍스트 두개를 같이 살펴보자. 가장 먼저 필터링을 거치지 않은 전체 단어 통계 분석부터 살펴보겠다. 



이번에도 역시 the, a와같은 관사와 of, and in 등 각종 전치사, 접속사, 일반적인 부사는 상당히 높은 수치를 보인다. 심지어 'the'의 경우에는 전체 문서의 5퍼센트나 차지한다. 그외에 classification, analysis, library, audio 등 문서의 주제를 유추할 수 있는 단어들이 보이기 시작한다. 필터링을 거쳐보자. 



'일반적인'단어들이 많이 사라지고, 주제와 연관된 단어들이 많이 보이기 시작했다. 한 가지 아쉬운점은 첫 번째 문서에 비해 길이가 많이 짧아 pool 자체가 크지 않다는 점이다. 그렇지만 audio, analysis, library, feature, python, signal, pyaudioanalysis, classification 등의 상위 키워드들만 보더라도, 파이썬 라이브러리를 활용해서 오디오 분석을 하고, 머신러닝 기법의 일종인 classification을 사용해 오디오 분류를 하는것에 관한 내용이라는 것 정도는 유추할 수 있다. 

이번엔 유사한 주제의 문서라고 알고있는 soundpy2 문서를 분석해보자. 위에서부터 순서대로 필터링 하지 않은 결과, 필터링을 거친 결과이다. 




주제가 비슷하다보니 유사한 결과가 나왔지만 몇몇 새로운 단어들이 보인다. music, beat, onset 등이 보이고 그 외에 audio, function, analysis, python등은 공통된 단어들이다. 두 문서 모두 파이썬을 통해 오디오를 분석한다는 차원에서는 같지만 다른 모듈을 사용해 다른 측면의 분석을 제공하기 때문에 이런 차이가 나타났을 것이다. 이 문서역시 길이가 충분히 길지 못해 단어의 pool이 아주 크지는 않지만, 두 문서들간의 공통된 단어와 차이가 나는 단어들을 통해 유의미한 정보를 얻을 수 있다. 

이번엔 두 문서 속에 등장하는 숫자를 살펴보자. 





문서가 짧다보니 유의미한 결과를 얻을 만큼 숫자가 많이 등장하지 않는다. 그나마도 년도가 많이 등장하지만 22회, 15회 등장으로 유의미한 결과를 도출하기엔 너무 적다. 


200을 기준으로 잘라내보면 전체적으로 작은 숫자의 등장빈도가 높은 듯 하지만, 이것 역시 모집단이 너무 작아 결론을 내리기는 어렵다. 



3. 종교 - 성경과 쿠란 

이번 프로젝트를 진행하면서 가장 흥미로웠던 부분이라고 생각한다. 문득 종교 관련 서적에는 어떤 단어가 많이 등장할까?라는 생각이 들었으며 즉각 분석을 해보았다. 먼저 성경이다. 성경은 구약을 사용하였다. 

다른 문서에 비해서도 특히 일반적이고 추상적인 단어들이 지배적이다. 그 사이사이에 god, lord와 성경에 많이 쓰이는 고어체인 thy, thou 등이 눈에 띈다. 필터링을 한 번 해보자.



Data science나 python에 관련된 문서를 분석했을 때는 절대 찾아볼 수 없었던 단어들이 등장하기 시작했다. God 이나 lord 보다도 unto, his가 많이 쓰인 것을 보면 성경의 문체의 영향이 있었을 거라는 생각이 든다. House, children, people, king과 같은 단어가 많이 보이는데, 구약 성경 속 등장하는 인물들의 이야기가 그들의 지역 사회를 기반으로 묘사되기 때문에 이런 단어들이 많이 등장하지 않았을까 조심스럽게 예측해본다. 또한 누군가 측정 인물을 지친하는 단어로 남성형인 his와 man이 눈에 띄는데 반해 여성형의 지시어가 보이지 않는다. 

이번에는 쿠란을 살펴보자




필터링 없이 global로 출력한 결과는 크게 다르지 않았다. 그렇지만 필터링을 거치미 맨 위에는 무려 allah가 있으며, 성경과 마찬가지로 his가 두 번째에 위치해있다. 그리고 성경과는 다르게 prophet이라는 단어가 높은 등장빈도를 보인다. 그 외에도 muslim, islam 등의 단어의 등장빈도가 많으며 성경에도 자주 등장했던 lord, god이라는 단어도 높은 빈도로 등장한다. 

그렇다면 종교 경전에는 어떤 숫자가 자주 등장할까? 또 종교별로 자주 등장하는 숫자가 다를까? 위에서 만들었던 count_number함수를 이용해 성경과 쿠란에 등장하는 숫자를 분석해보자. 

그런데 여기서 문제가 생긴다. 성경과 쿠란을 살펴보니 숫자를 아라비아숫자로 표기하기보다 영문을 표기하며, 아라비아숫자는 주로 절과 장을 나타내기 위해 사용된다. 따라서 다음과 같이 영문으로 표기한 숫자를 분석하기 위한 함수를 새로 만들어야 했다. 


성경과 쿠란을 불러와 숫자를 분석해보자. 먼저 성경의 결과이다:


다른 숫자에 비해 'one'이 월등하게 많이 등장한다! (무려 모든 숫자의 26프로를 차지한다) 또한 hundred와 thousand도 상당히 빈도가 높은데, 주의해서 생각해야 할 점은 hundred와 thousand는 몇백, 몇천을 나타낼 때도 쓰이기에 꼭 1000, 100 만이 통계에 잡혔다고 보기는 힘들다. 

다음은 쿠란이다. 

신기하게도, 쿠란과 성경에서 모두 'seven'의 등장빈도가 그 부근의 한 자리 숫자헤 비해 상당히 높다. 그러나 쿠란의 경우 성경보다 숫자의모집단 자체가 작았으며 'one'의 비율이 48퍼센트로 상당히 집중되어있다. 


4. Business1 / nonprofit business 
business1 은 경영/컨설팅에 관한 문서, nonprofit business는 비영리 비즈니스에 관한 문서이다. 먼저 business1 부터 출력해보자. 위에부터 필터링을 거치지 않은 것, 거친 것 순서이다. 




필터링을 하지 않은 결과에서 보이는 단어들은 문서의 주제에 관련없이 거의 유사한 듯 보인다. (누군가가 가장 많이쓰이는 영단어 100개만 알아도 어느정도 대화를 할 수 있다고 농담조로 한 말이 떠오른다.) 필터링을 거치니 역시 종교, data science와는 또 다른 새로운 단어들이 보인다. 가장 많이 쓰이는 말은 market이며, 수치에 대한 분석을 많이 하다보니 percent, million과 같은 단어들도 보인다. industry, cost, product, good, mak 등의 단어 역시 경영과 밀접한 연관이 있는 단어들이다. 이 문서는 특히 경영 컨설팅 인터뷰에 관한 정보도 크게 다루어서 그런지 interviewer, students, questions, case 등의 단어도 눈에 띈다. 

다음에는 비영리 비즈니스에 관한 문서이다. 




이번에는 market이나 cost 등 생산과 수익창출에 관한 단어들보다는 collaboartion, fund등과 같이 비영리 사업에 더 밀접한 단어들이 많이 등장했다. 한가지 크게 아쉬운점은, 이 문서 역시 충분히 길지 않아 단어의 pool이 크지 않았다는 것이다.

마지막으로 business1 문서의 숫자를 살펴보자. (nonprofit은 문서의 길이가 너무 짧아 유의미한 결과를 보여주지 못해 생략하도록 하겠다)


지금까지와 다르게 10의 등장빈도가 굉장히 높았다! 200 이상의 큰 숫자를 제거한 뒤 Data science관련 문서들과 마찬가지로 분포의 동향이 있는지 살펴보려 했지만 훨씬 분포가 들쭉날쭉했다. 



***

더 많은 자료(dataset)가 필요하다

코드를 짜고 일단 급한대로 가지고 있는 문서들을 txt로 만든 뒤 테스트를 해 보았고, 몇몇 흥미로운 결과를 볼 수도 있었다. 그렇지만 단어 통계를 통해 유의미한 결론을 내거나, 단어와 주제 사이의 상관관계를 도출하기에는 너무 문서의 종류도, 길이도 제각각이며 결정적으로 문서의 갯수가 너무 적었다. 그래서 다음번엔 비슷한 길이의 문서를 카테고리별로 더 많이 준비해 제대로 분석하고, 공통된 단어들/공통되지 않은 단어들간의 관계를 분석해 문서간 네트워크를 만드는 작업을 진행해보려고 한다. 예를 들자면 가장 많이 등장한 10개의 단어들중 공통되는 단어들을 연결점으로 하는 문서 네트워크를 만들어보는 것이다. 그렇게해서 만들어진 네트워크가 문서들의 카테고리(혹은 주제)와 어느정도 일치성을 가지는지 살펴볼 계획이다. 



댓글

  1. 안녕하세요? 복자여자고등학교에 재학 중인 이혜원입니다.
    제가 이번 년도에 문체 분석과 관련된 연구를 진행하게 되었는데요. 위의 코딩을 응용해서 한국어로 된 작품을 품사를 나누어 분석할 수 있을까요?
    혹시 조언을 구할 수 있을까 싶어서 댓글 남깁니다.

    답글삭제

댓글 쓰기

이 블로그의 인기 게시물

Kaggle competition 간단후기

(2부) 플랫폼 비즈니스,그리고 카카오의 수익모델에 대한 idea