ChatGPT-4oと協力して「しりとり」プログラムを1時間弱で完成させた
お疲れ様です。Y研究員です。有隣堂のYouTubeチャンネルが好きです。
切っ掛け
だいぶ前ですが、三省堂の「消えた言葉辞典」が紹介されました。ようやく時間が取れたので、やっと読み終わりました。一番印象に残った単語は「金玉火鉢」です。身も蓋もない結末ですが、本自体は面白かったです。
それとは別に子供と「しりとり」をしていて、プログラムなら簡単に「しりとり」が出来るのではないか、と思いました。単語のデータベースをどこかから借りてきて、そこから単語を抽出すればできそうです。しかし自然言語処理はやったことがないし、ましてや日本語の取り扱いは難しそうなのでChatGPTに協力してもらいました。
やりかた
簡単にググったところ、日本語を研究している方のサイトから辞書データベースが見つかりました。エクセル形式でダウンロードできました。CSVに変換してからシェル芸をして、単語と読みと品詞の列だけ取りました。あとは名詞の行だけを抽出して前処理は完了しました。ここまではLinuxのShell(awk と grep)です。大きいデータもサクサク料理できるので、シェル芸はすごいです。
つぎにPythonのプログラミングに移りました。結果を見ながら書きたいので環境はJupyter Notebookにしました。最後の1文字が小さい文字だった場合は大きい文字に変換するのと、伸ばし棒(ー)の場合はもう一つ前の文字をとる処理を入れました。その最後の文字から次の単語を探す関数を書いて大体は完了です。
やってみて分かったこと
最初は適当に動かして遊んでいました。意外と「ん」で終わる単語が多いことに気が付きました。連続20回をエラーなく回すには何回か試行しないと結果が出ません。実際のしりとりでも「ん」で終わる単語を言ってしまいます。確率的にそうなるからゲームなのかなと思いました。
しりとりの結果
何回かやって面白いのが出てきたので共有します。はじめの単語は「テスト」「シリトリ」と「チノウ」です。
単語のジャンルがあちこちに飛ぶので面白いです。最後の「えぐみ」「身悶え」「エトランゼ」の連続は完全無作為なプログラムながら妙な面白みを感じました。
知らない単語も出てきます。「羅刹」は仏教用語で人を食べる鬼が転じて守護神になったらしいです。「追儺」は旧暦の大晦日に疫鬼(えきき)や疫神(えきしん)を払う儀式らしいです。
「特級」「薄口」とくれば「醤油」でしょうか。無関係な単語が連続しても何かしらの物語を勝手に想像できるのは面白いです。
おわりに
ChatGPT-4oを助けに、アイディアのプロトタイプが簡単に出来ました。思いついてから動かすまで短時間で出来て凄いです。ただし、前提知識もあれこれ使っている気がしました。Googleが出てきた時は「ある」と想定できるものしか検索しないと思っていました。ChatGPTも「できそうだ」と見当がつくものしか出来ないのは似ている気がします。要は「道具」の使いよう、みたいな感じでしょうか。
参考にした情報
"松下達彦(2011)「日本語を読むための語彙データベース(VDRJ) Ver. 1.0 (教師用)"を利用させていただきました。2024年6月13日にダウンロードしました。
動かしたプログラム
短いのでつけておきます。最初は前処理のシェル芸(ワンライナー)です。エクセルはCSVに変換して保存しておきます。
cat VDRJ_Ver1_0_Teachers_Top60894.csv| awk -F',' '{print $14 "," $16 "," $17}' | grep "名詞"| grep -v "N/A" > meishi.csv
次は「しりとりエンジン」です。
import pandas as pd
import re
import random
def find_word_starting_with_last_katakana(input_str, df_katakana):
# 文字列の最後の文字を取り出す
if input_str[-1] == 'ー':
last_char = input_str[-2]
else:
last_char = input_str[-1]
# 小さい文字を大きい文字に変換
small_to_large = {
'ゃ': 'や', 'ゅ': 'ゆ', 'ょ': 'よ',
'ぁ': 'あ', 'ぃ': 'い', 'ぅ': 'う', 'ぇ': 'え', 'ぉ': 'お'
}
last_char = small_to_large.get(last_char, last_char)
# 最後の文字で始まる単語を無作為に探す
df_filtered = df_katakana[df_katakana['yomi'].str.startswith(last_char, na=False)]
if not df_filtered.empty:
result_row = df_filtered.sample(n=1).iloc[0]
return result_row.to_dict()
else:
return "No matching word found"
読み方がカタカナで入っている行だけ抽出します。それから「しりとりエンジン」を回します。既出単語のチェックは横着してありません。確率的に低いかなと。。。
df = pd.read_csv("meishi.csv", header=None,encoding="utf-8")
headers = ["word","yomi","meishi"]
df.columns = headers
df_katakana = df[df['yomi'].str.contains(r'[ァ-ヶ]', na=False)]
input_str = "テスト"
results = []
# 関数を連続して20回呼び出す
success_count = 0
total_attempts = 0
while success_count < 20:
total_attempts += 1
result = find_word_starting_with_last_katakana(input_str, df_katakana)
if isinstance(result, dict):
results.append(result)
input_str = result['yomi']
success_count += 1
else:
#print(f"Attempt {total_attempts}: No matching word found, restarting...")
success_count = 0
results = []
input_str = "テスト"
# 20回無事に回った場合にのみ結果を表示
if success_count == 20:
result_strings = [f"{res['word']}({res['yomi']})" for res in results]
result_output = "→".join(result_strings)
print(f"Completed in {total_attempts} attempts")
print(result_output)
else:
print("The loop was interrupted before completing 20 iterations.")
では。
無料のプログラミングクラブCoderDojoを運営するにあたり寄付を受け付けています。お金は会場費・Wifiの費用・教科書に使用します。