LoginSignup
3
5

大量の英文を分解して自分だけの単語帳を作る方法

Last updated at Posted at 2023-04-17

どうも皆さま。初めまして。ごきげんよう。
Mondderというサービスをやっているqbotaと申します。

大学入試に出てくる英文を基にして単語帳(というか単語問題)を作ったので、そこで得られた僅かばかりの知見を共有したいと思います。半分はサービスの宣伝です。

NLTKを使って英語の文章を形態素解析にかける

文章をそれを構成している単語(正確には形態素)に分解することを形態素解析といいます。
日本語では、MeCabJUMANがよく知られていますが、Pythonで英文を形態素解析にかけるにはNLTK(Natural Language Toolkit)というのが利用できるようです。

import nltk
text = "NLTK is a leading platform for building Python programs to work with human language data. "
for t in nltk.pos_tag(nltk.word_tokenize(text)):
    print(t)

これを実行するとこんな結果が得られます。

('NLTK', 'NNP')
('is', 'VBZ')
('a', 'DT')
('leading', 'VBG')
('platform', 'NN')
('for', 'IN')
('building', 'VBG')
('Python', 'NNP')
以下省略

特定の品詞だけ取り出す

定冠詞や固有名詞は今回の目的には不要なので動詞、名詞、副詞、形容詞のみを取り出します。

import nltk
text = "NLTK is a leading platform for building Python programs to work with human language data. "
for t in nltk.pos_tag(nltk.word_tokenize(text)):
    pos = ""
    if t[1] == "JJ" or t[1] == "JJR" or t[1] == "JJS":
        pos = "形容詞"
    elif  t[1] == "NN" or t[1] == "NNS":
        pos = "名詞"
    elif  t[1] == "RB" or t[1] == "RBR" or t[1] == "RBS":
        pos = "副詞"
    elif  t[1] == "VB" or t[1] == "VBD" or t[1] == "VBG" or t[1] == "VBN" or t[1] == "VBP" or t[1] == "VBZ":
        pos = "動詞"
    if len(pos) >1:
        print(t[0],pos)
is 動詞
leading 動詞
platform 名詞
building 動詞
programs 名詞
work 動詞
human 形容詞
language 名詞
data 名詞

品詞タグの意味は、こちらの記事をご参照ください。

問題点

活用形が別の単語になってしまう

このままではhaveとhasやcatとcatsは別なものとして識別されます。
これは怠いので以下のようにすると原形や単数形に直すことができます。

from nltk.stem import WordNetLemmatizer

gen = WordNetLemmatizer().lemmatize("cats", pos="n")
print(gen)
gen = WordNetLemmatizer().lemmatize("has", pos="v")
print(gen)
cat
have

品詞の判定がちょいちょいデタラメ

上のリンクに出てくる「Hi, I'm Taro Yamada I woke up at 8am.」という文章を上記のやり方で分析するとTaroは形容詞に分類されます。そう、我らがTaroは形容詞だったのです。
他にも意味不明な記号(://など)や日本語の文字にも品詞が割り当てられることがあり、決して完璧ではありません。

で困ったのですが、とりあえず辞書にないものは無視しちゃえばいいんじゃないかという考えに至りました。

NLTKではWordNetという辞書が利用でき、以下のようにすると語を検索できます。

from nltk.corpus import wordnet
lemmas = wordnet.lemmas("use")
pos =""
for lemma in lemmas:
        print(lemma)
Lemma('use.n.01.use')
Lemma('function.n.02.use')
Lemma('use.n.03.use')
Lemma('consumption.n.03.use')
Lemma('habit.n.02.use')
Lemma('manipulation.n.01.use')
Lemma('use.n.07.use')
Lemma('use.v.01.use')
Lemma('use.v.02.use')
以下省略

これで語と使用品詞例を確認し、その品詞での使用がなければ破棄するようにしました。

from nltk.corpus import wordnet
def checkPOS(word,moto_pos):
    lemmas = wordnet.lemmas(word)
    pos = []
    for lemma  in lemmas:
        if lemma.synset().pos() == 'n':
            pos.append("名詞")
        elif lemma.synset().pos() == 's' or lemma.synset().pos() == 'a':
            pos.append("形容詞")
        elif lemma.synset().pos() == 'r':
            pos.append("副詞")
        elif lemma.synset().pos() == 'v':
            pos.append("動詞")
    if not pos or moto_pos not in pos:
        return False
    return True

print(checkPOS("taro","形容詞"))
print(checkPOS("scalable","形容詞"))
False
True

日本語Wordnetで単語の意味を調べる

Wordnetには日本語版もあってこれを利用すれば英和辞書的なものが作れるようです。

上のコードを拝借させて頂きこんな感じにしました。

import sqlite3
def getMeaning(word,limit):
    conn = sqlite3.connect("./wnjpn.db")
    cur = conn.cursor()
    sql = "\
        SELECT DISTINCT word_en.wordid, word_en.lemma,  word_ja.lemma\
        FROM sense sense_A, sense sense_B , word word_en , word word_ja \
        WHERE word_en.wordid = sense_A.wordid\
            and sense_A.lang = 'eng'\
            and sense_B.lang = 'jpn'\
            and sense_A.synset = sense_B.synset\
            and sense_B.wordid = word_ja.wordid\
            and word_en.lemma = ?\
        ORDER BY word_en.lemma"
    cur.execute(sql, (word,))
    before = 0
    meaning =  ""
    n  = 0
    i = 1
    for row in cur:
        if before != row[0]:
            if meaning:
                meaning += " "
            meaning += str(i)+' ' + row[2]
            before = row[0]
            n = 1
            i += 1
        else :
            if n >= limit :
                continue
            n += 1
            meaning +=  ',' +row[2]
    if "2 " not in meaning:
        meaning = meaning.replace("1 ","")
    cur.close()
    conn.close()
    return meaning
print(getMeaning("snatch",3))

これで「snatch」という単語を検索すると以下の結果が得られます。

1 おまんこ,われめちゃん,ぼぼ 2 掻っぱらう,分捕る,奪取

こいつは大丈夫なのかと思いましたが、英辞郎にも下の方に小さくそのような意味が載っているので一応大丈夫なようです。

Google翻訳で単語の意味を調べる

Wordnet日本語版で全ての単語の意味を調べられるわけではないので、残った単語はGoogle翻訳を使って意味を確認しました。

from googletrans import Translator
meaning = Translator().translate("canal", src="en", dest="ja").text
print(meaning)
運河

ChatGPTに例文を作ってもらう

せっかくなのでChatGPT(正確にはOpenAIのAPI)に指定した単語を使った例文を作って貰いました。

import openai
def exampleByGPT(word):
    openai.api_key = "*********************************"
    word = ""+word+""
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
        {"role": "user", "content": word+"という単語を使って簡単な英文を作って下さい。\n"},
        ],
        )
    return (response.choices[0]["message"]["content"].strip())

print(exampleByGPT("snatch"))
I tried to snatch the last cookie from the plate, but my sister got to it first.

非常に簡単ですが量が多いとものすごく時間がかかるので注意が必要です。自分の場合は余裕で10時間以上かかりました。またOpenAIのAPIは有料です。

DeepLで例文を翻訳する

例文はGoogleまたはDeepLのAPIを使って訳しました。

import deepl
def deeplTrans(text):
    translator = deepl.Translator("***********************")
    yaku = translator.translate_text(text,source_lang="EN",target_lang="JA").text
    print(yaku)
私は皿から最後のクッキーを奪い取ろうとしたが、妹に先を越された。

DeepLのAPIは無料プランでも月50万文字まで利用することができます。

できたもの

こんな感じで作ったデータをCVSファイルに変換してインポートするとこういうのが作れます。

実際に使用したコードはこちらに置いてあります。

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5