2018年7月27日金曜日

エネルギー基本計画から新語・複合語を探す。その1 gensim phrasesで複合語候補を探す(python,gensim.Phrases,自然言語処理,janome)

前回、gensim Phrasesを使って複合語を探す方法を書きました。複数回出てきた単語の組み合わせを学習して、複合語として取り出す方法です。

今回は、閣議決定された第5次エネルギー基本計画から複合語候補を取り出してみます。目標は、エネルギー基本計画から新語を取り出し、用語を辞書に登録することです。

ちなみに今まではエネルギー基本計画(案)を使っていましたが、今回からは正式版のエネルギー基本計画を使います。

資源エネルギー庁:第5次エネルギー基本計画
http://www.enecho.meti.go.jp/category/others/basic_plan/pdf/180703.pdf

下記のページを参考にしました。

gensim Phrase
https://radimrehurek.com/gensim/models/phrases.html
コード7区:gensim の Phrases の使い方。頻出する単語ペアを検出-python
http://ailaby.com/phrases/
コード7区:ツイートからユーザ辞書(MeCab や Janome 用)をpython で作ってみる
http://ailaby.com/tweet_dict/

・インポートとデータ読み込み
from gensim.models.phrases import Phrases , Phraser
from janome.tokenizer import Tokenizer
import pandas as pd

text_file=open("energy_plan.txt").read()
text_file

出力(一部)
'はじめに\n\n2011年3月の東日本大震災及び東京電力福島第一原子力発電所事故を受けて、政府は、2014年4月、2030年を念頭に、第4次エネルギー基本計画を策定し、原発依存度の低減、化石資源依存度の低減、再生可能エネルギーの拡大を打ち出した。\n第4次エネルギー基本計画の策定から4年、2030年の計画の見直しのみならず、パリ協定の発効を受けた2050年を見据えた対応、より長期には化石資源枯渇に備えた超長期の対応、変化するエネルギー情勢への対応など、今一度、我が国がそのエネルギー選択を構想すべき時期に来ている。このため、今回のエネルギー基本計画の見直しは、2030年の長期エネルギー需給見通し(2015年7月経済産業省決定。以下「エネルギーミックス」という。)の実現と2050年を見据えたシナリオの設計で構成することとした。

・janomeで分かち書き
tokenizer = Tokenizer()
corpus=[]

tokens = tokenizer.tokenize(text_file)
corpus.append([token.surface for token in tokens])
    
print(corpus)

出力(一部)
[['はじめ', 'に', '\n\n', '2', '0', '1', '1', '年', '3月', 'の', '東日本', '大震災', '及び', '東京電力', '福島', '第', '一', '原子力', '発電', '所', '事故', 'を', '受け', 'て', '、', '政府', 'は', '、', '2', '0', '1', '4', '年', '4月', '、', '2', '0', '3', '0', '年', 'を', '念頭', 'に', '、', '第', '4', '次', 'エネルギー', '基本', '計画', 'を', '策定', 'し', '、', '原発', '依存', '度', 'の', '低減', '、', '化石', '資源', '依存', '度', 'の', '低減', '、', '再生', '可能', 'エネルギー', 'の', '拡大', 'を', '打ち出し', 'た', '。', '\n', '第', '4', '次', 'エネルギー', '基本', '計画', 'の', '策定', 'から', '4', '年', '、', '2', '0', '3', '0', '年', 'の', '計画', 'の', '見直し', 'のみ', 'なら', 'ず', '、', 'パリ', '協定', 'の', '発効', 'を', '受け', 'た', '2', '0', '5', '0', '年', 'を', '見据え', 'た', '対応', '、', 'より', '長期', 'に', 'は', '化石', '資源', '枯渇', 'に', '備え', 'た', '超', '長期', 'の', '対応', '、', '変化', 'する', 'エネルギー', '情勢', 'へ', 'の', '対応', 'など', '、', '今', '一', '度', '、', '我が国', 'が', 'その', 'エネルギー', '選択', 'を', '構想', 'す', 'べき', '時期', 'に', '来', 'て', 'いる', '。', 'この', 'ため', '、', '今回', 'の', 'エネルギー', '基本', '計画', 'の', '見直し', 'は', '、', '2', '0', '3', '0', '年', 'の', '長期', 'エネルギー', '需給', '見通し', '(', '2', '0', '1', '5', '年', '7月', '経済', '産業', '省', '決定', '。', '以下', '「', 'エネルギー', 'ミックス', '」', 'と', 'いう', '。', ')', 'の', '実現', 'と', '2', '0', '5', '0', '年', 'を', '見据え', 'た', 'シナリオ', 'の', '設計', 'で', '構成', 'する', 'こと', 'と', 'し', 'た', '。']]

janomeで分かちがきし、リストに格納します。詳しくは前回記事をご参照ください。二重のリストにすることに注意。

・Phrasesで複合語を探す。4回繰り返し。
gramCnt = 5  
tokenizer = Tokenizer()
corpus_phrase=corpus

for i in range(gramCnt-1):
    phrases = Phrases(corpus_phrase,min_count=5, threshold=10.0)
    phraser = Phraser(phrases)
    transformed=list(phraser[corpus_phrase])

    corpus_phrase = transformed

for words in corpus_phrase:
    print(" ".join(words))

gensim Phrasesで複合語を探します。前回は1回ずつ計2回変換しましたが、今回はループで回して4回繰り返しました。

パラメーターのmin_count=5, threshold=10.0はデフォルト値です(なので省略も可)

・出力(一部)
はじめ に 

 2_0_1 1 年_3月 の 東日本_大震災 及び 東京電力_福島_第_一_原子力_発電_所_事故 を 受け て 、 政府 は 、 2_0_1_4 年_4月 、 2_0_3_0_年 を 念頭 に 、 第 4 次_エネルギー 基本_計画 を 策定_し 、 原発_依存_度 の 低減 、 化石_資源 依存_度 の 低減 、 再生_可能_エネルギー の 拡大 を 打ち出し た 。_
 第 4 次_エネルギー 基本_計画 の 策定 から 4 年 、 2_0_3_0_年 の 計画 の 見直し のみ_なら_ず 、 パリ_協定 の 発効 を 受け た 2_0_5_0_年 を 見据え_た 対応 、 より 長期 に は 化石_資源 枯渇 に 備え た 超 長期 の 対応 、 変化 する エネルギー_情勢 へ の 対応 など 、 今 一 度 、 我が国 が その エネルギー_選択 を 構想 す_べき 時期 に 来 て_いる_。 この_ため 、 今回 の エネルギー 基本_計画 の 見直し は 、 2_0_3_0_年 の 長期 エネルギー_需給 見通し (_2_0_1 5_年 7月 経済 産業 省 決定 。 以下 「 エネルギー_ミックス 」 と いう 。 ) の 実現 と 2_0_5_0_年 を 見据え_た シナリオ の 設計 で 構成 する_こと と し_た 。_

「東日本_大震災」「東京電力_福島_第_一_原子力_発電_所_事故」「再生_可能_エネルギー」などが複合語候補としてアンダーバーで結ばれました。

その一方、「て_いる_。」「する_こと と し_た 。_」など、複合語とは言えないフレーズも含まれています。

・複合語候補の取り出し
words_df=pd.DataFrame()

for sentence in corpus_phrase:
    for word in sentence:
        if word.find('_') >= 0:
            words_df=words_df.append([word])

words_df.columns=["複合語候補"]

words_df=(words_df.groupby("複合語候補")[["複合語候補"]].count()
       .sort_values(by="複合語候補",ascending=False)
       .rename(columns={'複合語候補': '回数'})
       .reset_index()
      )

words_df

Phrasesで変換した文章から複合語候補を取り出し、groupbyで出現回数を数えました。

・出力(一部)
複合語候補回数
0再生_可能_エネルギー171
1する_こと154
2。_\n135
3し_た128
4的_な118
5について_は91
6事業_者78
7する_ため72
8脱_炭素_化65
9し_て65
10し_て_いく65
11。_\n\n62
12。_また57
13技術_開発56
14可能_性55
15と_なる54
16新た_な53
17て_いく45
18中_で43
19し_て_いく_こと42
20必要_な42
21で_ある_。40
22さ_れる40
23で_あり39
24ある_。39
25に_加え38
26需要_家38
27安定_供給38
28観点_から37
29て_いる_。37
30し_て_いる36
31する_とともに36
32エネルギー_源36
33で_ある36
34こと_から36
35推進_する36
36エネルギー_需給_構造35
37に_向け_た35
38研究_開発35
39。_\n_また35
40廃_炉34
41て_いる33
42し_つつ33
43様々_な33
44化石_燃料32
45さ_れ_た32
46し_て_いる_。32
47安全_性31
48天然_ガス31
49に_向け_て30
50さ_れ30
51これ_まで30
52て_おり29
53LP_ガス29
54積極_的_に29
55国際_的_な28
56更_なる28
57使用_済_燃料28
58技術_革新28
59し_て_いく_ため27
60進め_て_いく27
61活用_し27
62着実_に26
63上_で26
64燃料_電池26
65について_も25
662_025
67重要_な25
68さ_せる25
69多様_な25
70において_も25
71温室_効果_ガス25
72供給_構造25
73効率_化25
74に_資する24
75安定_的_な24
76調整_力24
77。_さらに24
78分散_型_エネルギー_システム24
79行う_こと24
80に_向け_た_取組24
81さ_れ_て_いる23
82FIT_制度23
83電源_として23
84ある_。_\n23
85この_ため23
862_0_5_0_年23
87に_係る23
88エネルギー_選択23
89活用_し_た22
90電力_システム_改革22
91に_基づき22
92多様_化22
93に_取り組む22
94エネルギー_消費22
95エネルギー_需要22
962_0_3_0_年22
97(_2_0_122
98導入_拡大21
99パリ_協定21
100石油_製品21
101東京電力_福島_第_一_原子力_発電_所_事故21
102含め_た21
103競争_力21
104低_炭素_化20
105優れ_た20
106エネルギー_安全_保障20
107進める_。20
108エネルギー_転換20
109実現_する20
110中長期_的_な20
111サプライ_チェーン20
112で_ある_。_\n20
113エネルギー_政策20
114と_なり19
115高度_化19
116通じ_た19
117促進_する19
118具体_的19
119活性_化19
120のみ_なら_ず19
121この_よう_な19
122踏まえ_つつ19
123排出_量19
124できる_よう19
125エネルギー_転換_・_脱_炭素_化19
126と_なっ_て_いる18
127も_含め18
128に_基づく18
129必要_と_なる18
130新興_国18
1312_0_2_018
132て_いる_。_\n18
133適切_な18
134分散_型18
135可能_と_する18
136に_なる18
137エネルギー_分野17
138進める_こと17
139適切_に17
140に_応じ_て17
141エネルギー_ミックス17
142進める_。_\n\n17
143形_で17
144最終_処分17
145強靱_化16
146基本_計画16
147必要_が16
148し_て_き_た16
149た_場合16
150原子力_発電_所16

助詞や句読点などが含まれているものが多くありますが、「再生可能エネルギー」「脱炭素化」「温室効果ガス」などが見つかりました。
「分散型エネルギーシステム」「調整力」「電力システム改革」などのエネルギー用語もあります。

次回以降、この複合語候補から辞書登録する用語を選択してみます。


参考:
資源エネルギー庁:第5次エネルギー基本計画 http://www.enecho.meti.go.jp/category/others/basic_plan/pdf/180703.pdf
gensim Phrase
https://radimrehurek.com/gensim/models/phrases.html
gensim Phrase
https://radimrehurek.com/gensim/models/phrases.html
コード7区:gensim の Phrases の使い方。頻出する単語ペアを検出-python
http://ailaby.com/phrases/
コード7区:ツイートからユーザ辞書(MeCab や Janome 用)をpython で作ってみる http://ailaby.com/tweet_dict/
Janomeで形態素解析をやってみる。
http://eneprog.blogspot.com/2018/06/janomepython.html
janome Analayzerで複合語(複合名詞)を考慮して形態素解析を行う。
http://eneprog.blogspot.com/2018/07/janome-analayzerpython.html
gensim Phrasesで新語・複合語を探す(python、自然言語処理、機械学習)
https://eneprog.blogspot.com/2018/07/gensim-phrasespython.html

2018年7月24日火曜日

gensim Phrasesで新語・複合語を探す(python、自然言語処理、機械学習)

janome Analayzerで複合語(複合名詞)を考慮して形態素解析を行う。という記事を書きましたが、janome Analyzerでは名詞+名詞=複合名詞とするため、「脱炭素」など接頭詞がついたものは名詞とみなされませんでした。

今回は、機械学習ライブラリgensimのPhrasesを使って、複数回出現した単語の組み合わせを複合語として取り出す方法をやってみます。

gensim Phrase
https://radimrehurek.com/gensim/models/phrases.html

下記ブログ記事が大変詳しく解説されていて参考になりました。

コード7区:gensim の Phrases の使い方。頻出する単語ペアを検出-python
http://ailaby.com/phrases/

・インストール
!pip install gensim

gennsimのインストールはpipでできます。

・インポート
from gensim.models.phrases import Phrases , Phraser
from janome.tokenizer import Tokenizer

gensimからPhrasesとPhraserをインポートします。

・サンプル文章(エネルギー基本計画より)
text="""原子力発電所事故の経験、反省と教訓を肝に銘じて取り組むことが原点であるという姿勢は一貫して変わらない。
原子力発電所事故は、周辺国を含む国際社会に大きな不安をもたらしている。
太陽光や風力など変動する再生可能エネルギーはディマンドコントロール、揚水、火力等を用いた調整が必要であり、それだけでの完全な脱炭素化は難しい。
再生可能エネルギー・蓄電・デジタル制御技術等を組み合わせた脱炭素化エネルギーシステムへの挑戦が、幅広い産業を巻き込んで加速しつつある。"""

上記の4文をサンプルにして、Phraserに読ませる形式に変換します。
目標は

[['原子力', '発電', '所', '事故', 'の', '経験'],['変動', 'する', '再生', '可能', 'エネルギー']]

のように、二重リストの中に分かち書きされた各文書が格納されている状態です。

・改行で分割
text_split=text.split("\n")
['原子力発電所事故の経験、反省と教訓を肝に銘じて取り組むことが原点であるという姿勢は一貫して変わらない。',
 '原子力発電所事故は、周辺国を含む国際社会に大きな不安をもたらしている。',
 '太陽光や風力など変動する再生可能エネルギーはディマンドコントロール、揚水、火力等を用いた調整が必要であり、それだけでの完全な脱炭素化は難しい。',
 '再生可能エネルギー・蓄電・デジタル制御技術等を組み合わせた脱炭素化エネルギーシステムへの挑戦が、幅広い産業を巻き込んで加速しつつある。']

・分かち書きしてリストに格納
tokenizer = Tokenizer()
corpus=[]

for text_list in text_split:

    tokens = tokenizer.tokenize(text_list)
    corpus.append([token.surface for token in tokens])
    
print(corpus)
[['原子力', '発電', '所', '事故', 'の', '経験', '、', '反省', 'と', '教訓', 'を', '肝', 'に', '銘じ', 'て', '取り組む', 'こと', 'が', '原点', 'で', 'ある', 'という', '姿勢', 'は', '一貫', 'し', 'て', '変わら', 'ない', '。'], ['原子力', '発電', '所', '事故', 'は', '、', '周辺', '国', 'を', '含む', '国際', '社会', 'に', '大きな', '不安', 'を', 'もたらし', 'て', 'いる', '。'], ['太陽光', 'や', '風力', 'など', '変動', 'する', '再生', '可能', 'エネルギー', 'は', 'ディマンドコントロール', '、', '揚水', '、', '火力', '等', 'を', '用い', 'た', '調整', 'が', '必要', 'で', 'あり', '、', 'それ', 'だけ', 'で', 'の', '完全', 'な', '脱', '炭素', '化', 'は', '難しい', '。'], ['再生', '可能', 'エネルギー', '・', '蓄電', '・', 'デジタル', '制御', '技術', '等', 'を', '組み合わせ', 'た', '脱', '炭素', '化', 'エネルギー', 'システム', 'へ', 'の', '挑戦', 'が', '、', '幅広い', '産業', 'を', '巻き込ん', 'で', '加速', 'し', 'つつ', 'ある', '。']]

janomeで分かち書きして、リスト内包表記でリストに格納しています。

janomeの使い方はこちらをご覧ください。

・準備
tokenizer = Tokenizer()
corpus_phrase=corpus
phrases=""
bigram=""
transformed_bi=[]

・Phrasesで学習、Phraserでモデルを作る
phrases = Phrases(corpus_phrase,min_count=1, threshold=1.0)
bigram = Phraser(phrases)

まず、Phrasesで文章を学習します。

パラメーターでmin_countとthresholdがでてきますが、
  • 単語と単語の組み合わせが出現した回数がmin_count以下の場合、無視されます。
  • thresholdは閾値で、単語と単語の組み合わせ出現回数、各単語の出現回数などでスコアが決まり、スコアがこの値よりも大きい場合に複合語とされます。
スコアについての詳細は下記をご覧ください。

https://radimrehurek.com/gensim/models/phrases.html#gensim.models.phrases.npmi_scorer

今回は4文章と少ないので、min_count、thresholdともに1とし、2回以上単語の組み合わせが出てきた場合は複合語とみなします。

・phraserで作ったモデルで元の文章を変換
transformed_bi=list(bigram[corpus_phrase])

for words in transformed_bi:
    print(" ".join(words))
原子力_発電 所_事故 の 経験 、 反省 と 教訓 を 肝 に 銘じ て 取り組む こと が 原点 で ある という 姿勢 は 一貫 し て 変わら ない 。
原子力_発電 所_事故 は 、 周辺 国 を 含む 国際 社会 に 大きな 不安 を もたらし て いる 。
太陽光 や 風力 など 変動 する 再生_可能 エネルギー は ディマンドコントロール 、 揚水 、 火力 等_を 用い た 調整 が 必要 で あり 、 それ だけ で の 完全 な 脱_炭素 化 は 難しい 。
再生_可能 エネルギー ・ 蓄電 ・ デジタル 制御 技術 等_を 組み合わせ た 脱_炭素 化 エネルギー システム へ の 挑戦 が 、 幅広い 産業 を 巻き込ん で 加速 し つつ ある 。

モデル(bigram)で元の文章を変換します。複合語とみなした組み合わせはアンダーバーで結ばれています。

ここでは「原子力_発電」「所_事故」「再生_可能」「脱_炭素」などが複合語となりました。2つの単語の組み合わせ(bigram)のみを考慮しているので、「原子力_発電_所」や「再生_可能_エネルギー」とはなっていません。

ここで作った文章(transformed_bi)を用いて、もう一度学習、変換することで3つ(最大4つ)の単語による複合語を見つけることができます。

・trigramを見つける
tri_phrases = Phrases(transformed_bi,min_count=1, threshold=1.0)
trigram=Phraser(tri_phrases)
transformed_tri=list(trigram[transformed_bi])

for words in transformed_tri:
    print(" ".join(words))
原子力_発電_所_事故 の 経験 、 反省 と 教訓 を 肝 に 銘じ て 取り組む こと が 原点 で ある という 姿勢 は 一貫 し て 変わら ない 。
原子力_発電_所_事故 は 、 周辺 国 を 含む 国際 社会 に 大きな 不安 を もたらし て いる 。
太陽光 や 風力 など 変動 する 再生_可能_エネルギー は ディマンドコントロール 、 揚水 、 火力 等_を 用い た 調整 が 必要 で あり 、 それ だけ で の 完全 な 脱_炭素_化 は 難しい 。
再生_可能_エネルギー ・ 蓄電 ・ デジタル 制御 技術 等_を 組み合わせ た 脱_炭素_化 エネルギー システム へ の 挑戦 が 、 幅広い 産業 を 巻き込ん で 加速 し つつ ある 。

「原子力_発電_所_事故」「再生_可能_エネルギー」などができました。

・変換後の文章から複合語を取り出す。
phraseWords=[]

for sentence in transformed_tri:
    for word in sentence:
        if word.find('_') >= 0 and word not in phraseWords:
            p_word=word
            print(p_word)
            phraseWords.append(word)
原子力_発電_所_事故
再生_可能_エネルギー
等_を
脱_炭素_化

再生可能エネルギー、脱炭素化はいいのですが、「等_を」という単語の組み合わせも入っています。これは品詞を考慮せずに特定の単語の組み合わせを複合語としているためです。また、原子力発電所事故は「原子力発電所」で1単語としたいところです。

次回以降、品詞をもとに複合語の判定をしてみます。


参考:
gensim Phrase
https://radimrehurek.com/gensim/models/phrases.html
コード7区:gensim の Phrases の使い方。頻出する単語ペアを検出-python
http://ailaby.com/phrases/

Janomeで形態素解析をやってみる。
http://eneprog.blogspot.com/2018/06/janomepython.html
janome Analayzerで複合語(複合名詞)を考慮して形態素解析を行う。
http://eneprog.blogspot.com/2018/07/janome-analayzerpython.html

2018年7月20日金曜日

Coursera machine learning コースを始めました。edX UCバークレーFoundations of Data Scienceとの違いなど(オンライン学習、機械学習、mooc)

edX UCバークレー データサイエンス基礎(Foundations of Data Science)コースに続き、有名なCoursera machine learningコースを始めました。現在、week2が終わったところです。

Coursera machine learningコース
https://www.coursera.org/learn/machine-learning

スタンフォード大学のAndrew Ng教授の人気講座で、ブログ記事などで評判を見かけ、やってみることにしました。すでにいろんな方が講座の内容などを紹介されていますので、ここでは主にedX UCバークレーコース(以下、edX Data8)との違いを書いてみたいと思います。

受講は基本的には無料、終了証の発行には8680円(日本円)が必要になります。これはedX Data8と同じで、Courseraの方が少し安いです。

edX Data8の方は、開講期間が決まっていて一斉にスタートするのに対し、Courseraコースはいつでも開始可能です。ただし、受講のペースは決まっていて、1週間の課題を○○日までに送信するようにというアナウンスが出ます。



オンライン学習では一定のペースで続けることが難しくなってくるので、こういう締め切りがあるのはいいことだと思います。(すでに締め切りに追われていますが。。。)

edX Data8ではdiscussionを見ると自分が疑問に思ったことについて誰かが質問していて、それに対する回答も多く寄せられており、一緒に勉強している感がありましたが、Courseraは一斉にスタートするわけではないためか、discussionはあまり活発に動いていないようです(そもそも、コードをdiscussionに載せることが禁止されている)。

代わりに、ブログ等での解説記事はたくさんあるので、こちらを参考にできます。

edX Data8コースとの最大の違いは、日本語字幕があることでしょうか。



講義動画に日本語字幕を出せます。ダウンロードも可能。これは機械翻訳ではなく、ボランティアの有志で付けられているそうです。各単元で翻訳者が違っていて、時々分かりにくかったり、字幕がずれていたりすることもありますが、専門用語も日本語で書かれているので後で調べる際にもとても役に立ちます。

edX Data8の方は英語のみなので、やはりハードルは高いですね。

講義は、Andrew教授がスライドに書き込みを入れるスタイルで進んでいきます。



評判どおり、平易な言葉で解説されていて大変分かりやすいです(理解できているかはまた別問題)。week1では、行列の足し算などの計算から復習がありました。難しいと思うところもありますが、その都度、ここは覚えなくていい、難しいから理解できなくてもいいという言葉もあり、励みにしながらとりあえず進めています。

edX Data8では、講義もjupyter notebookのpythonを動かしながら進むので、動画を見ながら一緒に手を動かすことができるのですが、Courseraの方は通常の学校などの授業と同様、講義を聴く感じになっています。



講義動画の途中に、ところどころで動画が止まり上記のようなクイズが出題されます。動画を見ているだけでは何となく聞き流してしまうので、このクイズは理解度を深める上でとてもよい仕組みだと思います。

プログラミング課題では、OctaveまたはMatlabを使います。Octaveはフリーソフト、Matlabは有料ですがオンライン版でコース受講中に使える無料パスがあるようです。私はOctaveをインストールしました。edX Data8ではpython、jupyter notebook等の環境構築が必要なかったので、この点ではedX Data8の方が楽です。

GNU Octave
https://www.gnu.org/software/octave/

上記からGNU Octaveをインストールしました。バージョンは最新版で4.40です。コースの注意書きで4.0はインストールするなとありましたが、いまのところ普通に動いているようです。



Octaveの画面。Octaveは行列計算に特化した感じで、とてもシンプルな言語になっているようです。week2の講義資料にOctaveのチュートリアルがあり、このチュートリアルを見ながら練習しました。pythonでやったらいいのにとも思いましたが、Andrew Ng教授によると、pythonなどを使うよりもOctaveの方がスムーズに操作・理解できるとのことです。

edX Data8でもpythonのpandas等の普段使うモジュールではなく、より簡易化した独自モジュールを使って演習をしているので、同じような考え方なのだと思います(edX Data8では特定のプログラミング言語を学ぶのではなく、データサイエンスの基礎を学ぶのだとの記載あり)。

このCourseraコースでは1週間で動画講義と項目ごとのテスト、最後にプログラミング課題という構成になっています。プログラミング課題は全て英語で、ほとんど図もないpdfで記載されていて、ちょっと戸惑いました。課題のpdfではヒントも少なく、1週間分の講義内容を課題にしているため忘れている部分もあったので、動画講義の進行に合わせて、プログラミング課題も少しずつ進めたほうがいいかもしれません。

課題についてはgithubなどに回答例がたくさんあります。他の人のコードを写すのは禁止とされていますが、分からなければ参考にするのもいいと思います。コードを見ると、そういうことかと理解できるところがありました。(ただし、間違っている例もあるので要注意)

以上、長くなりましたが、全体としてこのコースは機械学習の理論を学ぶのに大変よいと思いますが、数学的な話が主で手を動かしながらという感じでもなく、モチベーションが高くないと続けるのが少し難しい気がします。

まだweek2が終わったところなので、どこまでできるか分かりませんが、出来るところまでやってみようと思います。


参考:
Coursera machine learningコース
https://www.coursera.org/learn/machine-learning
edX UCバークレー データサイエンス基礎講座

https://www.edx.org/professional-certificate/berkeleyx-foundations-of-data-science
プログラミング学習:edx UCバークレー データサイエンス基礎講座の紹介(python)
https://eneprog.blogspot.com/2018/04/edx-uc-python.html
プログラミング学習:edx UCバークレー データサイエンス基礎講座、第2弾受講中(python)
https://eneprog.blogspot.com/2018/06/edx-uc-2python.html

追伸:edX UCバークレー データサイエンス基礎コース 第3弾、機械学習コースが2018年7月24日に始まります。こちらも受講申し込み済みです。

Foundations of Data Science: Prediction and Machine Learning
https://www.edx.org/course/foundations-data-science-prediction-uc-berkeleyx-data8-3x

2018年7月13日金曜日

ハローワークの求人情報を見てみる。賃金分布、地域、業種(python,pandas,matplotlib)

前回、ハローワークインターネットサービスから求人一覧を取得しました。

ハローワークインターネットサービスから求人情報を取得する
http://eneprog.blogspot.com/2018/07/pythonpandas.html

今回はこのデータの中身を見てみます。

・インポートとデータ読み込み
import pandas as pd
from time import sleep

import matplotlib
import matplotlib.pyplot as plt

tables=pd.read_csv("ehime_job.csv",encoding="CP932")
tables.head()
Unnamed: 0NO求人番号職種雇用形態/賃金(税込)就業時間/休日/週休二日産業沿線/就業場所受理日
0NEW!◎113040- 82018581ルームアドバイザー職/新居浜駅前店正社員/182,000円~182,000円変形 1年単位1)10:00~19:00/他/その他不動産業,物品賃貸業のうち不動産代理業・仲介業愛媛県新居浜市平成30年7月9日
1NEW!◎213170- 30358781施工管理/松山市(要普免) 【急募】正社員/230,000円~400,000円1)08:00~17:00/土日/毎週不動産業,物品賃貸業のうち建物売買業,土地売買業愛媛県松山市平成30年7月9日
2NEW!◎321010- 26058881メディカルスタッフ(たんぽぽ薬局今治喜田村店)正社員/167,800円~200,000円変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:0...卸売業・小売業のうち医薬品・化粧品小売業愛媛県今治市平成30年7月9日
3NEW!◎427020- 46421181フィールドサービス(松山市)**急募**正社員/150,000円~225,000円変形 1年単位1)08:35~18:30/他/毎週卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日
4NEW!◎527020- 46422081営業職(プレゼン型)松山市★東証一部上場★メーカー正社員/150,000円~225,000円変形 1年単位1)08:35~18:30/土日祝他/毎週卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日

愛媛県のフルタイム正社員の求人情報、7575件です。

「雇用形態/賃金(税込)」と「就業時間/休日/週休二日」は複数の情報が一つのカラムに入っているので分割し、データを整理します。

・「雇用形態/賃金(税込)」の整理
table2=(tables["雇用形態/賃金(税込)"]
        .str.replace("円~","/")
        .str.replace("円","")
        .str.replace(",","")
        .str.split("/",expand=True)
       )

able2.columns=["雇用形態","賃金(最低)","賃金(最大)"]
table2=table2[["賃金(最低)","賃金(最大)"]].astype(int)
table2.head() 
賃金(最低)賃金(最大)
0182000182000
1230000400000
2167800200000
3150000225000
4150000225000


「雇用形態/賃金(税込)」列には「正社員/182,000円~182,000円」というように"雇用形態","賃金(最低)","賃金(最大)"の3つの情報が入っています。区切り文字を"/"に統一し、不要な文字("円",コンマ)を削除して、splitで列を分割します。

その後、列名をつけ、「賃金(最低)」「賃金(最大)」を数値に変換しました。

・「就業時間/休日/週休二日」の分割
table3=tables["就業時間/休日/週休二日"].str.split("/",expand=True)
table3.columns=["就業時間","休日","週休二日"]
table3.head()
就業時間休日週休二日
0変形 1年単位1)10:00~19:00他その他
11)08:00~17:00土日毎週
2変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:00日祝他毎週
3変形 1年単位1)08:35~18:30他毎週
4変形 1年単位1)08:35~18:30土日祝他毎週

同様に「就業時間/休日/週休二日」も3つに分割します。

・データ結合
job_table=(pd.concat([tables,table2,table3],axis=1)
           .drop(["雇用形態/賃金(税込)","就業時間/休日/週休二日"],axis=1)
          )
job_table.head()
Unnamed: 0NO求人番号職種産業沿線/就業場所受理日雇用形態賃金(最低)賃金(最大)就業時間休日週休二日
0NEW!◎113040- 82018581ルームアドバイザー職/新居浜駅前店不動産業,物品賃貸業のうち不動産代理業・仲介業愛媛県新居浜市平成30年7月9日正社員182000182000変形 1年単位1)10:00~19:00他その他
1NEW!◎213170- 30358781施工管理/松山市(要普免) 【急募】不動産業,物品賃貸業のうち建物売買業,土地売買業愛媛県松山市平成30年7月9日正社員2300004000001)08:00~17:00土日毎週
2NEW!◎321010- 26058881メディカルスタッフ(たんぽぽ薬局今治喜田村店)卸売業・小売業のうち医薬品・化粧品小売業愛媛県今治市平成30年7月9日正社員167800200000変形 1ヶ月単位1)08:30~17:302)08:30~13:303)09:00~18:00日祝他毎週
3NEW!◎427020- 46421181フィールドサービス(松山市)**急募**卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日正社員150000225000変形 1年単位1)08:35~18:30他毎週
4NEW!◎527020- 46422081営業職(プレゼン型)松山市★東証一部上場★メーカー卸売業・小売業のうち各種商品卸売業愛媛県松山市平成30年7月9日正社員150000225000変形 1年単位1)08:35~18:30土日祝他毎週

データ結合し、表の完成です。

ここから中身を見てみます。

・求人の多い地域
job_area=job_table.groupby("沿線/就業場所")[["沿線/就業場所"]].count().sort_values(by="沿線/就業場所", ascending=False)
job_area[:10] 
沿線/就業場所
沿線/就業場所
愛媛県松山市2853
愛媛県今治市894
愛媛県新居浜市734
愛媛県西条市620
愛媛県四国中央市612
愛媛県宇和島市321
愛媛県大洲市240
愛媛県八幡浜市198
愛媛県伊予郡松前町150
愛媛県東温市150

groupbyで「沿線/就業場所」をグループ化し、データ数を数えました。

松山市の求人数がダントツで多いです。続いて今治市、西条市、新居浜市となっています。

・求人の多い業種
job_table.groupby("産業")[["産業"]].count().sort_values(by="産業", ascending=False)[:10]
産業
産業
医療,福祉のうち老人福祉・介護事業1025
医療,福祉のうち病院478
運輸業,郵便業のうち一般貨物自動車運送業319
建設業のうち一般土木建築工事業246
製造業のうち船舶製造・修理業,舶用機関製造業229
医療,福祉のうち一般診療所207
建設業のうち土木工事業(舗装工事業を除く)143
卸売業・小売業のうち自動車小売業108
卸売業・小売業のうち医薬品・化粧品小売業108
医療,福祉のうち歯科診療所107

産業別では、医療、介護系が最も多く、運輸、建設・製造と続いています。

・賃金の統計量
table2[["賃金(最低)","賃金(最大)"]].describe()
賃金(最低)賃金(最大)
count7575.0000007575.000000
mean167828.605545224215.472871
std35528.51465972106.315667
min45000.00000050000.000000
25%147000.000000173000.000000
50%162500.000000210000.000000
75%184817.000000260000.000000
max416667.000000791666.000000

.describe()で賃金情報の統計量を見てみます。

賃金(最低)の平均は167,828円、中央値162,500円で、賃金(最大)では平均224,215円、中央値210000と平均値と中央値の差は小さくなっています。

・賃金の分布
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams["font.size"] = 16

table2.plot(y=["賃金(最低)","賃金(最大)"],bins=20,alpha=0.5,range=(0,600000),kind="hist",figsize=(10,5))


matplotlibで日本語を表示させると文字化けするので、plt.rcParams['font.family']でフォントを指定しています。alpha=0.5は色の透過度の指定です。

赤色、賃金(最低)では16万円に大きな山となり分布範囲は小さくなっています。このくらいの求人が多いということですね。青色、賃金(最高)の方は最頻値が20万円程度で最低よりも分布が広く、やや右に裾の長いグラフになりました。

参考:
ハローワークインターネットサービス
https://www.hellowork.go.jp/index.html

プログラミング学習:pandasでweb上の表を取得する。
https://eneprog.blogspot.com/2018/04/pandaswebpython.html
ハローワークインターネットサービスから求人情報を取得する
http://eneprog.blogspot.com/2018/07/pythonpandas.html

2018年7月11日水曜日

ハローワークインターネットサービスから求人情報を取得する(python,pandas,スクレイピング)

私は現在、求職中です。どんな求人があるのか気になるので、ハローワークインターネットサービスから求人情報を取得してみることにしました。

ハローワークインターネットサービス 求人情報基本条件入力
https://www.hellowork.go.jp/servicef/130020.do?action=initDisp&screenId=130020


上記から検索条件を指定して検索すると、職種、雇用形態、賃金などが記載された「求人情報一覧」という表がでてきます。



この表を取得することを目指します。

・インポート
import pandas as pd
from time import sleep

pandasのほか、timesのsleepをインポート。sleepは一時的に処理を止めるときに使います。

・URLを作る
pageno=1

url=("https://www.hellowork.go.jp/servicef/130050.do?"
     "fwListNaviBtn1=1&"
     "fwListNowPage=1&"
     "fwListLeftPage=" + str(pageno) +"&" #ページ番号
     "fwListNaviCount=1&"
     "kyujinShuruiHidden=1&" #フルタイム
     "koyoKeitaiHidden=1&" #正社員
     "todofukenHidden=38&" #愛媛県
     "screenId=130050&"
     "xab_vrbs=detailJokenDispButton,commonNextScreen,detailJokenChangeButton,commonDetailInfo")

情報を取得するURLを作成します。普通に検索しただけではURLが出てこないので、ソースと下記ページを参考に作りました。

ハローワークの一覧を簡易クロールして求人ページのURLを抽出する

今回は「フルタイム」「正社員」「愛媛県」の求人を指定しました。それぞれの数値はソースなどで確認してください。また、URLの前半部分の「13050」とscreenIdは変更することがあるようです。

・表の取得
df_tmp=pd.read_html(url,match="求人番号",header=0)
df=df_tmp[0]

作成したURLからread_htmlで表を取得します。read_htmlの使い方は以前書きました。

プログラミング学習:pandasでweb上の表を取得する。(python)

read_htmlでは、webページ上の表を一つずつリストとして取得します。上記記事ではリスト番号から目的の表を探しましたが、今回は match="求人番号"で"求人番号"という言葉が含まれている表だけを取得しています。header=0で1行目を列名として使います。

df=df_tmp[0]で目的の表を取り出し。match指定していしているので目的の表1つだけがdf_tmpに取得されているはずです(要確認)

・複数ページ取得
tables=pd.DataFrame()

for pageno in range(1,4):
    print(pageno)
    url=("https://www.hellowork.go.jp/servicef/130050.do?"
       "fwListNaviBtn1=1&"
       "fwListNowPage=1&"
       "fwListLeftPage=" + str(pageno) +"&"
       "fwListNaviCount=1&"
       "kyujinShuruiHidden=1&" #フルタイム
       "koyoKeitaiHidden=1&" #正社員
       "todofukenHidden=38&" #愛媛県
       "screenId=130050&"
       "xab_vrbs=detailJokenDispButton,commonNextScreen,detailJokenChangeButton,commonDetailInfo")
    
    df_tmp=pd.read_html(url,match="求人番号",header=0)
    tables=tables.append(df_tmp[0]).reset_index(drop=True)
    
    sleep(1)


1~3ページ目まで取得する例です。各ページの表をtablesにappendで結合します。ページ移行時にsleepで1秒待機しています。

出力(一部)
Unnamed: 0NO求人番号職種雇用形態/賃金(税込)就業時間/休日/週休二日産業沿線/就業場所受理日
0NEW!◎2138010- 23863381一般作業正社員/206,100円~274,800円変形 1ヶ月単位1)08:15~17:00/日他/その他建設業のうち一般土木建築工事業愛媛県伊予郡松前町平成30年7月10日
1NEW!◎2238010- 23866581運転手(大型)正社員/250,000円~400,000円変形 1ヶ月単位1)08:00~17:00/他/その他運輸業,郵便業のうち特定貨物自動車運送業愛媛県松山市平成30年7月10日
2NEW!◎2338010- 23868781介護支援専門員(施設)正社員/165,000円~220,000円変形 1ヶ月単位1)08:30~17:30/他/その他医療,福祉のうち老人福祉・介護事業愛媛県東温市平成30年7月10日
3NEW!◎2438010- 23886881大型車両整備士正社員/287,086円~337,098円1)08:30~17:30/日祝他/その他運輸業,郵便業のうち一般貨物自動車運送業愛媛県東温市平成30年7月10日
4NEW!◎2538010- 23893781看護師・准看護師正社員/190,000円~240,000円変形 1ヶ月単位1)08:45~18:152)08:45~18:303)08:45~12:4...医療,福祉のうち一般診療所愛媛県松山市平成30年7月10日


無事、一覧表の取得が出来ました。これを整理して、ざっくりどんな業種・地域に求人が多いかや賃金の傾向などを見てみたいと思います。


参考:
//SyntaxHighlighter CDNより https://cdnjs.com/libraries/SyntaxHighlighter // 対応言語