word2vecによるニュース記事の傾向分析

エネルギー関連のニュース記事を使い、word2vecを用いた記事内容の傾向を分析したので以下にまとめます。

**Jupyter Notebook**
Part 1 (前処理):
https://github.com/Jun-Tam/article_analysis_word2vec/blob/master/NLP_Articles_Preprocess.ipynb

Part 2 (傾向分析):
https://github.com/Jun-Tam/article_analysis_word2vec/blob/master/NLP_Articles_Word2Vec.ipynb

## 前処理
PyPDF2(https://github.com/mstamy2/PyPDF2/) を使い、PDFファイルからテキスト・メタデータを読み込む。

```python
import PyPDF2

pdfReader = PyPDF2.PdfFileReader(open(path_file,'rb'))  # PDFファイルを読み込む

text = ''
for i in range(pdfReader.numPages):
    # ページオブジェクトからテキストデータを取り込み
    pageObj = pdfReader.getPage(i)
    text_tmp = pageObj.extractText()

    # ページ毎にテキストを追加
    if i == 0:
        text += text_tmp
    else:
        text += '\n'.join(text_tmp.split('\n')[1:])
   # 追加の処理
```

追加処理は、正規表現による文字列処理、大文字を全て小文字に変換、イギリス英語からアメリカ英語への変換、lemmatize等です。
イギリス英語とアメリカ英語の綴りリストは、こちらのサイト（http://www.tysto.com/uk-us-spelling-list.html) を使いました。
lemmitizeとは、動詞の過去形や名詞の複数形等、活用・変化した単語を元の単語に戻すことを指します。以下に例を示します。

```python
from nltk.stem.wordnet import WordNetLemmatizer

verbs = ['made','has','laid','ground','flew']
verb_lmtzd = [WordNetLemmatizer().lemmatize(word,'v') for word in verbs] # 動詞を原形に変換
print(verb_lmtzd) # ['make', 'have', 'lay', 'grind', 'fly']

nouns = ['birds','shelves','shoes','children','news']
noun_lmtzd = [WordNetLemmatizer().lemmatize(word,'n') for word in nouns] # 名詞を複数形から単数形に変換
print(noun_lmtzd) # ['bird', 'shelf', 'shoe', 'child', 'news']
```

## Word Count
前処理が済んだテキストデータに対し、まずは全ての記事に出てくる単語の頻度をヒストグラムでプロットしてみます。

![word_count.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557224/3aef4caa-06b3-0d64-7008-2a7414dbd29b.png)

当然ですが、石油事業の記事が多いため、gasとoilが上位にきています。
なお、それ自身で意味を持たない冠詞や接続詞等は、stop wordsとして取り除いています。stop wordsのリストはnltkとsklearnの中に既に存在し、執筆時（2020年2月16日）で前者が179語、後者が318語と異なります。今回は、自ら定義したstop words listを含んだ和集合を用いました。

```python
import nltk
_ = nltk.download('stopwords', quiet=True)
stop_words_nltk = nltk.corpus.stopwords.words('english')

from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS as sklearn_stop_words
stop_words_sklearn = list(sklearn_stop_words)

stop_words_own = ['week','copyright','report','project','outlook','month','year','fact','bd',
                  'kbd','bcf','bcm','tcf','bcfd','boed','mmtpa','mmboe','million','billion']

stop_words = list(sklearn_stop_words.union(stop_words_nltk)) + stop_words_own
```

## TF-IDFとWord Cloud 
単語の頻度をそのまま扱って傾向分析を行うと、低頻度だけど重要な意味を持つ単語が埋もれてしまうため、Inverse Document Frequency (IDF)とTerm Frequency (TF)という指標を使って、各記事、各単語に対して重み係数を割り当てます。<br>
IDFは全記事に出てきた単語の頻度に応じて、各単語に与えられる係数です。高頻度ほど、小さくなります。
TFは記事内の全単語数に対する各単語の頻度の割合です。TFとIDFを掛けたTF-IDFが、各記事における各単語の重要さを表します。(参照：https://en.wikipedia.org/wiki/Tf–idf)

このようにして重み付けされた単語を年毎にまとめ、Word Cloud (https://github.com/amueller/word_cloud) で視覚化してみます。
全体的に中国とLNGが目立ちますが、近年の中国の石油開発事業の活発化とモザンビークや米国のLNGプロジェクトを反映しています。米国のシェールオイルブームは、2014年のEagle Fordや2017年のPermianが示しています。

![word_cloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557224/fe71f0b9-7305-d3bb-e918-fe8ab1ae8f9c.png)

## Word2Vec
次に、記事毎に作成された各単語の重要度をもとに、Word2Vec(https://radimrehurek.com/gensim/models/word2vec.html) を使った記事の定量化を行います。word2vecとは単語をベクトル表現化した辞書のようなもので、大量のニュース記事を用いた単語間の関係性の学習により作成されています。300万の各単語に対して300の要素を持つベクトルが格納されており、各要素の意味を見出すのは難しいですが、word2vec上のベクトル空間内で記事を比較することで、傾向分析が可能になります。

```python
from nlpia.data.loaders import get_data
word_vectors = get_data('word2vec')
```

## Ness vector
ベクトル表現化された記事に対して意味付けを行うため、ness vectorを使います。(参照：https://github.com/totalgood/nlpia/blob/master/src/nlpia/book/examples/ch06_nessvectors.py)
"ness"とは英語の形容名詞の接尾語を表すのですが（例: kindness）、word2vecを使って自ら~nessを定義することができます。
今回は、好景気、環境、北米・中南米、欧州、アジアの5つのnessに対し、以下のように連想される単語を使ってそれぞれ定義しました。

```python
ness_keys = ['Upturn','Environment','Americas','Europe','Asia']
COMPONENT_WORDS = dict([
    (ness_keys[0], 'upturn investment boom growth'.split()),    
    (ness_keys[1], 'climate environment renewable nature clean'.split()),
    (ness_keys[2], 'Americas America Latin_America Brazil Argentine US oil gas'.split()),
    (ness_keys[3], 'Europe Norway UK Russia oil gas'.split()),
    (ness_keys[4], 'Japan China Southeast_Asia oil gas'.split()),
])

ness_vectors = [component_vector(words,word_vectors) for (component, words) in COMPONENT_WORDS.items()]
```

## 傾向分析
ness vectorを使って記事をベクトル表現化し、四半期平均してプロットしました。

まずは、原油価格（上）と好景気ネス＆環境ネス（下）を示した図です。
![upturn_environment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557224/575002c9-399a-e249-3446-98d0a5c0db1b.png)
好景気ネスについては、油価と関連があるように見えますが、変化量は必ずしも油価に比例している訳ではなさそうです。
2014年の大暴落の際は、誤差バーが大きく楽観的な記事も多かったようですが、2016年に更に下落した際は悲観的な記事が支配的だったようです。
環境ネスについては、変動はあるものの緩やかな上昇傾向が確認でき、環境問題への意識の高まりを示唆しています。
<br>
次に、原油価格（上）と北米・中南米ネス ＆ 欧州ネス & アジアネス（下）を示した図です。
こちらも基本的には油価と連動しているように見えますが、2014－2015年の北米で起きたシェールブームや近年の中国の活発化が読み取れます。
![americas_europe_asia.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557224/623831b8-79e4-c5f9-68a7-4673863fa8af.png)