Skip to content

第 12 章 ソースコード一覧

書籍第 12 章「自然言語処理の基礎」に掲載しているソースコードの一覧です。番号は書籍の「入力」番号と対応しています。上のバッジから、この章のコードをまとめた Google Colab ノートブックを開けます。

入力 12.1: join・split・replaceによる文字列操作

words = ["自然", "言語", "処理"]
print(" ".join(words))           # 自然 言語 処理

text = "Python は 自然言語処理 に 便利 です"
print(text.split(" "))           # ["Python", "は", "自然言語処理", ...]

s = "今日は天気が良いです。明日も天気が良いでしょう。"
print(s.replace("天気が良い", "晴れ"))  # 今日は晴れです。明日も晴れでしょう。

入力 12.2: テキストファイルの作成

# サンプルファイルの作成
text = "自然言語処理は人工知能の一分野です。\nテキストデータを分析する技術です。\n"
with open("sample.txt", "w", encoding="utf-8") as f:
    f.write(text)

入力 12.3: テキストファイルの読み込み

# テキストファイルの読み込み
with open("sample.txt", "r", encoding="utf-8") as f:
    text = f.read()
print(text)

入力 12.4: readlinesによる行ごとの読み込み

with open("sample.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
print(lines)

入力 12.5: 英語と日本語の単語分割の違い

# 英語: スペースで単語に分割できる
english = "Natural language processing is important"
print(english.split(" "))

# 日本語: スペースがないため単純に分割できない
japanese = "自然言語処理は重要です"
print(japanese.split(" "))

入力 12.6: MeCabのインストール

# Google Colabでの実行
!pip install mecab-python3 unidic-lite

入力 12.7: parseによる形態素解析

import MeCab

tagger = MeCab.Tagger()
text = "自然言語処理を学びます"
result = tagger.parse(text)
print(result)

入力 12.8: -Owakatiオプションによる分かち書き

import MeCab

tagger = MeCab.Tagger("-Owakati")
text = "自然言語処理を学びます"
result = tagger.parse(text)
print(result)

入力 12.9: parseToNodeによる品詞情報の取得

import MeCab

tagger = MeCab.Tagger()
text = "自然言語処理を学びます"

node = tagger.parseToNode(text)
while node:
    # 表層形(surface)と品詞などの情報(feature)
    if node.surface != "":
        word = node.surface
        pos = node.feature.split(",")[0]  # 品詞の取得
        print(f"{word}\t{pos}")
    node = node.next

入力 12.10: replaceによるテキストクリーニング

text = "今日の\t天気は<b>晴れ</b>です。\n"
# タブ文字の除去
text = text.replace("\t", "")
# 改行文字の除去
text = text.replace("\n", "")
# HTMLタグの除去
text = text.replace("<b>", "")
text = text.replace("</b>", "")
print(text)

入力 12.11: 正規表現によるテキストクリーニング

import re

text = "今日の\t天気は<b>晴れ</b>です。\n"
# タブと改行を除去
text = re.sub(r"[\t\n]", "", text)
# HTMLタグを除去
text = re.sub(r"<.*?>", "", text)
print(text)

入力 12.12: URL・メールアドレス・電話番号の除去

import re

text = """
お問い合わせは https://example.com まで。
メール: info@example.com
電話: 03-1234-5678 または 090-1234-5678
"""

# URLの除去
text = re.sub(r"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", "", text)

# メールアドレスの除去
text = re.sub(r"[\w\.-]+@[\w\.-]+\.\w+", "", text)

# 電話番号の除去(ハイフン区切り)
text = re.sub(r"\d{2,4}-\d{2,4}-\d{4}", "", text)

print(text)

入力 12.13: 余分な空白の整理

import re

text = "  これは  テスト  です  "
# 連続する空白を1つに置換
text = re.sub(r"\s+", " ", text)
# 前後の空白を除去
text = text.strip()
print(text)

入力 12.14: ストップワードの除去

import MeCab

# ストップワードの定義
stop_words = ["は", "の", "が", "を", "に", "へ", "と", "で", "た",
              "です", "ます", "する", "いる", "ある", "こと", "もの",
              "それ", "これ", "ない", "なる", "れる", "られる"]

tagger = MeCab.Tagger("-Owakati")
text = "自然言語処理は人工知能の重要な分野です"
words = tagger.parse(text).strip().split(" ")
print("除去前:", words)

# ストップワードの除去
filtered = [w for w in words if w not in stop_words]
print("除去後:", filtered)

入力 12.15: 品詞によるフィルタリング

import MeCab

tagger = MeCab.Tagger()
text = "機械学習の技術は急速に進歩している"

# 名詞、動詞、形容詞のみを抽出
target_pos = ["名詞", "動詞", "形容詞"]
words = []

node = tagger.parseToNode(text)
while node:
    if node.surface != "":
        pos = node.feature.split(",")[0]
        if pos in target_pos:
            words.append(node.surface)
    node = node.next

print(words)

入力 12.16: 前処理パイプラインの関数化

import re
import MeCab

# テキストの前処理パイプライン
def preprocess(text):
    # 1. テキストクリーニング
    text = re.sub(r"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", "", text)  # URL除去
    text = re.sub(r"[\w\.-]+@[\w\.-]+\.\w+", "", text)  # メールアドレス除去
    text = re.sub(r"\d{2,4}-\d{2,4}-\d{4}", "", text)  # 電話番号除去
    text = re.sub(r"[!-/:-@\[-`{-~]", "", text)  # 半角記号除去
    text = re.sub(r"[!-/:-@[-`{-~、。・「」『』【】]", "", text)  # 全角記号除去
    text = re.sub(r"\s+", " ", text).strip()  # 空白の正規化

    # 2. 形態素解析と品詞フィルタリング
    tagger = MeCab.Tagger()
    target_pos = ["名詞", "動詞", "形容詞"]
    words = []

    node = tagger.parseToNode(text)
    while node:
        if node.surface != "":
            pos = node.feature.split(",")[0]
            if pos in target_pos:
                words.append(node.surface)
        node = node.next

    return words

入力 12.17: 前処理パイプラインの実行

text = "詳細は https://example.com をご覧ください!お問い合わせ: info@test.com"
result = preprocess(text)
print(result)

入力 12.18: 複数文書への前処理の適用

documents = [
    "自然言語処理は人工知能の一分野です。",
    "機械学習を使ってテキストを分析します。",
    "深層学習の発展により精度が向上しました。",
]

processed_docs = []
for doc in documents:
    words = preprocess(doc)
    processed_docs.append(" ".join(words))

for i, doc in enumerate(processed_docs):
    print(f"文書{i+1}: {doc}")

入力 12.19: CountVectorizerによるBoWベクトル化

import MeCab
from sklearn.feature_extraction.text import CountVectorizer

# サンプル文書
documents = [
    "自然言語処理は人工知能の一分野です",
    "機械学習で自然言語を処理します",
    "深層学習は機械学習の一手法です",
]

# MeCabで分かち書き
tagger = MeCab.Tagger("-Owakati")
wakati_docs = [tagger.parse(doc).strip() for doc in documents]
print("分かち書き結果:")
for i, doc in enumerate(wakati_docs):
    print(f"  文書{i+1}: {doc}")

# CountVectorizerでBoWベクトルを生成
vectorizer = CountVectorizer()
bow_matrix = vectorizer.fit_transform(wakati_docs)

# 語彙の確認
print("\n語彙:", vectorizer.get_feature_names_out())

# BoW行列の表示
print("\nBoW行列:")
print(bow_matrix.toarray())

入力 12.20: fit_transformとtransformの使い分け

from sklearn.feature_extraction.text import CountVectorizer

# 訓練データ
train_docs = ["猫 は かわいい", "犬 も かわいい"]

# テストデータ
test_docs = ["猫 と 犬 は 友達"]

# 訓練データで学習+変換(fit_transform)
# token_pattern で1文字の単語も語彙に含める
vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b")
train_matrix = vectorizer.fit_transform(train_docs)
print("学習した語彙:", vectorizer.get_feature_names_out())
print("訓練データのベクトル:")
print(train_matrix.toarray())

# テストデータには transform のみ適用
test_matrix = vectorizer.transform(test_docs)
print("\nテストデータのベクトル:")
print(test_matrix.toarray())

入力 12.21: CountVectorizerの主なパラメータ

from sklearn.feature_extraction.text import CountVectorizer

docs = ["猫 は かわいい 動物", "犬 も かわいい 動物", "猫 も 犬 も かわいい"]
tp = r"(?u)\b\w+\b"  # 1文字の単語も語彙に含める設定

# max_df: 出現頻度が高すぎる単語を除外(全文書の80%より多くに出現する単語を除外)
vec1 = CountVectorizer(max_df=0.8, token_pattern=tp)
result1 = vec1.fit_transform(docs)
print("max_df=0.8 の語彙:", vec1.get_feature_names_out())

# min_df: 出現頻度が低すぎる単語を除外(2文書未満にしか出現しない単語を除外)
vec2 = CountVectorizer(min_df=2, token_pattern=tp)
result2 = vec2.fit_transform(docs)
print("min_df=2 の語彙:", vec2.get_feature_names_out())

# max_features: 語彙の最大数を指定(上位3語のみ)
vec3 = CountVectorizer(max_features=3, token_pattern=tp)
result3 = vec3.fit_transform(docs)
print("max_features=3 の語彙:", vec3.get_feature_names_out())

入力 12.22: ngram_rangeによるN-gramの生成

from sklearn.feature_extraction.text import CountVectorizer

docs = ["自然 言語 処理 を 学ぶ"]
tp = r"(?u)\b\w+\b"  # 1文字の単語も語彙に含める設定

# ユニグラムのみ(デフォルト)
vec_uni = CountVectorizer(token_pattern=tp, ngram_range=(1, 1))
vec_uni.fit(docs)
print("ユニグラム:", vec_uni.get_feature_names_out())

# バイグラムのみ
vec_bi = CountVectorizer(token_pattern=tp, ngram_range=(2, 2))
vec_bi.fit(docs)
print("バイグラム:", vec_bi.get_feature_names_out())

# ユニグラム + バイグラム
vec_both = CountVectorizer(token_pattern=tp, ngram_range=(1, 2))
vec_both.fit(docs)
print("ユニグラム+バイグラム:", vec_both.get_feature_names_out())

入力 12.23: TfidfVectorizerによるTF-IDFベクトル化

import MeCab
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer

# サンプル文書
documents = [
    "自然言語処理は人工知能の一分野です",
    "機械学習で自然言語を処理します",
    "深層学習も自然言語を処理します",
]

# MeCabで分かち書き
tagger = MeCab.Tagger("-Owakati")
wakati_docs = [tagger.parse(doc).strip() for doc in documents]

# TfidfVectorizerでTF-IDFベクトルを生成
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(wakati_docs)

# 結果をDataFrameで見やすく表示
feature_names = tfidf_vectorizer.get_feature_names_out()
df = pd.DataFrame(
    tfidf_matrix.toarray(),
    columns=feature_names,
    index=["文書1", "文書2", "文書3"]
)
print(df.round(2))

入力 12.24: BoWとTF-IDFの比較

import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer

documents = [
    "猫 は かわいい 動物",
    "犬 も かわいい 動物",
    "猫 は 自由 な 動物",
]
tp = r"(?u)\b\w+\b"  # 1文字の単語も語彙に含める設定

# Bag-of-Words
count_vec = CountVectorizer(token_pattern=tp)
bow = count_vec.fit_transform(documents)
print("【Bag-of-Words】")
df_bow = pd.DataFrame(bow.toarray(), columns=count_vec.get_feature_names_out(),
                       index=["文書1", "文書2", "文書3"])
print(df_bow)

# TF-IDF
tfidf_vec = TfidfVectorizer(token_pattern=tp)
tfidf = tfidf_vec.fit_transform(documents)
print("\n【TF-IDF】")
df_tfidf = pd.DataFrame(tfidf.toarray(), columns=tfidf_vec.get_feature_names_out(),
                          index=["文書1", "文書2", "文書3"])
print(df_tfidf.round(2))

入力 12.25: 文書間のコサイン類似度の計算

import MeCab
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# サンプル文書コーパス
documents = [
    "機械学習はデータからパターンを学習する技術です",
    "深層学習はニューラルネットワークを用いた機械学習の手法です",
    "自然言語処理はテキストデータを分析する技術です",
    "画像認識は写真や動画から物体を検出する技術です",
    "機械学習を使ってテキストを分類することができます",
]

# MeCabで分かち書き
tagger = MeCab.Tagger("-Owakati")
wakati_docs = [tagger.parse(doc).strip() for doc in documents]

# TF-IDFベクトルの生成
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(wakati_docs)

# 全文書間のコサイン類似度を計算
cos_sim = cosine_similarity(tfidf_matrix)

# 結果の表示
labels = [f"文書{i+1}" for i in range(len(documents))]
df_sim = pd.DataFrame(cos_sim, index=labels, columns=labels)
print(df_sim.round(2))

入力 12.26: 類似文書の検索と順位付け

import MeCab
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# クエリに類似した文書を検索して順位付けする
def search_similar(query, documents, vectorizer, tfidf_matrix, top_n=3):
    # クエリをMeCabで分かち書き
    tagger = MeCab.Tagger("-Owakati")
    query_wakati = tagger.parse(query).strip()

    # クエリをTF-IDFベクトルに変換(学習済みのvectorizerを使用)
    query_vec = vectorizer.transform([query_wakati])

    # クエリとコーパス内の各文書とのコサイン類似度を計算
    similarities = cosine_similarity(query_vec, tfidf_matrix)[0]

    # 類似度の高い順にソート
    ranking = np.argsort(similarities)[::-1]

    print(f"クエリ: 「{query}」\n")
    print("類似文書ランキング:")
    for rank, idx in enumerate(ranking[:top_n], 1):
        print(f"  {rank}位 (類似度: {similarities[idx]:.4f}): {documents[idx]}")

# 検索の実行
query = "テキストデータの分析と分類の方法"
search_similar(query, documents, vectorizer, tfidf_matrix)