본문 바로가기

[파이썬 데이터분석] 가장 많이 사용하는 '영어 단어'는? 코드 구현!

Derrick 발행일 : 2023-11-20
728x90
반응형

 

1억 개의 영어 단어그 빈도수를 정리/구성된 British National Corpus(BCN) 단어 모음을 분석하고 그래프로 시각화해보자. 그리고나서 '이상한 나라의 엘리스' 동화책에 등장하는 단어와 BCN의 영어단어의 사용빈도 수를 비교해보자. BCN과 영어동화책에서 가장 많이 사용된 영어 단어는 무엇일까?

→ 'corpus.txt' 를 이용해서 가장 많이 사용된 영어 단어 분석 (하나의 텍스트파일 - BCN 자료)
→ 'alice/chapter1~5.txt' 를 이용하여 영어동화책에 사용된 영어 단어 분석 (여러 개의 텍스트파일 - 동화책)
→ 'matplotlib' 을 이용해 단어별 사용빈도를 보여주는 막대 그래프 작성
→ 아래 주어진 단계를 통해 각각의 필요한 함수들을 생성하고, main.py를 실행시켜 결과를 확인

 

가장 많이 사용되는 영어단어모음(BCN)를 분석하고
단어별 사용빈도를 보여주는 그래프를 시각화!

 

 

 

 

1. 필요한 패키지 import + 부연설명

실전 프로젝트에 필요한 패키지 import 하기 (각 패키지별 부연 설명 참고)

 

# 필요한 패키지 import
from operator import itemgetter
from collections import Counter
from string import punctuation
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

 

- from operator import itemgetter
 : itemgetter 함수는 주로 데이터 정렬 혹은 특정 데이터 추출하는 역할로 사용되는 것으로, 호출함수인 caller를 return하고 caller는 실제로 iterable한 값에 대해 인자로 지정된 n번째 원소를 최종적으로 return 하게 된다.

 # ex1) 원소 추출
 from operator import itemgetter
 a = [1, 3, 5]
 func = itemgetter(2)
 print(func(a))                    # 5

# ex2) 데이터 정렬
 from operator import itemgetter
 dots = [(1, 2), (1, 3), (-1, 7), (-1, 4)]
 dots = sorted(dots, key = itemgetter(1))
 print(dots)                         # [(1, 2), (1, 3), (-1, 4), (-1, 7)]
 → dots 리스트의 1번째 index에 해당하는 값을 기준으로 정렬

- from collections import Counter
 : collections 모듈의 Counter 클래스는 데이터의 개수를 셀 때 매우 유용하게 사용될 수 있는 라이브러리이다. 

- from string import punctuation
 : string.punctuation은 특수문자(!, #, $, & 등)들을 불러올 수 있고, 이를 활용해서 특수문자를 제거할 수 있다.

- import matplotlib.pyplot as plt / import matplotlib.font_manager as fm
 : matplotlib 패키지로 그래프를 시각화시키고, 한글폰드를 지원하기 위한 함수

 

2. 한 개의 데이터를 불러와서 리스트로 변환하기

단어와 빈도수 데이터가 담긴 한 개의 파일을 불러온 후, (단어, 빈도 수)의 형태로 Tuple로 구성된 리스트 반환
→ 'corpus' 텍스트파일을 읽어와서 리스트로 변환하는 함수 생성 (import_corpus)
아래 'corpus' 파일의 일부분을 보면 '단어'와 그 단어에 대한 '빈도수'가 쉼표(,)로 구분되어있고, 단어의 수는 대략 10,000개 정도 된다.

 

'corpus.txt' 파일

def import_corpus(filename):
    # 튜플(단어, 빈도수)을 저장할 리스트 생성
    corpus = []
    
    # 매개변수로 입력 받은 파일을 열고, corpus에 저장
    with open(filename) as file:
        # file의 각 줄을 (단어, 빈도수) 형태로 corpus에 저장
        for line in file:
            word, freq = line.strip().split(',')
            corpus.append((word, int(freq)))
            
    return corpus
    
# 함수 실행
print(import_corpus('corpus.txt'))

 

[ import_corpus('corpus.txt') 실행 결과 ]

위 실행 결과를 보면 단어들과 해당 단어의 빈도수 데이터가 있는 'corpus.txt' 텍스트 파일을 입력받아서 각 line별로 (단어, 빈도수) 형태로 'corpus'라는 리스트에 잘 저장된 것을 확인할 수 있다.

 

반응형

 

3. 여러 개의 파일들을 한 번에 불러와서 리스트 변환하기

앞에서는 1개의 텍스트 파일에 대해 (단어, 빈도수) 형태의 튜플(Tuple)로 구성된 리스트를 반환했다면, 이제는 여러 개의 파일을 한번에 불러와서 동일한 작업을 실행한다. 아래의 순서대로 수행해보자.

# 아래의 사진과 같이 현재의 디렉토리 내 chapter1~5까지의 총 5개의 텍스트파일들이 있다.
 1) 이 텍스트파일들을 한번에 불러와서 모두 하나의 리스트(words)에 저장한다.
 2) 문장에 있는 모든 특수기호를 제거한다.
 3) words에 저장된 모든 데이터들을 (단어, 빈도수)인 튜플 형태의 리스트 형식으로 변환한다.
  → Counter 클래스를 사용해서 중복된 데이터의 빈도수를 추출해낼 수 있다.
  → Dictionary의 Value로 저장된다. 

 

[ chapter1 텍스트파일 ]
[ chapter2 텍스트 파일 ]

 

# 함수 생성
def create_corpus(filenames):
    # 모든 단어들을 저장할 리스트 생성
    words = []
    
    for filename in filenames:
        with open(filename) as file:
            content = file.read().strip()
            
            # 문장 내 모든 특수기호를 제거한다
            for symbol in punctuation:
                content = content.replace(symbol, '')
            words += content.split()
    
    # words 리스트에 있는 모든 데이터를 (단어, 빈도수) 형태로 변환
    corpus = Counter(words)
    return list(corpus.items())

# 여러 텍스트파일 불러오기 + 함수 실행
alice_files = ['alice/chapter{}.txt'.format(chapter) for chapter in range(1, 6)]
alice_corpus = create_corpus(alice_files)

print(alice_corpus)

 

[ corpus.item() ]
[ corpus.keys() ]
[ corpus.values() ]

위의 실행 결과를 보면, 여러 개의 텍스트파일들을 한번에 불러와서 (단어, 빈도수) 형태인 Tuple들이 포함된 리스트가 잘 생성된 것을 확인할 수 있다.

Counter() 함수를 통해서 중복된 데이터를 배열의 인자로 저장/출력함으로써 빈도 수를 계산하고, Counter 클래스는 파이썬의 기본 자료구조인 Dictionary를 확장하고 있기 때문에 '단어'도 저장된다.
corpos.items() : Keys(단어)와 Values(빈도 수) 모두 저장/출력
corpos.keys() : words 리스트에 저장된 모든 데이터의 Keys(단어)만 저장/출력
corpos.values() : words 리스트에 저장된 모든 데이터의 Values(빈도 수)만 저장/출력

 

4. 특정 문자로 시작하는 단어만 추출

바로 위에서 생성한 (단어, 빈도 수) 형태의 튜플(tuple)들을 담고 있는 리스트인 'corpus' 데이터에 대해서 특정 문자열(=prefix)로 시작하는 단어 데이터만 추출하는 함수로 생성해보자. (리스트 형태로 저장)
→ ex) filter_by_prefix(corpus, 특정 문자열) 

 

# 함수 생성
def filter_by_prefix(corpus, prefix):
    return [(word, freq) for (word, freq) in corpus if word.startswith(prefix)]

# 테스트
corpus = import_corpus('corpus.txt')

print("#'head'로 시작하는 단어만 추출 :")
print(filter_by_prefix(corpus, 'head'), "\n")
print("#'ab'로 시작하는 단어만 추출 :")
print(filter_by_prefix(corpus, 'ab'))

 

[ 실행 결과 - head, ab로 시작하는 단어 추출 ]

위의 결과를 보면, 'head'와 'ab'로 각각 시작하는 단어들이 추출되고 해당 단어의 빈도 수까지 잘 출력된 것으로 확인할 수 있다.

- corpus = import_corpus('corpus.txt')
 : 주어진 'corpus.txt' 파일을 import_corpus() 함수를 통해 리스트로 변환한 데이터

 

5. 가장 빈도 수가 높은 n개의 데이터만 추출

위의 corpus의 데이터들 중 가장 빈도가 높은 n개(=number개)의 데이터들만 높은 순서대로 추출한다.
sorted(), itemgetter() 함수를 통해서 데이터 정렬!

 

# 함수 생성
def most_frequent_words(corpus, number):
    # 텍스트파일(corpus)과 높은 순서대로 출력할 number를 입력받음
    return sorted(corpus, key=itemgetter(1), reverse=True)[:number]

# 함수 테스트
corpus = import_corpus('corpus.txt')
print(most_frequent_words(corpus, 10))

 

[ 함수 실행 결과 ]

위의 결과를 보면 corpus 데이터 중에서 가장 많이 빈도 수가 높은 순으로 10개(=number)의 데이터가 출력된 것을 확인할 수 있다.

- sorted(corpus, key=itemgetter(1), reverse=True)[:number]
 → reverse=True : 데이터들을 오름차순이 아닌 높은 순서대로 내림차순으로 정렬
 → [:number] : 첫번째 데이터부터 입력받은 number만큼의 데이터만 추출
 → key=itemgetter(1) : 각 데이터의 index 1번째의 데이터(=빈도 수)를 기준으로 정렬한다.

# itemgetter()
 : itemgetter 함수는 주로 데이터 정렬 혹은 특정 데이터 추출하는 역할로 사용되는 것으로, 호출함수인 caller를 return하고 caller는 실제로 iterable한 값에 대해 인자로 지정된 n번째 원소를 최종적으로 return 하게 된다.

# Example)
 from operator import itemgetter
 dots = [(1, 2), (1, 3), (-1, 7), (-1, 4)]
 dots = sorted(dots, key = itemgetter(1))
 print(dots)                         # [(1, 2), (1, 3), (-1, 4), (-1, 7)]
 → dots 리스트의 1번째 index에 해당하는 값을 기준으로 정렬

 

6. 전처리한 데이터로 그래프를 그리는 함수 생성

여기까지 전처리한 데이터를 바탕으로 본격적인 각 데이터모음의 빈도 수에 대한 막대그래프를 그리는 함수를 생성해보자 (draw_frequency_graph)
→  함수는 단어별 높은 순으로 빈도 수가 정렬된 데이터를 입력 받는다. (top_ten)

 

# 함수 생성
def draw_frequency_graph(corpus):
    # 막대 그래프의 막대 위치를 결정하는 pos 선언
    pos = range(len(corpus))
    
    # 튜플의 리스트 형태인 corpus를 단어와 빈도 수의 리스트로 분리
    words = [time[0] for time in corpus]
    freqs = [time[1] for time in corpus]
    
    # 차트를 한국어로 보기 좋게 표시되도록 폰트 설정
    font = fm.FontProperties(fname='./NanumBarunGothic.ttf')
    
    # 막대의 높이가 빈도의 값이 되도록 성정
    plt.bar(pos, freqs, align='center')
    
    # 각 막대에 해당되는 단어 입력(xticks)
    plt.xticks(pos, words, rotation='vertical', fontproperties=font)
    
    # 그래프의 제목 설정
    plt.title('단어별 사용 빈도', fontproperties=font)
    
    # Y축에 설명 추가
    plt.ylabel('빈도', fontproperties=font)
    
    # 단어가 잘리지 않도록 여백 조정 + 차트 저장
    plt.tight_layout()
    plt.savefig('graph.png')

# 데이터 불러오기 & 함수 테스트
corpus = import_corpus('corpus.txt')
top_ten = most_frequency_graph(top_ten)

draw_grequency_graph(top_ten)

 

[ 그래프 출력 결과 ]

위의 차트를 통해 x축에는 빈도 수가 많은 10개의 추출된 데이터들을, y축에는 해당 단어의 빈도 수를 표현한 막대그래프로 시각화된 것을 확인할 수 있다.

 

7. main 함수로 생성한 함수들 종합하기

지금까지 데이터 분석을 통해 생성한 함수들을 main 함수 안에 종합하고, 실제로 결과를 확인해보자

 

# main 함수 생성
def main(prefix=''):
    # import_corpus() 함수를 통해 튜플의 리스트 생성
    corpus = import_corpus('corpus.txt')
    
    # prefix로 시작하는 단어들만 골라서 추출
    prefix_words = filter_by_prefix(corpus, prefix)
    
    # 주어진 prefix로 시작하는 단어들을 빈도가 높은 순으로 정렬(10개 추출)
    top_ten = most_frequent_words(prefix_words, 10)
    
    # 단어별 빈도수가 그래프로 출력
    draw_frequency_graph(top_ten)
    
    # '이상한 나라의 엘리스' 영문 동화책의 단어(chapter1~5)를 corpus로 변환
    alice_files = ['alice/chapter{}.txt'.format(chapter) for chapter in range(1, 6)]
    alice_corpus = create_corpus(alice_files)
    
    top_ten_alice = most_frequent_words(alice_corpus, 10)
    draw_frequency_graph(top_ten_alice)


# main 함수 실행
if __name__ == '__main__':
    main('ab')
    # main('un')

 

[ main(ab), main(un) 실행 결과 ]

위의 차트를 보면, 각각 'ab'와 'un'으로 시작하는 단어들의 빈도수가 높은 순으로 데이터들이 추출되었고, 해당 빈도수에 맞게 차트가 그려진 것을 확인할 수 있다.

 

8. 최종 코드 & 실행 결과 

최종적으로 코드를 정리하고, 아무런 prefix 없이 BCN 데이터와 영문 동화책의 영어단어의 빈도수를 출력하고 그래프로 비교해보자.

 

# 프로젝트에 필요한 패키지 import
from operator import itemgetter
from collections import Counter
from string import punctuation
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm


# 1) 한 개의 데이터를 불러와서 리스트로 변환
def import_corpus(filename):
    # 튜플(단어, 빈도수)을 저장할 리스트 생성
    corpus = []
    
    # 매개변수로 입력 받은 파일을 열고, corpus에 저장
    with open(filename) as file:
        # file의 각 줄을 (단어, 빈도수) 형태로 corpus에 저장
        for line in file:
            word, freq = line.strip().split(',')
            corpus.append((word, int(freq)))
            
    return corpus
    
# 함수 실행
# print(import_corpus('corpus.txt'))


# 2) 여러 개의 파일들을 한번에 불러와서 리스트 변환
def create_corpus(filenames):
    # 모든 단어들을 저장할 리스트 생성
    words = []
    
    for filename in filenames:
        with open(filename) as file:
            content = file.read().strip()
            
            # 문장 내 모든 특수기호를 제거한다
            for symbol in punctuation:
                content = content.replace(symbol, '')
            words += content.split()
    
    # words 리스트에 있는 모든 데이터를 (단어, 빈도수) 형태로 변환
    corpus = Counter(words)
    return list(corpus.items())

# 여러 텍스트파일 불러오기 + 함수 실행
# alice_files = ['alice/chapter{}.txt'.format(chapter) for chapter in range(1, 6)]
# alice_corpus = create_corpus(alice_files)
# print(alice_corpus)


# 3) 특정 문자로 시작하는 단어만 추출 (리스트)
def filter_by_prefix(corpus, prefix):
    return [(word, freq) for (word, freq) in corpus if word.startswith(prefix)]

# corpus = import_corpus('corpus.txt')
# print("#'head'로 시작하는 단어만 추출 :")
# print(filter_by_prefix(corpus, 'head')


# 4) 가장 빈도가 높은 n개의 데이터만 추출

def most_frequent_words(corpus, number):
    # corpus의 데이터 중 가장 빈도가 높은 number개의 데이터만 높은 순서대로 추출
    return sorted(corpus, key=itemgetter(1), reverse=True)[:number]

# corpus = import_corpus('corpus.txt')
# print(most_frequent_words(corpus, 10))


# 5) 막대그래프를 그리는 함수 생성
def draw_frequency_graph(corpus):
    # 막대 그래프의 막대 위치를 결정하는 pos를 선언합니다.
    pos = range(len(corpus))
    
    # 튜플의 리스트인 corpus를 단어의 리스트 words와 빈도의 리스트 freqs로 분리합니다.
    words = [time[0] for time in corpus]
    freqs = [time[1] for time in corpus]
    
    # 한국어를 보기 좋게 표시할 수 있도록 폰트를 설정합니다.
    font = fm.FontProperties(fname='./NanumBarunGothic.ttf')
    
    # 막대의 높이가 빈도의 값이 되도록 설정합니다.
    plt.bar(pos, freqs, align='center')
    
    # 각 막대에 해당되는 단어를 입력합니다.
    plt.xticks(pos, words, rotation='vertical', fontproperties=font)
    
    # 그래프의 제목을 설정합니다.
    plt.title('단어 별 사용 빈도', fontproperties=font)
    
    # Y축에 설명을 추가합니다.
    plt.ylabel('빈도', fontproperties=font)
    
    # 단어가 잘리지 않도록 여백을 조정합니다.
    plt.tight_layout()
    
    # 그래프를 표시합니다.
    plt.savefig('graph.png')

# corpus = import_corpus('corpus.txt')
# top_ten = most_frequent_words(corpus, 10)
# 단어 별 빈도수를 그래프로 시각화
# draw_frequency_graph(top_ten)


# 6) main 함수 생성
def main(prefix=''):
    # import_corpus() 함수를 통해 튜플의 리스트를 생성합니다.
    corpus = import_corpus('corpus.txt')
    
    # head로 시작하는 단어들만 골라 냅니다.
    prefix_words = filter_by_prefix(corpus, prefix)
    
    # 주어진 prefix로 시작하는 단어들을 빈도가 높은 순으로 정렬한 뒤 앞의 10개만 추립니다.
    top_ten = most_frequent_words(prefix_words, 10)
    
    # 단어 별 빈도수를 그래프로 나타냅니다.
    draw_frequency_graph(top_ten)
    
    # '이상한 나라의 엘리스' 책의 단어를 corpus로 바꿉니다.
    alice_files = ['alice/chapter{}.txt'.format(chapter) for chapter in range(1, 6)]
    alice_corpus = create_corpus(alice_files)
    
    top_ten_alice = most_frequent_words(alice_corpus, 10)
    draw_frequency_graph(top_ten_alice)


if __name__ == '__main__':
    main()

 

[ corpus 데이터와 엘리스 동화책 데이터의 빈도수 비교 ]

위의 차트를 통해 BCN 영어모음과 '이상한 나라의 엘리스' 동화책의 영어단어의 빈도수를 비교할 수 있다.

# 최종 코드 내 함수 설명
- import_corpus(filename) : corpus 파일(filename)을 불러와서 리스트로 변환 (단어, 빈도수)
- create_corpus(filename) : 여러 개의 파일(영문 동화책)을 불러와서 리스트로 변환
- filter_by_prefix(corpus, prefix) : 입력 받은 특정 문자(prefix)로 시작하는 단어들만 추출
- most_frequent_words(corpus, number) : 빈도 수가 높은 순으로 number 개의 데이터들 추출
- draw_frequency_graph(corpus) : 각 데이터모음의 빈도 수에 대한 막대그래프 그리기

 

 

댓글