【副業実験記#7】Python+KeyBERTで日本語テキストからキーワードを抽出してみた話

子育てSEパパのIT×AI×副業ラボ_副業実験記_7 副業実験記

つづき。


はじめに

引き続き、雑学動画自動生成ツールを自作できないか、検討してみているお話です。

今回は、文章からキーワードを自動で抽出してくれるPythonライブラリである「KeyBERT」について、雑学動画自動生成ツールで使えるか検証してみた話です。

検証準備

Pythonのインストール

「Python」で雑学動画自動生成ツールを作るつもりなので、検証でも同様に使います。

詳細は以下の記事にまとめていますので、ご興味ある方は、そちらをご覧ください。

PyCharmのインストール

Pythonでの開発を楽にしてくれる統合開発環境「PyCharm」を使います。

Pythonで雑学動画自動生成ツールを作る際に使うつもりなので、検証でも同様に使います。

詳細は以下の記事にまとめていますので、ご興味ある方は、そちらをご覧ください。

検証用Pythonプロジェクトおよびvenvの作成

検証用「Pythonプロジェクト」を作成します。

PyCharmで簡単に作成できます。

Pythonプロジェクトを作成したら、その中で「venv」(Python仮想環境)を作成しておきます。

詳細は以下の記事にまとめていますので、ご興味ある方は、そちらをご覧ください。

Pythonパッケージのインストール

今回は、以下のパッケージを使用します。

Noパッケージ説明備考
1keybertテキストの中から重要なキーワードを自動で抽出してくれるPythonライブラリパッケージです。
2sentence-transformers文章や文同士の意味の近さを数値で表すためのライブラリパッケージです。
3fugashi有名な日本語解析エンジン MeCab のPythonラッパーです。・Pythonラッパー=PythonからMeCabを簡単に使うためのもの
4unidic-litefugashiが使う「日本語の辞書データ(サイズ軽量版)」です。単語の意味や品詞などの情報を含んでいます。

KeyBERTは、基本的に英語向けということで、今回は「SentenceTransfomers」と日本語向けの埋め込みモデルである「cl-tohoku/bert-base-japanese」も一緒に使って試してみます。

この「cl-tohoku/bert-base-japanese」を使うために、「fugashi」や「unidic-lite」をインストールしています。

検証用Pythonプロジェクトでvenvを起動し、パッケージをインストールします。

ターミナルでコマンド実行してインストールする方法やPyCharm上で画面を操作してインストールする方法がありますが、今回は、PyCharm上で画面を操作し、venvにパッケージをインストールします。

検証してみた

KeyBERTを使用したキーワード抽出処理の流れ

以下の流れでKeyBERTを使っていくようでした。

  1. 「SentenceTransformers」を使い日本語モデルを読み込む
  2. 読み込んだ日本語モデルを「keyBERT」に渡す
  3. keyBERTで日本語テキストからキーワードを抽出する

KeyBERTを使用したキーワード抽出処理の試し

では実際に、keyBERTと日本語モデル「cl-tohoku/bert-base-japanese」を使って、日本語テキストからキーワードを抽出してみます

keyBERTと日本語モデル「cl-tohoku/bert-base-japanese」を使ったPythonサンプルコード

from keybert import KeyBERT
from sentence_transformers import SentenceTransformer

# 日本語対応のBERTモデルを読み込み
model = SentenceTransformer('cl-tohoku/bert-base-japanese')

# KeyBERTにモデルを渡す
kw_model = KeyBERT(model)

# キーワードを抽出したいテキスト
text = "Pythonはプログラミング言語のひとつで、データ分析やAI開発にも使われています。"

# キーワード抽出(トップ10件)
keywords = kw_model.extract_keywords(text, top_n=10)

# 結果表示
for kw in keywords:
    print(kw)

Pythonサンプルコード実行結果

('データ分析やai開発にも使われています', 0.9273)
('pythonはプログラミング言語のひとつで', 0.9215)

・・・。

思った以上に、抽出されるキーワードの粒度が粗い・・・。

あえて日本語モデルを使うのをやめて実行してみましたが、粒度は変わらずでした。

動画タイトルからキーワードを抽出してハッシュタグに使うことなどを想定していたましたが、このままだと使えそうにありません。

ChatGPTさんに相談したところ、keyBERTを使わなくとも、「SentenceTransformers」×「fugashi」×「scikit-learn」で似たような処理ができるということだったので、試してみました。

「SentenceTransformers」×「fugashi」×「scikit-learn」を使ったキーワード抽出(の手前)のPythonサンプルコード

import fugashi
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

# モデル読み込み(東北大でもOK)
model = SentenceTransformer("cl-tohoku/bert-base-japanese")

# 入力
input_text = "Pythonはプログラミング言語のひとつで、データ分析やAI開発にも使われています。"

def extract_noun_phrases(text):
    words = list(fugashi.Tagger()(text))
    phrases = []
    i = 0
    while i < len(words):
        word = words[i]
        # 名詞 + 接尾辞 のペア(例:ひと + つ → ひとつ)
        if "名詞" in word.feature:
            phrase = word.surface
            # 次が接尾辞ならくっつける
            if i + 1 < len(words) and "接尾辞" in words[i + 1].feature:
                phrase += words[i + 1].surface
                i += 1
            phrases.append(phrase)
        i += 1
    return list(set(phrases))  # 重複除去

candidates = extract_noun_phrases(input_text)

# 埋め込みベクトル化
doc_vec = model.encode([input_text])
cand_vecs = model.encode(candidates)

# 類似度スコアを計算
scores = cosine_similarity(doc_vec, cand_vecs)[0]

# 候補+スコアのペアを作る
scored = list(zip(candidates, scores))
scored.sort(key=lambda x: x[1], reverse=True)

# 表示
for w, s in scored:
    print(f"{w}: {s:.4f}")

Pythonサンプルコード実行結果

Python: 0.7277
データ: 0.6582
プログラミング: 0.6475
ひとつ: 0.6181
分析: 0.6071
言語: 0.5833
開発: 0.5749
AI: 0.5471

“「fugashi」で日本語テキストの名詞を抽出”し、抽出した名詞に対して類似度スコアを計算しましたが、こっちの方がハッシュタグを生成する用途で使えそうですね。

ここでふと疑問が。

「fugashiではなく、GiNZAではどうか?」

と思ったので、ChatGPTさんに相談したところ、「fugashi」の部分を「GiNZA」に置き換えても大丈夫そうだったので、試してみました。

「SentenceTransformers」×「GiNZA」×「scikit-learn」を使ったキーワード抽出(の手前)のPythonサンプルコード

import spacy
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

# GiNZAモデルの読み込み(ja_ginza_electraが高精度)
nlp = spacy.load("ja_ginza_electra")
model = SentenceTransformer("cl-tohoku/bert-base-japanese")

# 入力文
input_text = "Pythonはプログラミング言語のひとつで、データ分析やAI開発にも使われています。"

# 名詞句(noun chunk)を候補として抽出
def extract_noun_phrases_with_ginza(text):
    doc = nlp(text)
    return list(set([chunk.text for chunk in doc.noun_chunks if len(chunk.text.strip()) > 1]))

candidates = extract_noun_phrases_with_ginza(input_text)

# ベクトル化してスコア計算
doc_vec = model.encode([input_text])
cand_vecs = model.encode(candidates)
scores = cosine_similarity(doc_vec, cand_vecs)[0]

# スコア付きで並べる
scored = list(zip(candidates, scores))
scored.sort(key=lambda x: x[1], reverse=True)

# 表示
for word, score in scored:
    print(f"{word}: {score:.4f}")

Pythonサンプルコード実行結果

Python: 0.7277
プログラミング言語: 0.6830
データ分析: 0.6397
AI開発: 0.6162

“「fugashi」の代わりに「GiNZA」で日本語テキストの名詞を抽出”し、抽出した名詞に対して類似度スコアを計算しましたが、こっちの方が抽出される粒度が大きい代わりに、単語のまとまり具合が適切な感じです。

こちらの方がハッシュタグ的には適切なキーワードのような気もします。

あと、この粒度なら「Stable Diffusion web UI」のプロンプトに渡す粒度に適しているように思えました。

それぞれ、用途に応じて使い分けることもできそうに思いました。

おわりに

「keyBERT」ですが、日本語テキストからキーワードを抽出できることが分かりましたが、想定していた結果が得られなかったので、雑学動画自動生成ツールで使うかどうかは微妙です・・・。

その代わり、以下の代替方法によるキーワード抽出を使う可能性が高いです。

  • 「SentenceTransformers」×「fugashi」×「scikit-learn」
  • 「SentenceTransformers」×「GiNZA」×「scikit-learn」

ここら辺は、AI画像生成時のプロンプト自動生成やハッシュタグ自動生成で使おうと思います。

これで、「keyBERT」の検証を一通り終えたので、次の技術やツールの検証に移ろうと思います。

(今回も検証用のコードは、ChatGPT(GPT-4oモデル)に出力してもらったものを微修正したものです)


今回の記事も、同じように副業に悩んでいる人、手探りで取り組んでいる人にとって、何かの参考になれば嬉しいです。

これからも記録を続けていく予定なので、よければフォローしてもらえると嬉しいです。


つづき。

タイトルとURLをコピーしました