본문 바로가기
Python 코딩도장

파이썬 코딩도장 Unit 28 정리(2) - N-gram 만들기

by chanfficial 2022. 2. 18.

2. N-gram 만들기

  • N-gram은 문자열에서 N개의 연속된 요소를 추출하는 방법이다.
  • 만약 'Hello'라는 문자열을 문자(글자) 단위 2-gram으로 추출하면 다음과 같이 된다.
    He
    el
    ll
    lo​
  • 즉, 문자열의 처음부터 끝까지 한 글자씩 이동하면서 2글자를 추출한다(3-gram은 3글자, 4-gram은 4글자)

 

 

2-1. 반복문으로 N-gram 출력하기

  • 반복문으로 문자 단위 2-gram을 추출해보면, 문자열의 끝에서 한 글자 앞까지만 반복하며 현재 문자와 그다음 문자 두 글자씩을 출력한다.
    text = 'Hello'
     
    for i in range(len(text) - 1):          # 2-gram이므로 문자열의 끝에서 한 글자 앞까지만 반복함
        print(text[i], text[i + 1], sep='') # 현재 문자와 그다음 문자 출력
        
    # 실행 결과
    He
    el
    ll
    lo​

2-gram

  • 만약 3-gram이면 반복 횟수는 range(len(text)-2) 와 같이 되고, 문자열 끝에서 두 글자 앞까지 반복하면 된다.
  • 문자열을 출력할 때는 print(text[i], text[i+1], text[i+2], sep='') 가 되는데, 여기서 문자열을 끝까지 반복하면 text[i+1], text[i+2] 는 문자열의 범위를 벗어난 접근을 하게 되므로 주의해야 한다.
  • 다음은 문자열을 공백으로 구분하여 단어 단위 2-gram을 출력한다. 예를 들어 'this is python script' 는 'this is', 'is python', 'python script' 가 된다.
    text = 'this is python script'
    words = text.split()             # 공백을 기준으로 문자열을 분리하여 리스트로 만듦
     
    for i in range(len(words) - 1):  # 2-gram이므로 리스트의 마지막에서 요소 한 개 앞까지만 반복함
        print(words[i], words[i + 1]) # 현재 문자열과 그다음 문자열 출력
        
    # 실행 결과
    this is
    is python
    python script​
  • 이처럼 단어 단위 2-gram도 spilt을 사용하여 공백을 기준으로 문자열을 분리하고 리스트로 만든 다음, 2-gram이므로 words 리스트의 마지막에서 요소 한 개 앞까지만 반복하면서 현재 문자열과 그다음 문자열을 출력하면 된다.

 

 

 

2-2. zip으로 2-gram 만들기

  • 지금까지 zip 함수는 리스트 두 개를 딕셔너리로 만들 때 사용했는데, zip 함수는 반복 가능한 객체의 각 요소를 튜플로 묶어준다.
    text = 'hello'
     
    two_gram = zip(text, text[1:])
    for i in two_gram:
        print(i[0], i[1], sep='')
        
    # 실행 결과
    He
    el
    ll
    lo​
  • zip(text, text[1:]) 은 문자열 text와 text[1:]의 각 요소를 묶어서 튜플로 만들고, text[1:]은 인덱스 1(두번째 문자)부터 마지막 문자를 가져오므로 text와 text[1:]을 zip으로 묶으면 문자 하나가 밀린 상태로 각 문자를 묶게 된다.
    >>> text = 'hello'
    >>> list(zip(text, text[1:]))
    [('h', 'e'), ('e', 'l'), ('l', 'l'), ('l', 'o')]​
  • 이렇게 만들어진 2-gram 리스트를 출력할 때는 for i in two_gram: 과 같이 for로 반복하면서 print(i[0], i[1], sep='')로 튜플의 요소를 출력해주면 된다.
  • 단어 단위 2-gram도 문자열을 공백으로 분리하여 리스트로 만드는 것을 제외하고는 같은 방법으로 만들면 된다.
    >>> text = 'this is python script'
    >>> words = text.split()
    >>> list(zip(words, words[1:]))
    [('this', 'is'), ('is', 'python'), ('python', 'script')]​
  • 만약 3-gram을 만들고 싶다면 zip(words, words[1:], words[2:]) 와 같이 word, word[1:], word[2:] 총 3개의 리스트를 넣으면 된다.

 

 

 

2-3. zip과 리스트 표현식으로 N-gram 만들기

  • N-gram을 만들 때 zip에 일일이 [1:], [2:] 같은 슬라이스를 넣는데, 만약 N-gram의 숫자가 늘어나면 그만큼 슬라이스도 여러 개 입력해줘야 하는 것이 번거롭기 때문에 이 과정을 코드로 만든 리스트 표현식을 사용하면 된다.
    >>> text = 'hello'
    >>> [text[i:] for i in range(3)]
    ['hello', 'ello', 'llo']​
  • [text[i:] for i in range(3)] 처럼 for로 3번 반복하면서 text[i:]로 리스트를 생성했다.
  • 이때 for i in range(3)dms 0, 1, 2 까지 반복하므로 text[i:]는 text[0:], text[1:], text[2:] 가 되고, 이것이 3-gram에 필요한 슬라이스이다.(text[0:]은 text와 같아서 지금까지 zip에 넣었던듯)
    >>> list(zip(['hello', 'ello', 'llo']))
    [('hello',), ('ello',), ('llo',)]​
  • 리스트 ['hello', 'ello', 'llo'] 를 zip에 넣어보면 결과가 3-gram이 아닌데, 이는 zip에 반복 가능한 객체 여러 개를 콤마로 구분해서 넣어주지 않고 ['hello', 'ello', 'llo'] 처럼 요소가 3개 들어있는 리스트 1개를 넣었기 때문이다.
  • zip에 리스트의 각 요소를 콤마로 구분해서 넣어주려면 리스트 앞에 *를 붙여야 한다.
    >>> list(zip(*['hello', 'ello', 'llo']))
    [('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]​
  • 이제 3-gram 리스트가 만들어졌고, 리스트 표현식을 바로 zip에 넣어주려면 리스트 표현식 앞에 *를 붙이면 된다.
    >>> list(zip(*[text[i:] for i in range(3)]))
    [('h', 'e', 'l'), ('e', 'l', 'l'), ('l', 'l', 'o')]​