毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/8/10【48日目】Pythonでやっとword2vecを使えた

昨日は文章ごとのリストができましたので、先に進めて行きます。 次は各文章ごとの特徴を抜き出して行くようです。

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(analyzer = "word",
                             tokenizer = None,
                             preprocessor = None,
                             stop_words = None,
                             max_features = 5000) 
train_data_features = vectorizer.fit_transform(clean_train_reviews)
train_data_features = train_data_features.toarray()
print(train_data_features.shape)

実行結果。

(25000, 5000)

25000列の5000特徴量ができたようです。特徴量の指定ってできたんですね。変数に代入して出力するとこんな感じです。

vocab = vectorizer.get_feature_names()
print(vocab)

実行結果。

['abandoned', 'abc', 'abilities', 'ability', 'able', 'abraham', 'absence', 'absent', 'absolute', 'absolutely', 'absurd', 'abuse', 'abusive', 'abysmal', 'academy', 'accent', 'accents', 'accept', 'acceptable', 'accepted', 'access', 'accident', 'accidentally', 'accompanied', 

単語の出現回数を数えたいときは、NumPyのsumメソッドを使用するそう。

import numpy as np

dist = np.sum(train_data_features, axis=0)
print(dist)

実行結果。

[187 125 108 ..., 740 518 147]

zipメソッドでまとめるのはかわらず。

for tag, count in zip(vocab, dist):
    print(count, tag)
187 abandoned
125 abc
108 abilities
454 ability
1259 able
85 abraham
116 absence
83 absent

特徴量が取得できましたら、あとはランダムフォレストで学習させれば良いそうです。

from sklearn.ensemble import RandomForestClassifier

forest = RandomForestClassifier(n_estimators = 100) 
forest = forest.fit( train_data_features, train["sentiment"] )

同じようにテストデータも分析できる形にして、predictすれば分類結果が使えるようになります(今回はやらないですが)。

肝心のword2vecを利用する

word2vecを使用するにはgensimというライブラリが必要だそうなので、pip installでインストールしてします。

pip install gensim

コード内でimportしてみます。

from gensim.models import word2vec

あとの処理は、ほとんどさっきと同じです。

tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')

def review_to_sentences( review, tokenizer, remove_stopwords=False ):
    raw_sentences = tokenizer.tokenize(review.strip())
    sentences = []
    for raw_sentence in raw_sentences:
        if len(raw_sentence) > 0:
            sentences.append( review_to_wordlist( raw_sentence, remove_stopwords ))

    return sentences

sentences = [] 

print("Parsing sentences from training set")
for review in train["review"]:
    sentences += review_to_sentences(review, tokenizer)

print("Parsing sentences from unlabeled set")
for review in unlabeled_train["review"]:
    sentences += review_to_sentences(review, tokenizer)

こうするとセンテンスのリストごとに特徴量ができるらしいです。

print(sentences[3])
['some', 'of', 'it', 'has', 'subtle', 'messages', 'about', 'mj', 's', 'feeling', 'towards', 'the', 'press', 'and', 'also', 'the', 'obvious', 'message', 'of', 'drugs', 'are', 'bad', 'm', 'kay', 'visually', 'impressive', 'but', 'of', 'course', 'this', 'is', 'all', 'about', 'michael', 'jackson', 'so', 'unless', 'you', 'remotely', 'like', 'mj', 'in', 'anyway', 'then', 'you', 'are', 'going', 'to', 'hate', 'this', 'and', 'find', 'it', 'boring']

あとはこのデータをword2vecのモデルに入れて完成のようです。

num_features = 300    # ワードベクトルの次元数                      
min_word_count = 40   # 単語の数                        
num_workers = 4       # 並列処置の数
context = 10          # 文脈の数(?)                                                                                    
downsampling = 1e-3   # 頻出語のダウンサンプリング。0.001を設定。

model = word2vec.Word2Vec(sentences, workers=num_workers, \
            size=num_features, min_count = min_word_count, \
            window = context, sample = downsampling)

model.init_sims(replace=True)
model_name = "300features_40minwords_10context"
model.save(model_name)

モデルが完成したら、ちょっと使ってみます。 most_similarメソッドを使うと指定した単語の類義語を調べることができるようです。

model.most_similar("sun")

実行結果。

[('river', 0.7088125944137573),
 ('sky', 0.6877636313438416),
 ('skies', 0.6808205842971802),
 ('clouds', 0.6796398162841797),
(以下、省略)

sunの類義語はriverかskyが近いようです。

colaと入力するとよくわからない単語が返ってきますので、細かい調整が必要ですね。

model.most_similar("cola")
[('drilling', 0.5564199686050415),
 ('cargo', 0.5463235378265381),
 ('rig', 0.5401906967163086),
 ('dope', 0.5292767286300659),
 ('beer', 0.5280590057373047),

doesnt_matchメソッドを使うと、文章の仲間外れがわかるそうです。

model.doesnt_match("france england germany berlin".split())
'berlin'

フランス、イングランド、ドイツの中に1つだけ都市名であるベルリンがありますので、ベルリンが返ってきました。

また、モデルに直接単語を指定するとベクトルが返ってきます。

model["flower"]
array([-0.00689738,  0.00322649,  0.02021037, -0.06274773,  0.08876695,
        0.00546841,  0.05033052,  0.00244837,  0.04992382,  0.03910633,
        0.01777078, -0.07752343,  0.08437969, -0.04513944,  0.06993989,
       -0.01313402,  0.05363144,  0.01330627, -0.04074419, -0.04114439,
(以下省略)

時間がないので、今日はここまでにします。

この辺りの勉強していると、計算処理に時間がかかりすぎて勉強がなかなか進まないですね。

今日の結果

今日のAKBメンバーによる呟き45件でした。 「今日」「から」がまた目立ちますね。 f:id:rimt:20180811231620p:plain

{'楽しい': 11, 'ない': 4, '嬉しい': 4, '可愛い': 4, '悪い': 3, '怖い': 2, '大きい': 2, 'すごい': 2, 'いい': 1, '宜しい': 1, '寂しい': 1, '強い': 1, '面白い': 1, '短い': 1, 'かわいい': 1, '甘酸っぱい': 1, 'おいしい': 1, '美味しい': 1, '良い': 1, '正しい': 1, 'よい': 1, '懐かしい': 1})
'楽しい': 11, '今日': 11, '今': 8, '部': 8, '方': 7, 'こと': 7, '明日': 7, '日': 7, 'さん': 6, 'ちゃん': 6, 'アクシュカイ': 6, 
'する': 26, 'くださる': 12, '楽しい': 11, '今日': 11, 'なる': 9, '今': 8, '部': 8, '来る': 8, '方': 7, 'こと': 7, '明日': 7, '日': 7, 'てる': 7, 'さん': 6, 'ちゃん': 6, 'アクシュカイ': 6, 'れる': 6, '観る': 6, 'いる': 6,