이번 포스팅에서는 토큰화의 정의와 유형, 주요 알고리즘과 토크나이저를 구축할 때 주의할 사항과 평가지표에 대해서 소개하겠습니다. 

 

1. 토큰화(Tokenization)이란 무엇인가? 

2. 서브워드 토큰화 알고리즘 (Subword Tokenization Algorithms)에는 무엇이 있나? 

3. 토크나이저 구축 시 주의할 점은 무엇인가?  

4. 토크나이저의 성능을 평가하는 지표에는 무엇이 있나? 

5. Hugging Face의 Tokenizers 모듈로 BPE tokenizer 구현해보기

 

 

1. 토큰화(Tokenization)이란 무엇인가? 

 

NLP(자연어 처리)에서 토큰화(Tokenization)는 텍스트를 더 작은 단위로 나누는 과정을 의미합니다. 이 작은 단위들을 '토큰(token)'이라고 부릅니다. 토큰은 단어, 문자, 구, 문장, 서브워드(Subword) 등 다양한 기준으로 나눌 수 있으며, 토큰화의 목적은 주로 텍스트 데이터를 분석하기 용이하게 전처리하는 것입니다.  

주어진 문장 "토큰화는 자연어처리를 하는데 있어 핵심적인 작업입니다"에 대한 다양한 토큰화 예시는 다음과 같습니다.  

- 문장 단위 토큰화 (Sentence tokenization):  ["토큰화는 자연어처리를 하는데 있어 핵심적인 작업입니다"]  
- 단어 단위 토큰화 (Word tokenization):  ["토큰화는", "자연어처리를", "하는데", "있어", "핵심적인", "작업입니다"]  
- 서브워드 단위 토근화 (Subword tokenization):  [["토큰", "화는", "자연어", "처리를", "하는데", "있어", "핵심", "적인", "작업", "입니다"]  
- 문자 단위 토큰화 (Character Tokenization): 토", "콘", "화", "는", " ", "자", "연", "어", "처", "리", "를", " ", "하", "는", "데", " ", "있", "어", " ", "핵", "심", "적", "인", " ", "작", "업", "입", "니", "다"]  


특히, Subword 토큰화는 텍스트를 더 작은 의미 단위로 나누는 방법에 초점을 맞추며, 이는 언어의 모호성을 줄이고, 모르는 단어(out-of-vocabulary, OOV) 문제를 해결하며, 언어 모델의 크기를 줄이는 데 도움이 됩니다. 

 

 

2. 서브워드 토큰화 알고리즘 (Subword Tokenization Algorithms)에는 무엇이 있나?  


주요 Subword 토큰화 알고리즘으로는 BPE, WordPiece, SentencePiece, Unigram Language Model 이 있습니다.  

 

토큰화 알고리즘

* 이미지 출처: https://blog.floydhub.com/tokenization-nlp/

 

 


(1) Byte Pair Encoding (BPE): BPE는 데이터 압축 알고리즘에서 유래되었으며, 가장 빈번하게 등장하는 바이트 쌍(most frequent pair of bytes)을 반복적으로 병합하여 텍스트를 토큰화합니다. NLP에서는 문자열 쌍을 병합하여 사용되며, 이 과정을 통해 공통적으로 나타나는 문자열 패턴을 효율적으로 인코딩할 수 있습니다. 

(2) WordPiece: WordPiece는 BPE와 유사하지만, 병합 과정에서 언어 모델의 가능성(likelihood)을 최대화하는 쌍을 선택합니다. 이는 주로 Google의 BERT 모델에서 사용됩니다.  

(3) SentencePiece: SentencePiece는 언어에 구애받지 않고 원시 텍스트를 직접 토큰화할 수 있게 해주는 알고리즘으로, 미리 정의된 언어나 문법 규칙에 의존하지 않습니다. 이는 BPE나 WordPiece와 같은 알고리즘을 포함하여, 텍스트를 바이트 레벨(Byte-level)에서 처리함으로써 언어의 다양성에 대응할 수 있습니다. 

(4) Unigram Language Model: Unigram 언어 모델은 가능한 모든 서브워드 토큰의 집합에서 시작하여, 각 토큰을 제거하는 것이 언어 모델의 확률(Probability)을 최소한으로 감소시키는 방식으로 토큰을 선택합니다. 이 방법은 토큰의 확률 분포를 기반으로 하며, 최종적으로 가장 유용한 서브워드 집합을 결정합니다. 

이러한 Subword 토큰화 방법들은 특히 다양한 언어와 도메인에 걸쳐 효율적인 자연어 이해를 가능하게 하는 데 중요한 역할을 합니다. 각각의 방법은 특정 상황이나 요구에 맞게 선택되며, NLP 모델의 성능과 효율성을 크게 향상시킬 수 있습니다. 

 

 

 

3. 토크나이저 구축 시 주의할 점은 무엇인가?  

 

토크나이저의 구축(Build a Tokenizer)은 자연어 처리(NLP)에서 텍스트 데이터를 사전 정의된 단위(토큰)로 분리하는 프로그램이나 알고리즘을 개발하는 과정을 의미합니다. 이러한 토큰은 단어, 문자, 문장 또는 서브워드(subword) 등이 될 수 있으며, 토큰화 과정은 텍스트 분석, 기계 번역, 감정 분석 등 다양한 NLP 작업의 기초를 형성합니다.  

토크나이저 구축 시 주의할 점으로는 다음과 같은 것들이 있습니다.  

(1) 언어의 특성 이해: 처리하려는 언어의 구문적, 의미적 특성을 이해하는 것이 중요합니다. 예를 들어, 공백으로 단어를 구분하는 언어(예: 영어)와 달리, 공백 없이 문자가 연속되는 언어(예: 중국어)는 다른 접근 방식을 요구합니다.  

(2) 도메인 특성 고려: 텍스트 데이터가 속한 도메인(예: 의료, 법률, 일상 대화)에 따라 사용되는 언어가 다를 수 있습니다. 전문 용어나 구어체 표현을 적절히 처리할 수 있는 토크나이저를 구축해야 합니다.  

(3) 성능과 정확도: 토크나이저의 성능과 정확도는 다운스트림 NLP 작업의 결과에 직접적인 영향을 미칩니다. 높은 정확도로 토큰을 식별하면서도, 처리 시간이 너무 길지 않도록 효율성을 고려해야 합니다.  

(4) 확장성과 유연성: 언어는 시간이 지남에 따라 변하고, 새로운 단어나 표현이 등장합니다. 따라서, 토크나이저는 새로운 데이터나 도메인에 쉽게 적용할 수 있도록 확장 가능하고 유연해야 합니다.  

(5) 다양한 토큰화 기법 고려: 단어, 문장, 문자, 서브워드 토큰화 등 다양한 토큰화 기법 중에서 목적에 가장 적합한 방법을 선택해야 합니다. 때로는 여러 기법을 조합하여 사용하는 것이 더 효과적일 수 있습니다.  

(6) 사전 및 사후 처리: 토큰화 과정에서 발생할 수 있는 문제(예: 구두점 처리, 대소문자 구분, 불용어 제거 등)를 해결하기 위해 적절한 사전 처리(pre-processing) 및 사후 처리(post-processing) 단계를 고려해야 합니다.  

(7) 평가 및 테스트: 개발한 토크나이저의 성능을 정확히 평가하기 위해 다양한 데이터 세트와 시나리오에서 테스트를 수행해야 합니다. 이를 통해 토크나이저의 강점과 약점을 파악하고 개선할 수 있습니다.  

토크나이저를 구축할 때 이러한 주의 사항을 고려하면, 다양한 언어와 도메인에 걸쳐 효과적으로 작동하는 강력하고 유연한 토크나이저를 개발할 수 있습니다.  

 

 

4. 토크나이저의 성능을 평가하는 지표에는 무엇이 있나? 

 

토크나이저 성능을 측정하는 데 있어서 "subword fertility (서브워드 다산성)", "proportion of continued words (연속된 단어의 비율)", 그리고 "coverage (커버리지)" 지표 등이 있습니다.  


(1) 서브워드 다산성(Subword Fertility): 이 지표는 하나의 고유 단어가 몇 개의 서브워드로 분해되는지를 나타냅니다. 예를 들어, 토크나이저가 단어를 너무 많은 작은 조각으로 나눈다면, 다산성이 높다고 할 수 있습니다. 이는 특정 언어나 도메인에서 토크나이저가 얼마나 세밀하게 단어를 분해하는지를 보여주는 지표로, 너무 높은 다산성은 처리해야 할 토큰의 수가 증가하여 성능 저하를 일으킬 수 있습니다.  

(2) 연속된 단어의 비율(Proportion of Continued Words): 이는 원본 텍스트에서 단어가 서브워드로 분해될 때, 연속적으로 나타나는 서브워드 조각들의 비율을 나타냅니다. 예를 들어, 하나의 단어가 여러 서브워드로 나뉘어 처리될 경우, 이러한 서브워드들이 원본 단어의 의미를 얼마나 잘 유지하고 있는지를 평가할 수 있습니다. 높은 비율은 토크나이저가 단어의 구조를 잘 보존하고 있다는 것을 의미할 수 있습니다.  

(3) 커버리지(Coverage): 커버리지는 토크나이저가 주어진 텍스트 데이터셋 내의 단어나 표현을 얼마나 잘 포착하는지를 나타내는 지표입니다. 높은 커버리지는 토크나이저가 대부분의 단어나 표현을 정확하게 인식하고 처리할 수 있음을 의미하며, 이는 특히 다양한 언어나 도메인에 걸쳐 토크나이저의 범용성을 평가하는 데 유용합니다. 커버리지가 낮다면, 토크나이저가 일부 단어나 표현을 놓치거나 잘못 처리할 가능성이 있음을 나타냅니다.  

이러한 지표들은 토크나이저의 성능을 다각도로 평가하고, 특정 언어나 도메인에 대한 토크나이저의 적합성을 결정하는 데 도움을 줍니다. 

이러한 지표들로 토크나이저 성능을 평가할 때, 트레이드오프를 균형 있게 고려하는 것이 중요합니다.   

예를 들어 서브워드 다산성(Subword fertility)와 계속되는 단어의 비율이 높은 토크나이저는 보이지 않거나 드문 단어들을 인식 가능한 서브워드로 분해함으로써 효과적으로 처리할 수 있을지도 모릅니다. 그러나, 이는 처리 과정의 비효율성으로 이어질 수 있고, 모델이 원래 단어의 전체 맥락이나 의미를 포착하는 능력을 저해할 수도 있습니다.  

높은 커버리지(Coverage)는 일반적으로 바람직하며, 이는 토크나이저가 입력 텍스트를 자신의 어휘로 효과적으로 표현할 수 있음을 의미합니다. 그러나, 매우 높은 커버리지를 달성하기 위해서는 큰 어휘 크기가 필요할 수 있으며, 이는 모델의 복잡성과 계산 요구사항을 증가시킬 수 있습니다.  

요약하자면, 토크나이저의 선택과 그 매개변수의 최적화는 애플리케이션의 특정 요구사항, 처리되는 언어(들)의 특성, 그리고 계산 제약 조건을 고려하여 결정해야 합니다. 이러한 지표들을 균형 있게 고려함으로써, Downstream NLP 작업을 효율적으로 지원하는 토크나이저를 개발하는 데 도움이 될 수 있습니다.  

 

 

 

5. Hugging Face의 Tokenizers 모듈로 BPE tokenizer 구현해보기

 

먼저, 터미널에서 pip install로 Hugging Face의 tokenizers 모듈을 설치합니다. 

 

! pip install -q tokenizers

 

 

 

- tokenizers 모듈의 Tokenizer, BepTrainer 메소드로 BPE tokenizer 훈련하기

 

매개변수로 unk_token (Unknown token), special_tokens 를 등록해줍니다. 

 

## Train the BPE tokenizer
from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.trainers import BpeTrainer
from tokenizers.pre_tokenizers import Whitespace

# Initialize a tokenizer with BPE model
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
tokenizer.pre_tokenizer = Whitespace()

# Initializer a trainer for the BPE model
trainer = BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])

# Sample corpus for training the tokenizer
corpus = [
    "This is an example of how BPE tokenization works.", 
    "BPE is an algorithm for subword tokenization", 
    "BPE tokenization works by repeatedly merging the most frequent pair of characters.", 
]

# Train the tokenizer
tokenizer.train_from_iterator(corpus, trainer)

# tokenizer.train(files=["your_dataset.txt"], trainer=trainer) # for files


tokenizer
# <tokenizers.Tokenizer at 0x1d153181b70>

 

 

일단 tokenizer의 학습이 완료되면, 아래처럼 학습된 tokenizer의 속성값에 접근할 수 있습니다. 

 

 

- BPE tokenizer의 vocab_size 접근해서 가져오기: get_vocab_size()

 

# Accessing the vocabulary size of the tokenizer
vocab_size = tokenizer.get_vocab_size()
print("Vocabulary size:", vocab_size)

# Vocabulary size: 111

 

 

- 학습된 tokenizer의 Vocaburary 에 접근해서 가져오기: get_vocab()

 

# Accessing the vocaburary
vocab = tokenizer.get_vocab()

# The 'vocab' variable is a dictionary where keys are tokens and values are token ids
print(vocab)

# {'z': 33, 'atio': 45, 'ar': 62, 'edl': 69, 'P': 8, 'oken': 42, 'p': 24, 'ken': 
# 41, 'characters': 109, 'Th': 57, 'B': 6, 'E': 7, 'tokenization': 49, 'am': 61, '.': 
# 5, 'ter': 86, 'peat': 81, 'BPE': 46, 'pair': 105, '[UNK]': 0, 'k': 19, 'frequent': 110, 
# 'e': 14, 'y': 32, 'works': 56, 'or': 34, 'repeat': 88, 'fre': 71, 'ample': 93, '[MASK]': 4, 
# 'th': 55, 'aracter': 94, 'example': 97, 'ex': 67, 'most': 103, 'l': 20, 'ks': 52, 'an': 50, 
# 'r': 26, 'h': 17, 'io': 38, 'iz': 40, 'for': 70, 'subword': 106, 'repeatedly': 107, 'b': 11, 
# 'is': 39, 'tokenizatio': 48, 'o': 23, 'u': 29, 'frequ': 99, 'mo': 77, 'wor': 44, 'gi': 72, 
# 'character': 96, 'izatio': 47, 'f': 15, 'w': 30, 'm': 21, 'ai': 59, 'ent': 87, 'er': 51, 
# '[PAD]': 3, 'ithm': 102, 'ho': 74, 'n': 22, 'qu': 83, 'edly': 98, 'merging': 104, 'en': 36, 
# 'algorithm': 108, 'pai': 80, 're': 54, 'ac': 58, 'token': 43, 'BP': 37, 'how': 101, 's': 27, 
# 'bwor': 64, 'le': 76, 'by': 63, 'd': 13, 'al': 60, 'ng': 79, 'acter': 91, 'gor': 73, 't': 28, 
# 'at': 35, 'su': 85, 'T': 9, 'st': 84, 'x': 31, 'of': 53, 'q': 25, '[SEP]': 2, 'eat': 68, 
# 'dl': 66, 'This': 90, 'algor': 92, 'bword': 95, 'the': 89, 'ith': 75, '[CLS]': 1, 'ch': 65, 
# 'i': 18, 'a': 10, 'ple': 82, 'c': 12, 'mer': 78, 'ging': 100, 'g': 16}

 

 

- tokenizer의 {token_id: token} 쌍 가져오기: vocab.items() 를 역변환

 

# You can get "token_id: token" pairs by inverting the vocab dictionary
id_to_token = {id: token for token, id in vocab.items()}

print(id_to_token)
# {33: 'z', 45: 'atio', 62: 'ar', 69: 'edl', 8: 'P', 42: 'oken', 24: 'p', 41: 'ken', 
# 109: 'characters', 57: 'Th', 6: 'B', 7: 'E', 49: 'tokenization', 61: 'am', 5: '.', 
# 86: 'ter', 81: 'peat', 46: 'BPE', 105: 'pair', 0: '[UNK]', 19: 'k', 110: 'frequent', 
# 14: 'e', 32: 'y', 56: 'works', 34: 'or', 88: 'repeat', 71: 'fre', 93: 'ample', 4: '[MASK]', 
# 55: 'th', 94: 'aracter', 97: 'example', 67: 'ex', 103: 'most', 20: 'l', 52: 'ks', 50: 'an', 
# 26: 'r', 17: 'h', 38: 'io', 40: 'iz', 70: 'for', 106: 'subword', 107: 'repeatedly', 11: 'b', 
# 39: 'is', 48: 'tokenizatio', 23: 'o', 29: 'u', 99: 'frequ', 77: 'mo', 44: 'wor', 72: 'gi', 
# 96: 'character', 47: 'izatio', 15: 'f', 30: 'w', 21: 'm', 59: 'ai', 87: 'ent', 51: 'er', 
# 3: '[PAD]', 102: 'ithm', 74: 'ho', 22: 'n', 83: 'qu', 98: 'edly', 104: 'merging', 36: 'en', 
# 108: 'algorithm', 80: 'pai', 54: 're', 58: 'ac', 43: 'token', 37: 'BP', 101: 'how', 27: 's', 
# 64: 'bwor', 76: 'le', 63: 'by', 13: 'd', 60: 'al', 79: 'ng', 91: 'acter', 73: 'gor', 28: 't', 
# 35: 'at', 85: 'su', 9: 'T', 84: 'st', 31: 'x', 53: 'of', 25: 'q', 2: '[SEP]', 68: 'eat', 
# 66: 'dl', 90: 'This', 92: 'algor', 95: 'bword', 89: 'the', 75: 'ith', 1: '[CLS]', 65: 'ch', 
# 18: 'i', 10: 'a', 82: 'ple', 12: 'c', 78: 'mer', 100: 'ging', 16: 'g'}

 


- {token_id: token} 쌍을 token_id 기준으로 오름차순 정렬해서 보기

 

# Sort id_to_token dictionary by IDs
print(sorted(id_to_token.items(), key=lambda x: x[0]))

# [(0, '[UNK]'), (1, '[CLS]'), (2, '[SEP]'), (3, '[PAD]'), (4, '[MASK]'), (5, '.'), (6, 'B'), 
# (7, 'E'), (8, 'P'), (9, 'T'), (10, 'a'), (11, 'b'), (12, 'c'), (13, 'd'), (14, 'e'), (15, 'f'), 
# (16, 'g'), (17, 'h'), (18, 'i'), (19, 'k'), (20, 'l'), (21, 'm'), (22, 'n'), (23, 'o'), 
# (24, 'p'), (25, 'q'), (26, 'r'), (27, 's'), (28, 't'), (29, 'u'), (30, 'w'), (31, 'x'), 
# (32, 'y'), (33, 'z'), (34, 'or'), (35, 'at'), (36, 'en'), (37, 'BP'), (38, 'io'), (39, 'is'), 
# (40, 'iz'), (41, 'ken'), (42, 'oken'), (43, 'token'), (44, 'wor'), (45, 'atio'), (46, 'BPE'), 
# (47, 'izatio'), (48, 'tokenizatio'), (49, 'tokenization'), (50, 'an'), (51, 'er'), (52, 'ks'), 
# (53, 'of'), (54, 're'), (55, 'th'), (56, 'works'), (57, 'Th'), (58, 'ac'), (59, 'ai'), 
# (60, 'al'), (61, 'am'), (62, 'ar'), (63, 'by'), (64, 'bwor'), (65, 'ch'), (66, 'dl'), 
# (67, 'ex'), (68, 'eat'), (69, 'edl'), (70, 'for'), (71, 'fre'), (72, 'gi'), (73, 'gor'), 
# (74, 'ho'), (75, 'ith'), (76, 'le'), (77, 'mo'), (78, 'mer'), (79, 'ng'), (80, 'pai'), 
# (81, 'peat'), (82, 'ple'), (83, 'qu'), (84, 'st'), (85, 'su'), (86, 'ter'), (87, 'ent'), 
# (88, 'repeat'), (89, 'the'), (90, 'This'), (91, 'acter'), (92, 'algor'), (93, 'ample'), 
# (94, 'aracter'), (95, 'bword'), (96, 'character'), (97, 'example'), (98, 'edly'), 
# (99, 'frequ'), (100, 'ging'), (101, 'how'), (102, 'ithm'), (103, 'most'), (104, 'merging'), 
# (105, 'pair'), (106, 'subword'), (107, 'repeatedly'), (108, 'algorithm'), (109, 'characters'), 
# (110, 'frequent')]

 

 

- 토큰이 Vocabulary 에 들어있는지 확인하기: tokenizer.token_to_id(token)

 

# Checking if a token is in the vocabulary
token_id = tokenizer.token_to_id("BPE")

if token_id is not None:
    print("Token 'BPE' is in the vocabulary with ID:", token_id)
else:
    print("Token 'BPE' is not in the vocabulary")
    
# Token 'BPE' is in the vocabulary with ID: 46    


id_to_token[46]
# 'BPE'

 

 

- Sepcial Tokens 와 ID 확인하기

: special_tokens = ["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]

 

# Accessing Special Tokens and their IDs
# Assuming the tokenizer has been trained or loaded with special tokens
special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"]

for special_token in special_tokens:
    special_token_id = tokenizer.token_to_id(special_token)
    print(f"{special_token} token ID: {special_token_id}")
    
# [UNK] token ID: 0
# [CLS] token ID: 1
# [SEP] token ID: 2
# [PAD] token ID: 3
# [MASK] token ID: 4

 

 

- 새로운 텍스트 토큰화하기: tokenizer.encode(new text)

 

# Tokenize a new text
output = tokenizer.encode("This is a new example to showcase BPE tokenization.")

# Print the tokens and their IDs
print("Tokens:", output.tokens)
print("Token IDs:", output.ids)

# Tokens: ['This', 'is', 'a', 'n', 'e', 'w', 'example', 't', 'o', 's', 'how', 'c', 'a', 's', 'e', 'BPE', 'tokenization', '.']
# Token IDs: [90, 39, 10, 22, 14, 30, 97, 28, 23, 27, 101, 12, 10, 27, 14, 46, 49, 5]

 

 

- 토큰 IDs를 디코딩하기: tokenizer.decode(token_ids)

 

# Decode token IDs reversely
tokenizer.decode(output.ids)

# 'This is a n e w example t o s how c a s e BPE tokenization .'

 

 

- 새로운 토큰을 토크나이저에 추가하기: tokenizer.add_tokens(new_tokens)

 

# Adding new tokens to a tokenizer
# To add new tokens to a tokenizer using the tokenizers library by Hugging Face, you can use the add_tokens method if you're working with a tokenizer that supports dynamic vocabulary modifications. This feature is particularly useful when you have out-of-vocabulary (OOV) tokens that you want to include in your tokenizer's vocabulary for better model performance on specific tasks or domains.

# 1. Install the Tokenizers Library: First, ensure that the tokenizers library is installed. You can install it using pip if you haven't already.
# 2. Load or Initialize Your Tokenizer: Load the tokenizer you wish to modify. This could be a pre-trained tokenizer or a custom one you've created.
# 3. Add New Tokens: Use the add_tokens method to add your new tokens to the tokenizer's vocabulary. The method typically requires a list of new tokens to be added.


# [case 1] Add new tokens to the trained tokenizer above
new_tokens = ["SentencePiece", "Unigram"]
tokenizer.add_tokens(new_tokens)

# Verify if the new tokens were added
# Tokenize a new text
output = tokenizer.encode("SentencePiece Unigram")

# Print the tokens and their IDs
print("Tokens:", output.tokens)
print("Token IDs:", output.ids)

# Tokens: ['SentencePiece', 'Unigram']
# Token IDs: [111, 112]

 

 

- 새로운 토큰을 Hugging Face Hub에 있는 토크나이저에 추가하기: tokenizer.add_tokens(new_tokens)

 

# [case 2] adding new tokens to pretrained tokenizer and model from Hugging Face Hub
# Let's see how to increase the vocabulary of Bert model and tokenizer
tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased")

num_added_toks = tokenizer.add_tokens(["new_tok1", "my_new-tok2"])
print("We have added", num_added_toks, "tokens")

# Notice: resize_token_embeddings expect to receive the full size of the new vocabulary, i.e., the length of the tokenizer.
model.resize_token_embeddings(len(tokenizer))

 

 

- 토크나이저를 직렬화, 역직렬화 (serialization and deserialization of tokenizer)

 

# Serialization and Deserialization
# Serialize tokenizer to string
tokenizer_str = tokenizer.to_str()

print(tokenizer_str)

# {"version":"1.0",
# "truncation":null,
# "padding":null,
# "added_tokens":[{"id":0,"content":"[UNK]","single_word":false,"lstrip":false,"rstrip":false,"normalized":false,"special":true},
# {"id":1,"content":"[CLS]","single_word":false,"lstrip":false,"rstrip":false,"normalized":false,"special":true},{"id":2,"content":"[SEP]","single_word":false,"lstrip":false,"rstrip":false,"normalized":false,"special":true},{"id":3,"content":"[PAD]","single_word":false,"lstrip":false,"rstrip":false,"normalized":false,"special":true},{"id":4,"content":"[MASK]","single_word":false,"lstrip":false,"rstrip":false,"normalized":false,"special":true}],"normalizer":null,
# "pre_tokenizer":{"type":"Whitespace"},
# "post_processor":null,"decoder":null,
# "model":{"type":"BPE","dropout":null,"unk_token":"[UNK]","continuing_subword_prefix":null,"end_of_word_suffix":null,"fuse_unk":false,
# "vocab":{"[UNK]":0,"[CLS]":1,"[SEP]":2,"[PAD]":3,"[MASK]":4,".":5,"B":6,"E":7,"P":8,"T":9,"a":10,"b":11,"c":12,"d":13,"e":14,"f":15,"g":16,"h":17,"i":18,"k":19,"l":20,"m":21,"n":22,"o":23,"p":24,"q":25,"r":26,"s":27,"t":28,"u":29,"w":30,"x":31,"y":32,"z":33,"or":34,"at":35,"en":36,"BP":37,"io":38,"is":39,"iz":40,"ken":41,"oken":42,"token":43,"wor":44,"atio":45,"BPE":46,"izatio":47,"tokenizatio":48,"tokenization":49,"an":50,"er":51,"ks":52,"of":53,"re":54,"th":55,"works":56,"Th":57,"ac":58,"ai":59,"al":60,"am":61,"ar":62,"by":63,"bwor":64,"ch":65,"dl":66,"ex":67,"eat":68,"edl":69,"for":70,"fre":71,"gi":72,"gor":73,"ho":74,"ith":75,"le":76,"mo":77,"mer":78,"ng":79,"pai":80,"peat":81,"ple":82,"qu":83,"st":84,"su":85,"ter":86,"ent":87,"repeat":88,"the":89,"This":90,"acter":91,"algor":92,"ample":93,"aracter":94,"bword":95,"character":96,"example":97,"edly":98,"frequ":99,"ging":100,"how":101,"ithm":102,"most":103,"merging":104,"pair":105,"subword":106,"repeatedly":107,"algorithm":108,"characters":109,"frequent":110},
# "merges":["o r","a t","e n","B P","i o","i s","i z","k en","o ken","t oken","w or","at io","BP E","iz atio","token izatio","tokenizatio n","a n","e r","k s","o f","r e","t h","wor ks","T h","a c","a i","a l","a m","a r","b y","b wor","c h","d l","e x","e at","e dl","f or","f re","g i","g or","h o","i th","l e","m o","m er","n g","p ai","p eat","p le","q u","s t","s u","t er","en t","re peat","th e","Th is","ac ter","al gor","am ple","ar acter","bwor d","ch aracter","ex ample","edl y","fre qu","gi ng","ho w","ith m","mo st","mer ging","pai r","su bword","repeat edly","algor ithm","character s","frequ ent"]}}

 

 

- 토크나이저를 저장하기 로딩하기: tokenizer.save(), tokenizer.from_file()

 

## Saving and Loading tokenizer

# Save it to a file
tokenizer.save("./tokenizer.json")


import os

print("Current working directory:", os.getcwd())
print("File list at current directory:", os.listdir(os.getcwd()))

# Current working directory: C:\Users\Documents\BPE-Tokenizer
# File list at current directory: ['BPE-subword-tokenization.ipynb', 'tokenizer.json']



# Load the saved Tokenizer JSON file back
tokenizer = tokenizer.from_file("./tokenizer.json")

print("Vocabulary size:", tokenizer.get_vocab_size())

# Vocabulary size: 111

 

 

 

- Hugging Face Hub에서 AutoTokenizer 메소드를 사용해 이미 훈련이 된 모델의 tokenizer 사용하기 

 

# Using Pre-trained tokenization from the Hugging Face Hub
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# Accessing tokenizer attributes
vocab_size = tokenizer.vocab_size
print("Vocabulary size:", vocab_size)

# Vocabulary size: 30522


# Special tokens
print("PAD token:", tokenizer.pad_token)
print("PAD token ID:", tokenizer.pad_token_id)

# PAD token: [PAD]
# PAD token ID: 0

 

 

[ Reference ]

1. "Tokenizers: How Machines Read" by Cathal Horan: https://blog.floydhub.com/tokenization-nlp/

2. "Summary of the tokenizers" from Hugging Face: 
https://huggingface.co/docs/transformers/tokenizer_summary

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

 

728x90
반응형
Posted by Rfriend
,

토큰화, 단어 임베딩, 텍스트 임베딩은 자연어 처리(NLP) 및 기계 학습에서 텍스트 데이터를 표현하고 처리하는 데 사용되는 개념입니다. 이러한 개념들은 감정 분석, 기계 번역, 텍스트 분류와 같은 NLP 작업에서 중요하며, 기계 학습 모델이 이해하고 학습할 수 있는 형태로 텍스트 정보를 표현하고 처리하는 데 사용됩니다.

 

이번 포스팅에서는 토근화(Tokenization), 단어 임베딩 (Word Embedding), 텍스트 임베딩 (Text Embedding)에 대해서 소개하겠습니다. 그리고 transformers 와 PyTorch 를 이용하여 실습을 해보겠습니다. 

 

tokenization, word embedding, text embedding

 


1. 토큰화 (Tokenization)

 

- 정의: 토큰화는 텍스트를 토큰이라 불리는 더 작은 단위로 분해하는 과정입니다. 이러한 토큰은 단어, 서브워드 또는 문자일 수 있으며 원하는 정밀도 수준에 따라 다릅니다.

- 목적: 토큰화는 NLP에서 중요한 전처리 단계로, 기계가 텍스트의 개별 요소를 이해하고 처리할 수 있게 합니다. 토큰은 후속 분석을 위한 구성 요소로 작용합니다.

 

-- Install transformers, torch, sentence-transformers at terminal at first 

pip install -q transformers
pip install -q torch
pip install -q -U sentence-transformers

 

# 1. Tokenization 
# : Tokenization is the process of breaking down a text into smaller units called tokens. 
# : These tokens can be words, subwords, or characters, depending on the level of granularity desired.

from transformers import AutoTokenizer

# Load pre-trained DistilBERT tokenizer
tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased')

# Example text
text = "Love is wanting to be loved"

# Tokenize the text
input_ids = tokenizer.encode(text)
tokens = tokenizer.tokenize(tokenizer.decode(input_ids))

print("Input IDs:", input_ids)
print("-------" * 10)
print("Tokens:", tokens)

# Input IDs: [101, 2293, 2003, 5782, 2000, 2022, 3866, 102]
# ----------------------------------------------------------------------
# Tokens: ['[CLS]', 'love', 'is', 'wanting', 'to', 'be', 'loved', '[SEP]']

 

 


2. 단어 임베딩 (Word Embedding)

 

- 정의: 단어 임베딩은 단어를 연속적인 벡터 공간의 실수로 이루어진 밀도 있는 벡터로 나타내는 기술입니다. 각 단어는 벡터로 매핑되며 이러한 벡터 간의 거리와 방향이 의미를 가집니다.

- 목적: 단어 임베딩은 단어 간의 의미적 관계를 포착하여 기계가 주어진 텍스트의 맥락과 의미를 이해할 수 있게 합니다. 단어가 맥락과 의미가 유사한 경우 단어 임베딩 벡터가 서로 가깝게 위치하는 특성이 있어 semantic search에 유용하게 활용됩니다. 유명한 단어 임베딩 모델로는 Word2Vec, GloVe, FastText가 있습니다. 

 

# 2. Word Embedding
# : Word embedding is a technique that represents words 
#   as dense vectors of real numbers in a continuous vector space. 
# : Each word is mapped to a vector, and the distances and directions 
#   between these vectors carry semantic meaning.

from transformers import AutoTokenizer, AutoModel
import torch

# Load pre-trained DistilBERT model
tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased')
model = AutoModel.from_pretrained('distilbert-base-uncased')

# Encode the tokens to obtain word embeddings
input_ids = tokenizer.encode(text, return_tensors='pt')
with torch.no_grad():
    word_embeddings = model(input_ids)[0]

print("Tensor Size:", word_embeddings.size())
print("------" * 10)
print("Word Embeddings:")
print(word_embeddings)
# Tensor Size: torch.Size([1, 8, 768])
# ------------------------------------------------------------
# Word Embeddings: 
#   tensor([[
#          [-0.1067, -0.0101, -0.0897,  ..., -0.1721,  0.2134,  0.3274],
#          [ 0.8698,  0.1002,  0.2687,  ..., -0.3276,  0.4205,  0.1344],
#          [-0.1877, -0.0777,  0.1905,  ..., -0.0220,  0.0024,  0.5138],
#          ...,
#          [ 0.5998, -0.2141,  0.3774,  ..., -0.3945, -0.1149,  0.1245],
#          [ 1.1550, -0.1050,  0.3570,  ..., -0.4063, -0.0489, -0.0717],
#          [ 1.0036,  0.1886, -0.4508,  ...,  0.0999, -0.5486, -0.3076]]])

 


3. 텍스트 임베딩 (Text Embedding)

 

- 정의: 텍스트 임베딩은 문장(sentences)이나 문서(documents) 전체를 밀도 있는 벡터로 나타내어 전체 텍스트의 전반적인 의미를 캡처하는 기술입니다. 단어 임베딩을 집계하거나 요약하여 전체 텍스트의 표현을 만듭니다. 

- 목적: 텍스트 임베딩은 전체 문서나 문장을 의미적 공간에서 비교하고 분석할 수 있게 합니다. 텍스트 임베딩을 생성하는 방법에는 단어 임베딩의 평균(averaging word embeddings)을 사용하거나 순환 신경망(RNN), 장·단기 기억 네트워크(LSTM), 트랜스포머(Transformers)를 사용하는 방법 등이 있습니다. 

 

텍스트 임베딩은 

 - 텍스트 분류 (Text Classification),

 - 감성분석 (Sentiment Analysis),

 - 검색 엔진 랭킹 (Search Engine Ranking),

 - 군집 및 유사도 분석 (Clustering and Similarity Analysis),

 - 질의 응답 (Question Answering, 질문과 답변을 임베딩으로 표현함으로써 시스템은 쿼리의 의미 콘텐츠와 데이터셋의 관련 정보를 정확하게 검색할 수 있음)

 

등에 활용할 수 있습니다. 

text embedding 을 하는 방법에는 (1) transformers 를 이용한 방법과, (2) sentence-transfomers 모델을 이용하는 방법이 있습니다. sentence-transformers 모델을 이용하는 방법이 코드가 간결합니다. 

 

 

3-1. transformers 를 이용한 text embedding

# 3. Text Embedding
# : Text embedding represents entire sentences or documents as dense vectors, 
#   capturing the overall meaning of the text. 
# : It involves aggregating or summarizing word embeddings 
#   to create a representation for the entire text.

from transformers import AutoTokenizer, AutoModel
import torch
import torch.nn.functional as F

#Mean Pooling - Take attention mask into account for correct averaging
def mean_pooling(model_output, attention_mask):
    token_embeddings = model_output[0] #First element of model_output contains all token embeddings
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)


# Sentences we want sentence embeddings for
# Example sentence
text = "Love is wanting to be loved"

# Load model from HuggingFace Hub
tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased')
model = AutoModel.from_pretrained('distilbert-base-uncased')

# Tokenize sentences
encoded_input = tokenizer(text, padding=True, truncation=True, return_tensors='pt')

# Compute token embeddings
with torch.no_grad():
    model_output = model(**encoded_input)

# Perform pooling
sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])

# Normalize embeddings
sentence_embeddings = F.normalize(sentence_embeddings, p=2, dim=1)

print("Tensor Size", sentence_embeddings.size())
print("--------" * 10)
print("Sentence embeddings:")
print(sentence_embeddings)

# Tensor Size torch.Size([1, 768])
# --------------------------------------------------------------------------------
# Sentence embeddings:
# tensor([[ 7.1203e-02, -9.0556e-03,  2.0404e-02, -5.4984e-03,  5.3534e-02,
#          -2.7214e-02,  2.7177e-02,  5.1983e-02, -1.1366e-02, -4.1719e-02,
#              :             :           :           :             :
#           2.5733e-02, -2.1918e-02,  5.2480e-03, -5.7470e-04,  1.4644e-02,
#          -1.8896e-02, -4.5600e-03,  1.4625e-02]])

 

 

 

3-2. sentence-transformers 모델을 이용한 text embedding

: 'all-mpnet-base-v2' 모델을 HuggingFace에서 다운로드 하여 사용

 

sentence-transformers 모델에 대한 설명은 https://huggingface.co/sentence-transformers 를 참고하세요. 

 

# ! pip install -q -U sentence-transformers


# Text embedding by sentence-transformers model
# reference: https://huggingface.co/sentence-transformers/all-mpnet-base-v2
from sentence_transformers import SentenceTransformer

text = "Love is wanting to be loved"

model = SentenceTransformer('sentence-transformers/all-mpnet-base-v2')
text_embedding = model.encode(text)

print("Tensor Shape:", text_embedding.shape)
print("------" * 10)
print("Text Embedding:")
print(text_embedding)

# Tensor Shape: (768,)
# ------------------------------------------------------------
# Text Embedding:
# [ 7.25340098e-02 -3.43943425e-02  3.50002125e-02 -1.46801360e-02
#   1.79491900e-02  5.70273288e-02 -9.77409929e-02  2.65225749e-02
#      :               :               :               :
#   -6.68407883e-03  1.09006204e-02 -1.37606068e-02 -4.93713543e-02
#   3.27182375e-02  5.77081088e-03  4.32791896e-02 -1.55460704e-02]

 

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python을 사용해서 

 

(1) 텍스트 데이터 전처리 (text data pre-processing)

(2) 토큰화 (tokenization)

 

하는 방법을 소개하겠습니다. 

 

 

(1) 텍스트 데이터 전처리 (text data pre-processing)

 

텍스트 데이터 전처리를 하는데는 (a) Python의 텍스트 처리 내장 메소드 (Python built-in methods)와 (b) 정규 표현식 매칭 연산(regular expression matching operations)을 제공하는 Python re 패키지를 사용하겠습니다. re 패키지는 Python을 설치할 때 디폴트로 같이 설치가 되므로 별도로 설치할 필요는 없습니다. 

 

예제로 사용할 Input 텍스트는 인터넷쇼핑몰의 고객별 거래내역에 있는 구매 품목 텍스트 데이터이며, Output 은 텍스트 전처리 후의 고객별 구매 품목의 리스트입니다. 

 

예) Input: '**[세일]** 말티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건'

예) Output: [말티즈, 강아지사료, 습식, 소프트]

 

[ 텍스트 데이터 전처리 절차 ]

    (1-1) [], (), {}, <> 괄호와 괄호 안 문자 제거하기

    (1-2) '...외', '...총' 제거하기

    (1-3) 특수문자, 숫자 제거

    (1-4) 단위 제거: cm, km, etc.

    (1-5) 공백 기준으로 분할하기

    (1-6) 글자 1개만 있으면 제외하기

    (1-7) 텍스트 데이터 전처리 사용자 정의함수(User Defined Function) 정의 

    (1-8) pandas DataFrame의 텍스트 칼럼에 데이터 전처리 사용자 정의함수 적용

 

 

(1-1) [], (), {}, <> 괄호와 괄호 안 문자 제거하기

 

Python의 정규 표현식(regular expression)을 다루는 re 패키지를 사용해서 다양한 형태의 괄호와 괄호안의 문자를 매칭한 후에 '' 로 대체함으로써 결과적으로 제거하였습니다. re.sub() 는 pattern 과 매치되는 문자열을 repl 의 문자열로 대체를 시켜줍니다. 

 

정규표현식에서 문자 클래스를 만드는 메타 문자인 [ ] 로 만들어지는 정규표현식은 [ ]사이에 들어가는 문자 중 어느 한개라도 매치가 되면 매치를 시켜줍니다. 가령, [abc] 의 경우 'a', 'b', 'c' 중에서 어느 하나의 문자라도 매치가 되면 매치가 되는 것으로 간주합니다. 

 

## Python Regular expression operations
import re

## sample text
s = '**[세일]** 말티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건'


## (1-1) [], (), {}, <> 괄호와 괄호 안 문자 제거하기
pattern = r'\([^)]*\)'  # ()
s = re.sub(pattern=pattern, repl='', string=s)

pattern = r'\[[^)]*\]'  # []
s = re.sub(pattern=pattern, repl='', string=s)

pattern = r'\<[^)]*\>'  # <>
s = re.sub(pattern=pattern, repl='', string=s)

pattern = r'\{[^)]*\}'  # {}
s = re.sub(pattern=pattern, repl='', string=s)

print(s)
[Out] 
# **** 말티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건

 

 

 

(1-2) '...외', '...총' 제거하기

 

Python의 내장 문자열 메소드인 replace() 를 사용해서 '...외', '...총' 을 ' ' 로 대체함으로써 제거하였습니다. 

 

## (1-2) '...외', '...총' 제거하기
s = s.replace('...외', ' ')
s = s.replace('...총', ' ')

print(s)
[Out]
# **** 말티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!! 5건

 

 

 

(1-3) 특수문자, 숫자 제거

 

정규표현식에서 하이픈(-)은 from ~ to 의 범위를 나타냅니다. [a-zA-Z] 는 소문자와 대문자 영어 모두를 의미하며, [가-힣] 은 한글 전체를 의미합니다. 

 

정규표현식에서 [^] 는 not 의 의미이며, 아래의 [^a-zA-Z가-힣] 은 앞에 '^' 가 붙었으므로 영어와 한글이 아닌(not, ^) 문자, 즉 특수문자와 숫자와 매칭이 됩니다. 

 

## (1-3) 특수문자, 숫자 제거
pattern = r'[^a-zA-Z가-힣]'
s = re.sub(pattern=pattern, repl=' ', string=s)

print(s)
[Out] 
# 말티즈 강아지사료 습식 소프트 신  종   Kg       원    건

 

 

 

(1-4) 단위 제거: cm, km, etc.

 

## (1-4) 단위 제거: cm, km, etc.
units = ['mm', 'cm', 'km', 'ml', 'kg', 'g']
for unit in units:
    s = s.lower() # 대문자를 소문자로 변환
    s = s.replace(unit, '')
    
print(s)
[Out] 
# 말티즈 강아지사료 습식 소프트 신  종          원    건

 

 

 

(1-5) 공백 기준으로 분할하기

 

Python 내장형 문자열 메소드인 split() 을 사용해서 공백(space)을 기준으로 문자열을 분할하였습니다. 

 

## (1-5) 공백 기준으로 분할하기
s_split = s.split()

print(s_split)
[Out] 
# ['말티즈', '강아지사료', '습식', '소프트', '신', '종', '원', '건']

 

 

 

(1-6) 글자 1개만 있으면 제외하기

 

글자 길이가 1 보다 큰 (len(word) != 1) 글자만 s_list 의 리스트에 계속 추가(append) 하였습니다. 

 

## (1-6) 글자 1개만 있으면 제외하기
s_list = []
for word in s_split:
    if len(word) !=1:
        s_list.append(word)
        
print(s_list)
[Out] 
# ['말티즈', '강아지사료', '습식', '소프트']

 

 

 

(1-7) 텍스트 데이터 전처리 사용자 정의함수(User Defined Function) 정의 

 

위의 (1-1) ~ (1-6) 까지의 텍스트 전처리 과정을 아래에 사용자 정의함수로 정의하였습니다. 문자열 s 를 input으로 받아서 텍스트 전처리 후에 s_list 의 단어들을 분할해서 모아놓은 리스트를 반환합니다. 

 

## 텍스트 전처리 사용자 정의함수(UDF of text pre-processing)
def text_preprocessor(s):
    import re
    
    ## (1) [], (), {}, <> 괄호와 괄호 안 문자 제거하기
    pattern = r'\([^)]*\)'  # ()
    s = re.sub(pattern=pattern, repl='', string=s)
    
    pattern = r'\[[^)]*\]'  # []
    s = re.sub(pattern=pattern, repl='', string=s)
    
    pattern = r'\<[^)]*\>'  # <>
    s = re.sub(pattern=pattern, repl='', string=s)
    
    pattern = r'\{[^)]*\}'  # {}
    s = re.sub(pattern=pattern, repl='', string=s)
    
    ## (2) '...외', '...총' 제거하기
    s = s.replace('...외', ' ')
    s = s.replace('...총', ' ')
    
    ## (3) 특수문자 제거
    pattern = r'[^a-zA-Z가-힣]'
    s = re.sub(pattern=pattern, repl=' ', string=s)
    
    ## (4) 단위 제거: cm, km, etc.
    units = ['mm', 'cm', 'km', 'ml', 'kg', 'g']
    for unit in units:
        s = s.lower() # 대문자를 소문자로 변환
        s = s.replace(unit, '')
        
    # (5) 공백 기준으로 분할하기
    s_split = s.split()
    
    # (6) 글자 1개만 있으면 제외하기
    s_list = []
    for word in s_split:
        if len(word) !=1:
            s_list.append(word)
            
    return s_list
    

## sample text
s = '**[세일]** 말티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건'

## apply the UDF above
s_list = text_preprocessor(s)
print(s_list)
[Out] 
# ['말티즈', '강아지사료', '습식', '소프트']

 

 

 

(1-8) pandas DataFrame의 텍스트 칼럼에 데이터 전처리 사용자정의함수 적용

 

pandas DataFrame에 위의 (1-7) 텍스트 전처리 사용자 정의함수를 적용하기 위해서는 apply() 와 lambda function 을 사용합니다. 

 

## pandas DataFrame
import pandas as pd

s1 = '**[세일] 몰티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건'
s2 = '[시크루즈] 50%+추가20%/여름신상 루즈핏 롱원피스/상하세트/점프슈트...외3건'
s3 = '올챌린지 KF94 마스크 100매 국내생산 여름용 황사 화이트...총2건'
s4 = '[최대혜택가] ##하림 용가리치킨 300gX3봉 외 닭가슴살/튀김 골라담기...외12건'
s5 = '[20%+15%] 종아리알 타파! 무로 요가링/마사지릴/압박스타킹/마사지볼...외4종'

df = pd.DataFrame({
    'id': [1, 2, 3, 4, 5], 
    'items': [s1, s2, s3, s4, s5]
})

print(df)
[Out]
#    id                                              items
# 0   1  **[세일] 몰티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건
# 1   2     [시크루즈] 50%+추가20%/여름신상 루즈핏 롱원피스/상하세트/점프슈트...외3건
# 2   3           올챌린지 KF94 마스크 100매 국내생산 여름용 황사 화이트...총2건
# 3   4   [최대혜택가] ##하림 용가리치킨 300gX3봉 외 닭가슴살/튀김 골라담기...외12건
# 4   5    [20%+15%] 종아리알 타파! 무로 요가링/마사지릴/압박스타킹/마사지볼...외4종


## Apply the text preprocessing UDF using apply() and lambda function
df['items_list'] = df['items'].apply(lambda s: text_preprocessor(s))


print(df['items'])
print('-------------'*5)
print(df['items_list'])
[Out]
# 0    **[세일] 몰티즈 강아지사료 습식 소프트 신 3종 15Kg 39,000원!!...외5건
# 1       [시크루즈] 50%+추가20%/여름신상 루즈핏 롱원피스/상하세트/점프슈트...외3건
# 2             올챌린지 KF94 마스크 100매 국내생산 여름용 황사 화이트...총2건
# 3     [최대혜택가] ##하림 용가리치킨 300gX3봉 외 닭가슴살/튀김 골라담기...외12건
# 4      [20%+15%] 종아리알 타파! 무로 요가링/마사지릴/압박스타킹/마사지볼...외4종
# Name: items, dtype: object
# -----------------------------------------------------------------
# 0                     [몰티즈, 강아지사료, 습식, 소프트]
# 1         [추가, 여름신상, 루즈핏, 롱원피스, 상하세트, 점프슈트]
# 2       [올챌린지, kf, 마스크, 국내생산, 여름용, 황사, 화이트]
# 3               [하림, 용가리치킨, 닭가슴살, 튀김, 골라담기]
# 4    [종아리알, 타파, 무로, 요가링, 마사지릴, 압박스타킹, 마사지볼]
# Name: items_list, dtype: object

 

 

 

위에 Jupyter Notebook 에서 pandas DataFrame을 출력한 결과가 중앙 정렬로 되어있어서 보기가 불편한데요, 아래처럼 좌측 정렬 (left alignment) 을 해서 보기에 편하도록 해보았습니다. 

 

## align text of pandas DataFrame to left in Jupyter Notebook
dfStyler = df.style.set_properties(**{'text-align': 'left'})
dfStyler.set_table_styles([dict(selector='th', props=[('text-align', 'left')])])

text preprocessing using regular expressions

 

 

 

(2) 토큰화 (tokenization)

 

토큰화(Tokenization)는 말뭉치(Corpus)를 토큰이라고 불리는 단어 또는 문장으로 나누는 것을 말합니다. 이러한 토큰은 문맥(Context)을 이해하거나 NLP에 대한 모델을 개발하는 데 사용됩니다. 

 

POS 태킹 (Part-of-Speech Tagging) 은 널리 사용되는 자연어 처리 프로세스로, 단어의 정의와 문맥에 따라 언어의 특정 부분에 대응하여 텍스트(corpus)의 단어를 분류하는 것을 말합니다.

 

아래 코드는 위 (1)번의 텍스트 전처리에 이어서, 띄어쓰기가 제대로 되지 않아서 붙어 있는 단어들을, Python KoNLpy 패키지를 사용해서 형태소 분석의 명사를 기준으로 단어 토근화를 한 것입니다. ((2)번 words_tokonizer() UDF 안에 (1)번 text_preprocessor() UDF가 포함되어 있으며, 순차적으로 수행됩니다.)

 

KoNLpy 패키지는 Python으로 한국어 자연어 처리(NLP) 을 할 수 있게 해주는 패키지입니다. 그리고 Kkma 는 서울대학교의 IDS 랩에서 JAVA로 개발한 형태소 분석기(morphological analyzer)입니다.  

 

## insatll konlpy if it is not istalled yet
# ! pip install konlpy


## KoNLpy : NLP of the Korean language
## reference ==> https://konlpy.org/en/latest/
## Kkma is a morphological analyzer 
## and natural language processing system written in Java, 
## developed by the Intelligent Data Systems (IDS) Laboratory at SNU.
from konlpy.tag import Kkma


## define words tokenizer UDF
def words_tokonizer(text):
    from konlpy.tag import Kkma # NLP of the Korean language
    kkma = Kkma()
    
    words = []
    
    # Text preprocessing using the UDF above
    s_list = text_preprocessor(text)
    
    # POS tagging
    for s in s_list:
        words_ = kkma.pos(s)   
        
        # NNG indexing
        for word in words_:
            if word[1] == 'NNG':
                words.append(word[0])
            
    return words
    
    
## apply the UDF above as an example
words_tokonizer('강아지사료')
[Out] ['강아지', '사료']


words_tokonizer('상하세트')
[Out] ['상하', '세트']

 

 

위의 (2) words_tokenizer() UDF를 pandas DataFrame에 적용하기 위해서 apply() 함수와 lambda function 을 사용하면 됩니다. 

 

## apply the text tokenization UDF to pandas DataFrame using apply() and lambda function
df['items'].apply(lambda text: words_tokonizer(text))

[Out]
# 0 [몰티즈, 강아지, 사료, 습식, 소프트]
# 1 [추가, 여름, 신상, 루즈, 핏, 원피스, 상하, 세트, 점프, 슈트]
# 2 [챌린지, 마스크, 국내, 생산, 여름, 황사, 화이트]
# 3 [하림, 용가리, 치킨, 닭, 가슴살, 튀김]
# 4 [종아리, 타파, 무로, 요가, 링, 마사지, 압박, 스타, 킹, 마사지]
# Name: items, dtype: object

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요! :-)

 

728x90
반응형
Posted by Rfriend
,