トークナイゼーションの基礎
「テキストデータをモデルに入力する前に、まず文を”トークン”に分割する必要がある。この前処理がNLPの精度を大きく左右する。」
田中VPoEがサンプルの問い合わせテキストを指差す。
「英語と日本語では分割方法が異なる。両方のアプローチを押さえておこう。」
トークナイゼーションとは
テキストを意味のある最小単位(トークン)に分割する処理。機械学習モデルにテキストを入力するための最初のステップである。
英語のトークナイゼーション
英語はスペースで区切られているため、基本的な分割は容易。
import nltk
from nltk.tokenize import word_tokenize
# 基本的な分割
text = "My order hasn't arrived yet. Can you check the delivery status?"
tokens = word_tokenize(text)
print(tokens)
# ['My', 'order', 'has', "n't", 'arrived', 'yet', '.', 'Can', 'you',
# 'check', 'the', 'delivery', 'status', '?']
日本語のトークナイゼーション
日本語はスペースで区切られていないため、形態素解析器が必要。
# MeCabを使った形態素解析
import MeCab
tagger = MeCab.Tagger("-Owakati")
text = "注文した商品がまだ届きません。配送状況を教えてください。"
tokens = tagger.parse(text).strip().split()
print(tokens)
# ['注文', 'し', 'た', '商品', 'が', 'まだ', '届き', 'ませ', 'ん', '。',
# '配送', '状況', 'を', '教え', 'て', 'ください', '。']
# Janomeを使った形態素解析(インストールが簡単)
from janome.tokenizer import Tokenizer
t = Tokenizer()
tokens = [token.surface for token in t.tokenize(text)]
print(tokens)
# ['注文', 'し', 'た', '商品', 'が', 'まだ', '届き', 'ませ', 'ん', '。',
# '配送', '状況', 'を', '教え', 'て', 'ください', '。']
サブワードトークナイゼーション
BERT以降のモデルでは、サブワード(単語の一部分)に分割する手法が主流。未知語に対応できるのが大きな利点。
BPE(Byte Pair Encoding)
from transformers import AutoTokenizer
# BERTのトークナイザ
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
text = "My order hasn't arrived yet."
tokens = tokenizer.tokenize(text)
print(tokens)
# ['my', 'order', 'hasn', "'", 't', 'arrived', 'yet', '.']
# 日本語BERTのトークナイザ
tokenizer_ja = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese")
text_ja = "注文した商品がまだ届きません"
tokens_ja = tokenizer_ja.tokenize(text_ja)
print(tokens_ja)
# ['注文', 'し', 'た', '商品', 'が', 'まだ', '届き', 'ませ', 'ん']
サブワードの利点
# 未知語への対応例
text = "ChatGPTによるカスタマーサポート自動化"
tokens = tokenizer_ja.tokenize(text)
print(tokens)
# サブワードに分割されるため、未知語でも処理可能
# 例: ['Chat', '##G', '##PT', 'による', 'カスタマー', 'サポート', '自動', '化']
テキスト前処理パイプライン
トークナイゼーションの前後に行う前処理も重要。
import re
import unicodedata
def preprocess_text(text):
"""テキスト前処理パイプライン"""
# 1. Unicode正規化
text = unicodedata.normalize('NFKC', text)
# 2. 小文字化(英語テキストの場合)
text = text.lower()
# 3. URL除去
text = re.sub(r'https?://\S+', '', text)
# 4. メールアドレス除去
text = re.sub(r'\S+@\S+', '', text)
# 5. 注文番号の正規化
text = re.sub(r'[A-Z]{2}-\d{8}-\d{4}', '[ORDER_ID]', text)
# 6. 余分な空白の除去
text = re.sub(r'\s+', ' ', text).strip()
return text
# 前処理の実行例
sample = "注文番号NS-20260215-1234の商品が届きません!!\n\n詳細はhttps://example.comを確認"
print(preprocess_text(sample))
# 注文番号[order_id]の商品が届きません!! 詳細はを確認
ストップワード除去
意味のない(機能的な)単語を除去することで、重要な単語にフォーカスする。
# 英語のストップワード除去
from nltk.corpus import stopwords
stop_words = set(stopwords.words('english'))
text = "Can you please check the delivery status of my order"
tokens = word_tokenize(text.lower())
filtered = [t for t in tokens if t not in stop_words and t.isalpha()]
print(filtered)
# ['please', 'check', 'delivery', 'status', 'order']
# 日本語の助詞・助動詞除去
def remove_stopwords_ja(text):
"""日本語のストップワード除去"""
t = Tokenizer()
tokens = []
for token in t.tokenize(text):
part_of_speech = token.part_of_speech.split(',')[0]
# 名詞、動詞、形容詞のみ保持
if part_of_speech in ['名詞', '動詞', '形容詞']:
tokens.append(token.surface)
return tokens
text_ja = "注文した商品がまだ届きません"
print(remove_stopwords_ja(text_ja))
# ['注文', '商品', '届き']
まとめ
| 項目 | ポイント |
|---|---|
| トークナイゼーション | テキストを意味のある最小単位に分割 |
| 日本語の特殊性 | 形態素解析器(MeCab/Janome)が必要 |
| サブワード | BERT以降の主流、未知語に対応可能 |
| 前処理パイプライン | 正規化→クリーニング→トークン化→フィルタリング |
チェックリスト
- 英語と日本語のトークナイゼーションの違いを説明できる
- MeCabまたはJanomeで日本語テキストを分割できる
- サブワードトークナイゼーションの利点を理解した
- テキスト前処理パイプラインを実装できる
次のステップへ
トークナイゼーションの基礎を学んだところで、次はTF-IDFによるテキストの数値表現を学ぼう。
推定読了時間: 30分