N-gram(엔그램)이란?
연속된 N개의 단어(또는 문자)를 하나의 묶음으로 표현하는 기법
자연어 처리(NLP)에서 문장의 문맥을 일부 반영하기 위해 가장 많이 사용하는 방법 중 하나
N : 묶을 개수
Gram: 연속된 토큰(Token)의 집합
즉, 문장을 일정한 길이의 연속된 단어 묶음으로 나누는 방법
나는 오늘 학교에 간다를
Unigram (1-gram) 단어를 하나씩 분리
나는
오늘
학교에
간다
Bigram (2-gram) 연속된 두 개의 단어를 묶기
나는 오늘
오늘 학교에
학교에 간다
Trigram (3-gram) 연속된 세 개의 단어를 묶기
나는 오늘 학교에
오늘 학교에 간다
4-gram 연속된 네 개의 단어를 묶기
나는 오늘 학교에 간다
즉 단어가 아니라 문자 단위로 사용할 수 있어 단어의 순서와 일부 문맥(Context)을 반영할 수 있다.
Unigram으로 표현하면 단어들의 순서 정보가 사라지지만 Bigram은 앞뒤 단어 관계를 유지할 수 있다는 것.
Bag of Words는 순서를 고려하지 않지만 Bigram는 순서를 고려해 다음 단어를 예측하는 데도 사용된다.
즉 이전 단어 하나만 보고 다음 단어를 예측한다.
나는 : 1
밥을 : 1
먹었다 : 1
나는 오늘 ____.
sentence = "나는 오늘 학교에 간다"
words = sentence.split()
# Bigram 생성
bigrams = []
for i in range(len(words) - 1):
bigrams.append((words[i], words[i + 1]))
print(bigrams)
[('나는', '오늘'),
('오늘', '학교에'),
('학교에', '간다')]
Trigram 생성
Trigram은 연속된 3개의 토큰(단어 또는 문자)을 하나로 묶은 형태
sentence = "나는 오늘 학교에 간다"
words = sentence.split()
trigrams = []
for i in range(len(words) - 2):
trigrams.append((words[i], words[i + 1], words[i + 2]))
print(trigrams)
[('나는', '오늘', '학교에'),
('오늘', '학교에', '간다')]
NLTK 예제
from nltk import ngrams
sentence = "나는 오늘 학교에 간다".split()
# Bigram
print(list(ngrams(sentence, 2)))
# Trigram
print(list(ngrams(sentence, 3)))
[('나는', '오늘'),
('오늘', '학교에'),
('학교에', '간다')]
[('나는', '오늘', '학교에'),
('오늘', '학교에', '간다')]
구현이 매우 간단하고.단어의 순서를 일부 반영할 수 있다.
문맥 정보를 일정 부분 유지하고 텍스트 분류, 검색, 자동완성 등 다양한 NLP 작업에서 활용된다.
하지만 N이 커질수록 데이터 희소성(Data Sparsity) 문제가 발생해 5-gram, 6-gram처럼 N이 커지면 특정 조합이 학습 데이터에 거의 등장하지 않아 확률을 추정하기 어려워진다. 메모리 사용량과 계산량이 증가하고 긴 문맥을 충분히 반영하지 못한다. Bigram은 이전 1개 단어, Trigram은 이전 2개 단어만 참고하기 때문에 문장 전체의 의미를 이해하는 데 한계가 있다.
학습 데이터에 없는 N-gram은 처리하기 어렵다(Out-of-Vocabulary 및 희소성 문제).
다음단어 예측, 자동완성, 맞춤법 및 오타교정, 기계 번역, 텍스트 분류, 검색엔진에 이용된다.
핵심은 N-gram이 연속된 N개의 토큰을 묶어 단어의 순서와 일부 문맥 정보를 반영하는 기법이라는 점
다만 N이 커질수록 더 많은 문맥을 반영할 수 있는 대신, 데이터 희소성과 계산 비용이 증가하는 단점도 함께 커진다.