テキストデータのコンピュータ表現
画像データがRGBやYUVなどの形式で表されるように、自然言語処理(NLP)では文字列をコンピュータで処理可能な数値形式に変換する必要があります。画像処理で扱うピクセル行列と同様に、テキストデータも行列形式で表現されます。
分かち書き処理
日本語などの連続文字言語では、文章を意味のある単位に分割する処理が必要です。最大マッチングアルゴリズム(正向・逆向・双方向)を用いた例を示します。
def forward_max_match(text, max_length=6):
result = []
while text:
matched = False
for i in range(max_length, 0, -1):
if len(text) >= i:
word = text[:i]
if is_valid_word(word): # 辞書に存在するか確認
result.append(word)
text = text[i:]
matched = True
break
if not matched:
result.append(text[0])
text = text[1:]
return result
# 実行例
sentence = "今日の夕食はとても美味しかった"
tokens = forward_max_match(sentence)
print(tokens) # ["今日", "の", "夕食", "は", "とても", "美味しかった"]
one-hotエンコーディング
最も基本的なベクトル表現方法で、語彙数と同じ次元を持ちます。
vocab = {"私": 0, "今日": 1, "朝": 2, "食事": 3, "美味": 4, "かった": 5}
def one_hot_encode(word):
vector = [0] * len(vocab)
vector[vocab[word]] = 1
return vector
# 例
print(one_hot_encode("朝")) # [0, 0, 1, 0, 0, 0]
TF-IDFによる重み付け
単語の重要度を考慮した表現方法で、文書内での出現頻度と語彙全体での重要度を組み合わせます。
def calculate_tf_idf(term, doc, corpus):
# TFの計算
tf = doc.count(term) / len(doc)
# IDFの計算
doc_count = sum(1 for d in corpus if term in d)
idf = math.log(len(corpus) / (doc_count + 1))
return tf * idf
# 例
document = ["今日", "天気", "良い"]
corpus = [["今日", "天気", "良い"], ["昨日", "雨", "降った"]]
weight = calculate_tf_idf("天気", document, corpus)
print(f"TF-IDF: {weight:.3f}")
word2vecによる分散表現
ニューロンネットワークを用いた次元削減表現で、語義の類似性をベクトル空間で表現します。
word_vectors = {
"朝": [0.15, 0.22, 0.37],
"今日": [0.53, 0.11, 0.18],
"食事": [0.42, 0.92, 0.0]
}
def cosine_similarity(v1, v2):
return sum(a*b for a,b in zip(v1,v2)) / (math.sqrt(sum(x*x for x in v1)) * math.sqrt(sum(y*y for y in v2)))
# 類似度計算
similarity = cosine_similarity(word_vectors["朝"], word_vectors["今日"])
print(f"朝と今日の類似度: {similarity:.2f}")
word2vecの学習プロセス
CBOW(Continuous Bag of Words)とSkip-gramの2つのモデル構造があります。CBOWは周辺語から中心語を予測し、Skip-gramは中心語から周辺語を予測します。
- 語彙数1000、隠れ層ノード数150の場合は1000×150の重み行列が生成される
- 訓練後、左側の行列が最終的な単語ベクトルとして利用される
- 150~300次元が一般的なベクトルサイズ