はじめに
こちらは後編の記事になりますので、まずは前編をご覧下さい。
↓ 今回作成した単語データを使用した学習の様子(記事の最後にダウンロードリンクがあります!)
実行結果だけ見たい!という方はこちら→実行結果
目次
- 前回の振り返り
- 改善方法について
- プログラム内で使用する単語が多い
- case insensitiveになっていない
- stackoverflowのページにオーバフィットしている
- コードの全体像
- 改善点と追加機能
- プログラム内で使用する単語が多い
- case insensitiveになっていない
- stackoverflowのページにオーバフィットしている
- 単語の翻訳
- その他
- 実行結果
- 結論
- 【重要】英単語帳を作るには
- データのダウンロード
前回の振り返り
仮説と検証結果
前回は前編ということで、プログラムで自動生成してしまえば
もう英単語帳購入の必要はないんじゃないか?
という仮説の簡単な検証を行なっていきました。
前回の実行結果の一部がこちら。
rank:0 word: ('i', 96)
rank:1 word: ('python', 86)
rank:2 word: ('ago', 50)
rank:3 word: ('bronze', 36)
rank:4 word: ('have', 29)
rank:5 word: ('×', 25)
問題点
前回の検証結果として下記3つの問題点があることが見えてきました。
- プログラムのみで使用する単語が存在する
- case insensitiveになっていない
- stackoverflowのページにオーバフィットしている
今回はこれらの課題を解決し、
エンジニアにとって必要な英単語を最効率で学習
できる英単語帳の作成を目指していきます。
改善方法について
プログラム内で使用する単語が多い
def、jやkなどの単語のことになるのですが、プログラム的に除去していく方法としては以下のようなものが挙げられます。
- プログラムのみで使用するような単語のリストデータを作成し、フィルタリング
- 自然言語として意味のなさないものを除去する+2文字以下は単語とみなさない※1
- 品詞の解読精度を向上させる
1と3は時間がかかるので、TextBlobの機能が生かせる2を採用していきます。
まずは、こちらをご覧下さい。
>>fromtextblobimportWord>>print(Word("list").definitions)>>['a database containing an ordered array of items (names or topics)',...]
こちらで分かる通り、単語に意味が存在する場合definitions
というアトリビュートを呼ぶと、定義をリストで返してくれます。
同様に'def'の定義を見てみると
>>fromtextblobimportWord>>print(Word("def").definitions)>>[]
のように、空のリストが返されますので、こちらを利用して本来の英語には存在しない単語を除去していきます。
case insensitiveになっていない
これは下記のようにstringのメソッドlowerを呼んで、全て小文字にすることで対応していきます。
'string'.lower()
stackoverflowのページにオーバフィットしている
ここが良い単語帳を作成するにのに最も重要なポイントとなりそうです。「エンジニア」をターゲットとすると少し幅が広くてデータをとるのが大変なので、下記2点を行っている人にフォーカスした単語帳を作成することとして5つのwebページをピックアップしてみました。
- Pythonを使用している
- AIを使用したバックエンド開発を行っている
1/5 AWS Lamda
https://aws.amazon.com/lambda/
2/5 Python3.8 What's new
https://docs.python.org/3/whatsnew/3.8.html
3/5 Docker what is container
https://www.docker.com/resources/what-container
4/5 Wikipedia Artificial intelligence
https://en.wikipedia.org/wiki/Artificial_intelligence
コードの全体像
基本的には前回のコードを使いまわしていますが、今回は複数のサイトにアクセスするためのfor文が必要となったので、一部関数の切り出しと修正を行っています。
fromenumimportEnum,uniquefromtypingimportList,Tuple,Dictimportrequestsfrombs4importBeautifulSoupasbsfromtextblobimportTextBlob,Wordfromtextblob.exceptionsimportNotTranslatedURLS=(('stackoverflow','https://stackoverflow.com/questions/tagged/python'),('AWS','https://aws.amazon.com/lambda/'),('wikipedia AI','https://en.wikipedia.org/wiki/Artificial_intelligence'),('Docker','https://www.docker.com/resources/what-container'),('Python3.8 doc','https://docs.python.org/3/whatsnew/3.8.html'),)PARSER="html.parser"UNACCEPTABLE_LENGTH_OF_WORD=2@uniqueclassPartOfSpeechToLearn(Enum):JJ='Adjective'VB='Verb'NN='Noun'RB='Adverb'defsingle_page_text_from_url(url:str)->str:res=requests.get(url)raw_html=bs(res.text,PARSER)texts_without_html:str=raw_html.textreturntexts_without_htmldeffilter_for_wordbook(morph:TextBlob)->List[str]:word_and_tag:List[Tuple[str,str]]=morph.tagspart_of_speech_to_learn=tuple(pos.nameforposinPartOfSpeechToLearn)filtered_words=[]forwtinword_and_tag:word:str=wt[0].lower()part_of_speech:int=wt[1]ifpart_of_speechnotinpart_of_speech_to_learn:continueifwordinfiltered_words:continueif(len(word)<=UNACCEPTABLE_LENGTH_OF_WORDorlen(Word(word).definitions)==0):continuefiltered_words.append(word)returnfiltered_wordsdefshow_top_50_common_and_uncommon_words(word_and_count:Dict[str,int])->None:words_by_descending_order:List[Tuple[str,int]]=sorted(word_and_count.items(),key=lambdax:x[1],reverse=True)print('the most common words')fori,word_and_countinenumerate(words_by_descending_order[:10]):word:str=word_and_count[0]count:int=word_and_count[1]try:meaning_jp=str(TextBlob(word).translate(to='ja'))exceptNotTranslated:meaning_jp=wordprint(f'rank:{i+1} word: {word} count: {count} meanings: {meaning_jp}')print('the most uncommon words')forj,word_and_countinenumerate(words_by_descending_order[:-11:-1]):word:str=word_and_count[0]count:int=word_and_count[1]try:meaning_jp=str(TextBlob(word).translate(to='ja'))exceptNotTranslated:meaning_jp=wordprint(f'rank:{j+1} word: {word} count: {count} meanings: {meaning_jp}')if__name__=='__main__':word_and_count:Dict[str,int]={}forurlinURLS:print(f'website: {url[0]} url: {url[1]}')texts_without_html=single_page_text_from_url(url[1])morph=TextBlob(texts_without_html)filtered_words=filter_for_wordbook(morph)forwordinfiltered_words:count=morph.words.count(word,case_sensitive=False)ifcount==0:continueifwordnotinword_and_count.keys():word_and_count[word]=countelse:word_and_count[word]+=countprint(f'length of word_and_count: {len(word_and_count)}')show_top_50_common_and_uncommon_words(word_and_count)
それでは、前回から改良した点をみていきましょう!
改善点と追加機能
プログラム内で使用する単語が多い
前回内包表記でフィルタリングしていた部分を全て関数に切り出してif
でフィルターするようにしています。シンプルな処理であれば内包表記がnamespaceの節約と処理効率の面で便利ですが、複数の条件でデータを処理する場合にはif
文を使用する方がシンプルでベターかと思います。if
に関してはネストを避けるために、処理が軽そうなものから順にcontinue
していくようにしています。
deffilter_for_wordbook(morph:TextBlob)->List[str]:word_and_tag:List[Tuple[str,str]]=morph.tagspart_of_speech_to_learn=tuple(pos.nameforposinPartOfSpeechToLearn)filtered_words=[]forwtinword_and_tag:word=wt[0].lower()part_of_speech=wt[1]ifpart_of_speechnotinpart_of_speech_to_learn:continueifwordinfiltered_words:continueif(len(word)<=UNACCEPTABLE_LENGTH_OF_WORDorlen(Word(word).definitions)==0):continuefiltered_words.append(word)returnfiltered_words
上記コードのここで、プログラムでしか使用しない単語をフィルタリングしています。
if(len(word)<=UNACCEPTABLE_LENGTH_OF_WORDorlen(Word(word).definitions)==0):continue
case insensitiveになっていない
先ほどのコードの下記部分で、大文字小文字が違うだけで同じ単語を同一データとして重複を避ける処理を入れています。
forwtinword_and_tag:word=wt[0].lower()ifwordinfiltered_words:continue
stackoverflowのページにオーバフィットしている
先ほど紹介したwebサイトをtuple
型でURLS
として定義しています。
URLS=(('stackoverflow','https://stackoverflow.com/questions/tagged/python'),('AWS','https://aws.amazon.com/lambda/'),('wikipedia AI','https://en.wikipedia.org/wiki/Artificial_intelligence'),('Docker','https://www.docker.com/resources/what-container'),('Python3.8 doc','https://docs.python.org/3/whatsnew/3.8.html'),)
単語の翻訳
中身はGoogle翻訳ですが、単語の翻訳もTextBlobライブラリを使用しています。NotTranslated
は、python
という単語のように、翻訳してもpython
となるようなものを翻訳しようとした時にraise
されるものになります。
try:meaning_jp=str(TextBlob(word).translate(to='ja'))exceptNotTranslated:meaning_jp=word
その他
お気づきになった方もいらっしゃるかもしれませんが、下記のコードで
forwordinfiltered_words:count=morph.words.count(word)ifcount==0:continueifwordnotinword_and_count.keys():word_and_count[word]=countelse:word_and_count[word]+=count
このように、カウントがゼロの場合、次のループへ移行する文があります。
count=morph.words.count(word)ifcount==0:continue
具体的にはe.g.,
のような文字列を解析した際、トークナイズ時はe.g.
、品詞毎に分解した際はe.g
となるため、e.g.,
のような単語がきた時にcount==0
となるのでこちらのコードを挿入しています。
自然言語処理とTextBlobの使い方に関してまだまだ勉強不足ですので、ある程度知見がたまったら別途TextBlobの使い方まとめ、みたいな形で記事を出した際に解説していきたいと思います。
実行結果
前回の問題点は無事改良されているのでしょうか................?
実行結果はこちら..................................!
the most common words
rank:1 word: intelligence count: 327 meanings: 知性
rank:2 word: artificial count: 280 meanings: 人工的な
rank:3 word: help count: 190 meanings: 助けて
rank:4 word: python count: 186 meanings: python
rank:5 word: error count: 184 meanings: エラー
rank:6 word: target count: 168 meanings: 目標
rank:7 word: new count: 134 meanings: 新着
rank:8 word: learning count: 129 meanings: 学習する
rank:9 word: machine count: 125 meanings: 機械
rank:10 word: have count: 120 meanings: 持ってる
the most uncommon words
rank:1 word: donate count: 1 meanings: 寄付
rank:2 word: math count: 1 meanings: 数学
rank:3 word: inspect count: 1 meanings: 調べる
rank:4 word: ignore count: 1 meanings: 無視する
rank:5 word: processor count: 1 meanings: プロセッサー
rank:6 word: queue count: 1 meanings: キュー
rank:7 word: depend count: 1 meanings: 依存する
rank:8 word: pretend count: 1 meanings: ふり
rank:9 word: decrease count: 1 meanings: 減少
rank:10 word: allocator count: 1 meanings: アロケータ
おおおおおおおおっ!
結論
まずはもう一度仮説に振り返ってみたいと思います。今回のシリーズでの仮説は
Pythonで自動的に作成すれば、
もう英単語帳購入の必要はないんじゃないか?
というものでした。
こちらの仮説に対しての結論としては、
英単語帳は購入しなくても、プログラムで作れる!
といえそうです!!!※2
【重要】市販のような英単語帳を作るには
実行結果をみていただければわかりますが、今回抽出できた単語だけでもかなり有用なことが分かります。ただ、市販の単語帳と同等のものを作るにはインターフェースと3つの追加情報が必要になってきます。
インターフェース
市販の単語帳には、本、もしくはアプリといった問題形式で覚えたり、内容の確認をしやすくするためのインターフェースを備えています。
今回のように自作英単語データを学習に使用したいという方には、私のブログでも紹介していますAnkiアプリが超おすすめです!!素のAtom使ってる人がIDEを使いこなした時ぐらい感動します!
先日Twitterでたまたま見かけたのですが、連続起業家で有名な家入一真さんもAnkiを使用しているようです。
会食が無い分、毎晩ずっとNGSL3000語、NAWL1000語、英単語を暗記しまくってる。AnkiとQuizlet便利すぎ
— 家入 一真@クラファンのCAMPFIRE (@hbkr) April 9, 2020
PC版は無料でインストールできるので、PCだけであれば完全無料で英単語学習ができそうです。※3
【英語学習に必須】Ankiアプリとは?
3つの情報
市販の英単語帳には通常、下記の3つの情報がほぼ確実に含まれています。
- 単語の翻訳詳細(品詞、他の意味)
- 例文
- 例文の翻訳
1.単語の翻訳詳細(品詞、他の意味)や2.例文に関してはTextBlobの機能を使えばうまく引っ張ってくることができるのですが、例文の翻訳が問題となってきます。
こちらの記事でも紹介しましたが、Google翻訳を使用して文章を翻訳するとコンテクストの問題やそもそもの翻訳が違うなどの問題がでてくるので、正しい学習ができない可能性があります。
まだGoogle翻訳で消耗してるの?
しかし
人力であれば、例文の自然な翻訳をしていくことはまだ可能です。
もし、私のTwitterのフォロワーが1000を超えたら、今回作成したプログラムをさらに改良し例文も含めた、
エンジニア向けの最強英単語帳
のデータを配布していきたいと思います。
英語学習に関するTipsや万が一英単語帳の配布が決定した場合のお知らせなどはこちらのTwitterで随時お知らせしていきますので、この機会にぜひフォローして頂けると幸いです。
(会社のPCだからフォローし辛いという方は、スマホで「hossyan-blog.com」もしくは「ほっしゃん エンジニア 英語」で検索してみてください。)
Twitter:ほっしゃん@エンジニア&英会話講師

データのダウンロード
私のブログのこちらのページから単語データのダウンロードと、10秒でできるAnkiへのデータインポート方法を紹介していますので、参考にしてみて下さい。
https://hossyan-blog.com/2020/04/26/how-to-download-text-data/
注釈
※1 下記のサイトを見た感じだと無視して良さそうです
https://en.wikibooks.org/wiki/Scrabble/Two_Letter_Words
https://en.wiktionary.org/wiki/Category:English_one-letter_words
※2 英単語帳を英単語とその翻訳のデータセットとして定義すれば
※3 Ankiさん、広告費貰えるわけでもないのに激推ししておきましたよ!