반응형
젠스 알브레히트, 시다르트 라마찬드란, 크리스티안 윙클러, 『파이썬 라이브러리를 활용한 텍스트 분석 Blueprints for Text Analytics Using Python』, 심상진, 한빛미디어-OREILLY(2022), p135-175.
Learned
텍스트 데이터의 일반적인 전처리 파이프라인
노이즈 처리 w. regex
- +, *와 같은 반복자는 유의해서 사용 (텍스트의 많은 부분을 제거할 수 있음)
문자 정규화
- ex. 악센트와 같은 문자를 다른 토큰으로 인식 -> textacy 라이브러리 활용 가능
- textacy : spacy와 함께 작동하도록 구축된 라이브러리
- 언어 부분은 spacy에 맡기고 사전 및 사후 처리에 중점을 둠
- normalize_hyphenated_words: 줄 바꿈으로 구분된 단어를 다시 조합
- normalize_quotation_marks: 모든 종류의 따옴표를 ASCII에 해당하는 따옴표로 대체
- normalize_unicode: 유니코드에서 악센트가 있는 문자를 다른 코드로 변경
- remove_accents: 악센트가 있는 문자를 ASCII로 바꾸거나 삭제
데이터 마스킹
- url, email, 주소, 전화번호와 같이 무관한 정보나 개인정보를 보호할 때 적용
- 마스킹 관련 정규 표현식 -> textacy 참고
토큰화
- 토큰이란? : 의미론적으로 분석에 유용한 언어 단위
- 풀어야하는 문제에 따라 토큰화 방식은 달라짐
- ex. 어떤 문제에서는 이모티콘을 제외해야하고, 감성분석 같은 경우에는 이모티콘을 포함할 수도 있음
- scikit-learn CountVectorizer는 기본 토큰화에 \w\w+ 패턴을 사용함
# 한글
tokens = re.findall(r'\w\w+', '어떻게 하는지 한 번 봐볼까요? #연습 @테스트 😩😬')
print(*tokens, sep='|') # 어떻게|하는지|봐볼까요|연습|테스트
# 영어
tokens = re.findall(r'\w\w+', "Let's see how you do it. #practice @test 😩😬")
print(*tokens, sep='|') # Let|see|how|you|do|it|practice|test
- 해시태그, 이모지 등 포함하기
RE_TOKEN = re.compile(r"""
( [#]?[@\w'’\.\-\:]*\w # words, hash tags and email adresses
| [:;<]\-?[\)\(3] # coarse pattern for basic text emojis
| [\U0001F100-\U0001FFFF] # coarse code range for unicode emojis
)
""", re.VERBOSE)
def tokenize(text):
return RE_TOKEN.findall(text)
# 한글
tokens = tokenize('어떻게 하는지 한 번 봐볼까요? #연습 @테스트 😩😬')
print(*tokens, sep='|') # 어떻게|하는지|한|번|봐볼까요|#연습|@테스트|😩|😬
# 영어
tokens = tokenize("Let's see how you do it. #practice @test 😩😬")
print(*tokens, sep='|') # Let's|see|how|you|do|it|#practice|@test|😩|😬
- NLTK
- wort_tokenize 함수를 활용
- 내부적으로 PuncktSentenceTokenizer와 TreebankWordTokenizer를 사용
- 표준 텍스트에서는 잘 작동하지만 해시태그나 텍스트 이모티콘에는 결함이 있음
- 도메인별 토큰 패턴의 정밀도를 높이려면 사용자 지정 정규 표현식을 사용해야함
- 맞춤법 검사 -> 품질 향상 체크 필요
Spacy
- 토큰화, 품사 태거(part-of-speech tagger), 의존성 구문 분석기(dependency parser), 개체명 인식기(named-entitiy recognizer)와 같은 처리 파이프라인을 제공
- 토큰화: 복잡한 언어 종속 규칙과 정규표현식을 기반 -> 매우 빠름
- 후속 단계: 사전 훈련된 신경망 모델을 사용 -> 많은 시간을 소비, but GPU에서 실행 가능 - spacy.prefer_gpu()로 확인
- 파이프라인 수행 중에도 원본 텍스트가 유지됨
- 단계별 원본 텍스트의 추가 정보가 담긴 정보 계층이 존재
- ex. Doc: 처리된 텍스트에 대한 주요 정보를 가짐, Token 목록을 포함
- 다른 라이브러리와 비교했을 때, spacy 모델이 가장 빠름
토큰화 예시
- lemma_: 원형
- pos_: 품사 태그
- dep_: 종속성 태그
- ent_*: 개체 유형
- is_*: 특징 플래그 -> 규칙을 기반으로 생성됨
text = "Learning NLP is really funny!"
nlp = spacy.load("en_core_web_sm")
doc = nlp(text)
type(doc) # spacy.tokens.doc.Doc
display_nlp(doc)
사용자 정의 토큰화
- 문제에 맞게 토큰을 알맞게 분리시켜야하는 경우가 있음
- 중위, 접두사, 접미사 분할에 대한 개별 규칙을 사용해 토큰화를 변형하면 해결할 수 있음
- 중위 규칙: 단어 사이에 하이픈(-)이 있으면 분리 (compile_infix_regex)
- 접두사 규칙: 단어 바로 앞에 # or _와 같은 문자가 있으면 분리 (compile_prefix_regex)
- 접미사 규칙: 단어 바로 뒤에 # or _와 같은 문자가 있으면 분리 (compile_suffix_regex)
import re
import spacy
from spacy.tokenizer import Tokenizer
from spacy.util import compile_prefix_regex, compile_infix_regex, compile_suffix_regex
def custom_tokenizer(nlp):
# use default patterns except the ones matched by re.search
prefixes = [pattern for pattern in nlp.Defaults.prefixes
if pattern not in ['-', '_', '#']]
suffixes = [pattern for pattern in nlp.Defaults.suffixes
if pattern not in ['_']]
infixes = [pattern for pattern in nlp.Defaults.infixes
if not re.search(pattern, 'xx-xx')]
return Tokenizer(vocab = nlp.vocab,
rules = nlp.Defaults.tokenizer_exceptions,
prefix_search = compile_prefix_regex(prefixes).search,
suffix_search = compile_suffix_regex(suffixes).search,
infix_finditer = compile_infix_regex(infixes).finditer,
token_match = nlp.Defaults.token_match)
text = "@samoyed : test spacy for fun #smiling-sammy _url_ ;-) 😋👍"
nlp = spacy.load('en_core_web_sm')
# 기본 결과 (@samoyed|:|test|spacy|for|fun|#|smiling|-|sammy|_|url|_|;-)|😋|👍|)
doc = nlp(text)
for token in doc:
print(token, end="|")
print()
# 커스터마이징 결과 (@samoyed|:|test|spacy|for|fun|#smiling-sammy|_url_|;-)|😋|👍|)
nlp.tokenizer = custom_tokenizer(nlp)
doc = nlp(text)
for token in doc:
print(token, end="|")
불용어 제거 (Stopwords)
- is_stop을 기준으로 필터링
- 불용어 목록은 spacy.lang.en.STOP_WORDS에서 볼 수 있음
원형 추출 (Lemmatization)
- 불변형 어근에 매칭하는 과정 (ex. meet, meeting, met -> meet)
- 원형만 추출하면 어휘량이 적어지므로 모델 품질을 향상시킬 수 있고, 학습 시간과 모델 크기를 줄일 수 있음
- 명사, 동사, 형용사와 같은 특정 범수로 단어의 유형을 제한하는 것이 좋음 -> pos_ 활용
- 인칭 대명사(I, me, you)는 -PRON-으로 반환
- 때로는 원형 추출을 하지 않는 것이 좋을 수도 있음 (ex. 감성 분석)
import textacy
text = "Studying NLP is really fun for smiling sammy."
doc = nlp(text)
# 토큰 추출
tokens = textacy.extract.words(doc,
filter_stops = True, # default True, remove stop words from word list
filter_punct = True, # default True, remove punctuation from word list
filter_nums = True, # default False, if True -> remove number-like words (e.g. 10, "ten")
include_pos = ['VERB', 'ADJ', 'NOUN'], # default None = include all
exclude_pos = None, # default None = exclude none
min_freq = 1) # minimum frequency of words
print(*[t for t in tokens], sep='|') # Studying|fun|smiling|sammy
# 원형 추출
def extract_lemmas(doc, **kwargs):
return [t.lemma_ for t in textacy.extract.words(doc, **kwargs)]
lemmas = extract_lemmas(doc, include_pos=['ADJ', 'NOUN'])
print(*lemmas, sep='|') # fun|sammy
명사구 추출
- 품사 태그에 패턴 일치를 적용할 수 있음 (with Spacy, textacy)
- Spacy에는 규칙 기반 매처가 존재
- textacy에는 패턴 기반 구문 추출을 위한 래퍼가 존재
def extract_noun_phrases(doc, preceding_pos=['NOUN'], sep='_'):
patterns = []
for pos in preceding_pos:
patterns.append(f"POS:{pos} POS:NOUN:+")
if textacy.__version__ < '0.11':
# as in book
spans = textacy.extract.matches(doc, patterns=patterns)
else:
# new textacy version
spans = textacy.extract.matches.token_matches(doc, patterns=patterns)
return [sep.join([t.lemma_ for t in s]) for s in spans]
text = "Studying NLP is really fun for smiling sammy."
doc = nlp(text)
print(*extract_noun_phrases(doc, ['VERB', 'ADJ', 'NOUN']), sep='|') # smile_sammy
# NLP는 고유명사로 인식이되어 제외됨
개체명 추출 (Name Entity Recognition; NER)
- 텍스트에서 사람 이름, 주소와 같은 개체를 감지하는 절차
- ent_type_, ent_iob_ 활용
- ent_type_: named entity recognizer로 예측된 토큰의 개체명 type
- ent_iob: 해당 토큰에서 개체가 시작(B), 개체의 일부분(I), 개체가 아닌 경우(O)
from spacy import displacy
text = "Warren Buffett seems to be the greatest investor in history in America."
doc = nlp(text)
for ent in doc.ents:
print(f"({ent.text}, {ent.label_})", end=" ") # (Warren Buffett, PERSON) (America, GPE)
displacy.render(doc, style='ent', jupyter=True)
대규모 데이터셋 적용
- GPU를 활용 가능
- 일괄 처리 기능을 사용하는 것이 좋음 -> nlp.pipe
- multiprocessing 라이브러리를 사용하여 파이썬 작업을 병렬화하는 것도 속도 향상에 도움이 됨
- pandas 작업 병렬화: Dask, Modin, Vaex를 권장
- pandas에 직접 병렬 적용 연산자를 추가: pandarallel
Reference
- textacy
- NLTK
- SymSpell
- ent_type_
- Multiprocessing
반응형
'AI > NLP' 카테고리의 다른 글
Chapter 6. 텍스트 분류 알고리즘 (0) | 2023.03.26 |
---|---|
Chapter 5. 특성 엔지니어링 및 구문 유사성 (0) | 2023.03.26 |
Chapter 3. 웹사이트 스크래핑 및 데이터 추출 (0) | 2023.03.26 |
Chapter 2. API로 추출하는 텍스트 속 통찰 (0) | 2023.03.26 |
Chapter 1. 텍스트 데이터에서 찾는 통찰 (0) | 2023.03.26 |
댓글