継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

「Google Colaboratory」でツイートをテキストマイニングする

タダです。

機械学習技術や Python に興味があり、色々と勉強中で技術を手を動かして学びたいと思っていました。

そんな折、からあげさん( id:karaage )の機械学習コンテンツを購入し、テキストマイニングチュートリアルに取り組んだのでその内容をまとめていきます。

note.mu

チュートリアル概要

上記のチュートリアルでは「Google Colaboratory」を使って Twitter の自分のツイートでテキストマイニングを行います。

テキストマイニングとは文章からデータを単語や文節で区切り、それらの出現の頻度や相関、出現傾向、時系列などを解析することで有用な情報を取り出す、テキストデータの分析方法です。

ja.wikipedia.org

例えば、商品評価や顧客サービスの改善に利用される技術です。

Google Colaboratory について

Google Colaboratory」はブラウザの Jupyter Notebook 環境です。

colab.research.google.com

Google Colaboratory」の利用条件は、 Google のアカウントと Google Drive が保管場所になるためこの2つを使える必要があります。

関連記事

Google Colaboratory」については、以前社内勉強会でも触れて発表しました。 sadayoshi-tada.hatenablog.com

Google Colaboratory のメリット

Google Colaboratory」のメリットはなんといっても 環境構築が不要 であることです。起動したらそのまま機械学習の開発ができてしまいます。

そして、利用料は、無料です。GPU を乗せたオプションもありますがこれも無料。さすが、 Google さんと言わざるを言えません。

使い方含めて、下記の記事が参考になります。

www.codexa.net

チュートリアルで学べること

チュートリアルを通じて学べることを以下にまとめていきます。

なお、Python のプログラミングが必要になりますが、以下のものを利用します。

  • Pandas : 数理用ライブラリ
  • matplotlib : グラフなどの描画ライブラリ
  • janome : 言葉の形態素解析エンジン
  • Word Cloud : 単語の可視化ツール

また、予め Twitter および Google アカウントも必要です。

CSV ファイルの読み込み/抽出

全てのツイートをエクスポートするには以下の方法で実施します。

help.twitter.com

ツイートデータは、 CSV ファイルになっているため、 Pandas で読み込みさせます。

import pandas as pd

df = pd.read_csv('tweets.csv', encoding='utf-8')
df.head()

以下の画像のようにデータが読み込まれます。余談ですが、絵文字もちゃんと表示してくれます。

text カラムが今回の処理対象です。 f:id:sadayoshi_tada:20190319100114p:plain

データの前処理

ツイートには、後述する頻出単語を抽出するにあたって、特徴的な単語とは異なる不要な単語(記号や句読点など)、ノイズがいくつも入っています。

そのため、前処理として不要な単語を取り除く処理を、正規表現で行います。

例えば、以下のように処理します。

text = re.sub(r'#', "", text)
text = re.sub(r'\!', "", text)
text = re.sub(r'\(.*', "", text)
text = re.sub(r'.*\)', "", text)
text = re.sub(r'\*', "", text)
text = re.sub(r'\n', "", text)
text = re.sub(r'\$.*', "", text)
text = re.sub(r'`.*`', "", text)
text = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", text)
text = re.sub(r'@.* ', "", text)
text = re.sub(r'@さんから', "", text)
text = re.sub(r'【', "", text)
text = re.sub(r'】', "", text)
text = re.sub(r'『', "", text)
text = re.sub(r'』', "", text)
text = re.sub(r'「', "", text)
text = re.sub(r'」', "", text)
text = re.sub(r'(', "", text)
text = re.sub(r')', "", text)
text = re.sub(r'〜', "", text)
text = re.sub(r'〜', "", text)
text = re.sub(r'-', "", text)
text = re.sub(r'>', "", text)
text = re.sub(r'|', "", text)
text = re.sub(r' |', "", text)
text = re.sub(r'[a-zA-Z]', "", text)
text = re.sub(r'\d', "", text)
text = re.sub(r'&', "", text)
text = re.sub(r';', "", text)
text = re.sub(r'/', "", text)
text = re.sub(r'"', "", text)
text = re.sub(r'“', "", text)
text = re.sub(r'”', "", text)
text = re.sub(r'\.', "", text)
text = re.sub('や', "", text)
text = re.sub('などの', "", text)
text = re.sub(r'^・$', "", text)
text = text.strip()

単語ごとに分かち書きを行う

前処理後の単語を、分かち書きして別ファイルに保存します。

分かち書きとは、文章において語の区切りに空白を挟んで記述することです。

note.nkmk.me

コードでは、以下のように表現します。

from janome.tokenizer import Tokenizer
from collections import Counter, defaultdict
def counter(texts):
  t = Tokenizer()
  words_count = defaultdict(int)
  words = []
  for text in texts:
      tokens = t.tokenize(text)
      for token in tokens:
          pos = token.part_of_speech.split(',')[0]
          if pos == '名詞':
              words_count[token.base_form] += 1
              words.append(token.base_form)
  return words_count, words
words_count, words = counter(text_list)
text = ' '.join(words)
with open('ツイートを読み込ませるファイル', 'w', encoding='utf-8') as f:
  f.write(text)

Word Cloud でツイートの可視化

いよいよ、ツイートを可視化してみます。

Word Cloud でツイートを可視化してみると、以下のように表示されます。

f:id:sadayoshi_tada:20190319043751p:plain

コードで表すと、約10行ほどで可視化できてしまいます。

from wordcloud import WordCloud
import matplotlib.pyplot as plt
with open('ツイートを読み込ませるファイル') as f:
  text = f.read()
fpath = '/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf'
wordcloud = WordCloud(background_color="white", font_path=fpath, width=900, height=500).generate(text)
plt.figure(figsize=(15,12))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

参考情報

github.com

ツイートから頻出単語の抽出

また、ツイートからの頻出単語の抽出行います。テキストマイニングで必要な処理ですね。 d[:100]: で表示させる単語の最大の順位を示している為もっと表示させたい場合、この値を大きくします。

words = {}
for word in text.split(" "):
   words[word] = words.get(word, 0) + 1
d = [(v,k) for k,v in words.items()]
d.sort()
d.reverse()
for count, word in d[:100]:
   print(count, word)

そんなわけで、僕のツイート頻出単語を TOP 30位を出してみました。まだノイズが入っているので前処理で絞る必要がありますね。

328 –
49 :
46 今
40 勉強
37 技術
35 肉
34 会
34 ブログ
34 こ
33 自分
33 –,
31 的
30 方
30 |
24 本
23 –,,
22 間
22 発表
21 記事
21 参加
20 好き
20 一
19 株式会社
19 今夜
19 タディ
19 エンジニア
18 登録
18 明
18 学習
18 サビス

作成したコード

作ったコードですが、以下のリンク先にあります。 colab.research.google.com

ノイズを取り除いてみた結果の可視化の画像もはっておきます。ブログがでかい! ただ、ノイズがあるため継続してやってみます。 f:id:sadayoshi_tada:20190320095243p:plain

まとめ

自分のツイートを Word Cloud で可視化するのはとても簡単なコードで実現できるんだなという感想を持ちました。

よくデータ分析の分野で「前処理」が大切だというのが今回ノイズを消去したりして、実感できました。

前処理」として「ストップワード」というのもあります。今回触れてないですが、次にトライしてみます。

qiita.com

最後に、今回紹介したものに加え、からあげさん( id:karaage ) のチュートリアルは複数あり、コードを分からなくてもコピペで進められて良心的です。

また、「Google Colaboratory」は簡単かつ無料で始められるので、興味ある分野があれば購入されてみてはいかがでしょうか? note.mu

関連記事

僕同様このチュートリアルに関するブログを以下に記載します。 note.mu

あと、Slack の可視化を行なっています。 www.tokyo-ict.com

機械学習入門者にオススメな「機械学習のエッセンス」を読んだ

タダです。

機械学習の勉強を進めていて、僕のような初学者向けの本「機械学習のエッセンス」を読んだので所感をまとめていきます。

www.sbcr.jp

目次

本書の特徴

冒頭に書かれているのですが、本書では scikit-learn のようなライブラリで使える機能をゼロから Python で実装することを目的としています。

その理由は機械学習アルゴリズムの中身を理解していくために必要なこととし、主に5章でその実装を行います。

そして、僕のような数学を学生時代に挫折した方にも優しい内容になっているのが、本書の第2の特徴です。

数学で必要な知識を解説してくれているので、不明点があれば立ち返り可能なのが良い点です。

本書の Python 実行環境

本書では、 Anaconda を使うことになっています。

Python の他必要なライブラリが入っているので Python 初心者にとっつきやすいツールです。

また、機械学習といえば Python というのがほぼデファクトになっているので言語として Python は最適な選択だと思います。

Python の文法と、機械学習のための数学の基礎

4章と5章で Python を使ったプログラミングを行うにあたって、基本的な文法と数学の基礎を勉強していくのが2章と3章です。

文法としては以下の内容を学びます。

  • 数値、文字列の扱い
  • リスト、辞書、集合
  • 繰り返し
  • 条件分岐
  • 関数
  • モジュールのインポート
  • 例外処理

また、数学は「線形代数微積分、行列」がテーマになります。

4章、5章でも3章で学んだ数式がたくさん出てくるので、数学苦手な方は何度も立ち返る場所になるため重要なトピックになります。

機械学習と数学の実践

4章では、 numpy / Scipy を使って数列を扱ったり、 matplotlib で描画を行います。

上記のライブラリは頻出なため、使い方を数式で表現した場合と並行で解説されているので前章での知識整理に繋がります。

また、4章後半にある「数理最適化」問題や「統計」の専門用語は 並行で取り組んでいる「Coursera」中にも登場した概念で個人的に良い復習となりました。

関連記事

sadayoshi-tada.hatenablog.com sadayoshi-tada.hatenablog.com

機械学習ライブラリを使わない実装

5章で、機械学習のトピックをライブラリを使わず、手法ごとに実装方法の学習になります。扱うのは以下の内容です。

概念の解説 -> 数式での解説 -> コードでの数式で表現した箇所の解説 という構成になっているため、数式で理解が追いついてなくてもコードの実装からこういう処理をしているんだと理解を助けてくれます。

また、特徴量を特定する上で必要な、汎化と過学習の概念についても解説されているのがありがたいです。

まとめ

機械学習のエッセンス」を読んだ所感をまとめました。

様々な機械学習本や、解説記事を読んできたのですが、本書のように数学の基礎や Python のコードを詳細に解説してくれる本は個人的に初で入門者に最適と思います。

機械学習に興味あるけど、数学に苦手意識ある人や途中で挫折してしまった人にも一読してもらいたいそんな1冊だと思います!

PythonでスクレイピングとMNISTを使って機械学習を実践する

タダです。

あけましておめでとうございます! 新年一発目のブログを書いて行きます。

実は、id:kakku22さんのブログメンティーに選んでいただきまして、良いプレッシャーをいただきつつブログを書いています。

さて、昨年から機械学習に興味が出てきて、その技術について学んでいます。 その中でデータ収集するための手段としてスクレイピング技術を勉強しているので、今回はPythonスクレイピングをサンプルデータで実際に動かしてみます。

教本としてこちらの本を使わせてもらっています。

www.socym.co.jp

TL;DR

ソースコード載せたりしている関係で冗長になっているので、以下の2つのことを書いています。

スクレイピング機械学習

スクレイピングは、Webサイトから任意の情報を抽出、データ構造の解析することができます。

機械学習を行う為には、大量のデータを収集する必要があります。

そのための手段として、スクレイピング技術を扱うことができればデータの収集がしやすくなれると思い勉強しています。

スクレイピングの技術要素

勉強していて出てきたPythonスクレイピングするために必要な技術要素を紹介します。 なお、今回はスクレイピングしたデータから機械学習を行うための手順を書きたいので、下記の技術の詳細な説明は割愛します。

  • urllib : HTTPやFTPを利用してデータをダウンロードするためのライブラリ
    • urllib.request : ファイルをダウンロードするためのモジュール
  • requests : クッキーを利用したWebアクセスが簡単に行えるモジュール
  • BeautifulSoup : HTMLやXMLの解析を行うためのライブラリ
  • Selenium : JavaScriptなどWebブラウザを使わないと正しく動作しないサイトへの遠隔操作するためのツール。主にWebアプリのテストで使う。
  • PhantomJS : コマンドラインから使えるWebブラウザー(PhantomJSの開発は終了して、リポジトリアーカイブ化されてるため注意)

参考 : PhantomJSの開発が終了しリポジトリがアーカイブ化された - JSer.info

これらの技術を使ってWebからデータを収集します。

実際にPythonスクレイピングして機械学習を行う

それでは、実際にPythonスクレイピングして機械学習していきます。

今回は、機械学習のためのフレームワークである「scikit-learn」を使うので環境にインストールしておきます。

pip install -U scikit-learn scipy matplotlib scikit-image

また、機械学習の対象はMNISTの手書き数字データになります。

MNISTのデータは機械学習の練習によく使われるデータなので、利用することにしています。

MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

さて、大まかに作業の順番ですが、以下の通りです。

  1. MNISTから学習用データとテスト用データをダウンロードする
  2. MNISTの学習用データをCSVに変換する
  3. 画像データを学習させる

1. MNISTから学習用データとテスト用データをダウンロードする

MNISTのサイトから以下の4つファイルを「mnist」ディレクトリにダウンロードします。

  • train-images-idx3-ubyte.gz : 学習用画像データ
  • train-labels-idx1-ubyte.gz : 学習用ラベルデータ
  • t10k-images-idx3-ubyte.gz : テスト用画像データ
  • t10k-labels-idx1-ubyte.gz : テスト用ラベルデータ
# coding:utf-8
import requests
import gzip, os, os.path

savepath = "./mnist"
baseurl = "http://yann.lecun.com/exdb/mnist"
files = [
    "train-images-idx3-ubyte.gz",
    "train-labels-idx1-ubyte.gz",
    "t10k-images-idx3-ubyte.gz",
    "t10k-labels-idx1-ubyte.gz"
]

# ディレクトリの作成
if not os.path.exists(savepath): os.mkdir(savepath)

# ダウンロード
for file in files :
    url = baseurl + "/" + file
    res = requests.get(url)
    location = savepath + "/" + file
    print("download:", url)
    if not os.path.exists(location):
        with open(location, "wb") as f:
            f.write(res.content)
            
for file in files:
    gz_file = savepath + "/" + file
    raw_file = savepath + "/" + file.replace(".gz", "")
    print("gzip:" + file)
    with gzip.open(gz_file, "rt") as fp:
        body = fp.read()
        with open(raw_file, "wb") as w:
            w.write(body)

2.MNISTの学習用データをCSVに変換する

バイナリデータのままだとPythonで扱いづらいため、CSVファイルへの変換を行います。

CSVファイルへの変換とあわせて、画像データから最初の10件だけデータを取得しています。

# coding:utf-8
import struct

def to_csv(name, maxdata):
    # ラベルファイルとイメージファイルを開く
    lbl_f = open("./mnist/"+name+"-labels-idx1-ubyte", "rb")
    img_f = open("./mnist/"+name+"-images-idx3-ubyte", "rb")
    csv_f = open("./mnist/"+name+".csv", "w", encoding="utf-8")
    # ヘッダ情報を読む
    mag, lbl_count = struct.unpack(">II", lbl_f.read(8))
    mag, img_count = struct.unpack(">II", img_f.read(8))
    rows, cols = struct.unpack(">II", img_f.read(8))
    pixels = rows * cols
    # 画像データを読んでCSVで保存
    res = []
    for idx in range(lbl_count):
        if idx > maxdata: break
        label = struct.unpack("B", lbl_f.read(1))[0]
        bdata = img_f.read(pixels)
        sdata = list(map(lambda n: str(n), bdata))
        csv_f.write(str(label)+",")
        csv_f.write(",".join(sdata)+"\r\n")
        # 試しに10件だけPGMで保存
        if idx < 10:
            s = "P2 28 28 255\n"
            s += " ".join(sdata)
            iname = "./mnist/{0}-{1}-{2}.pgm".format(name,idx,label)
            with open(iname, "w", encoding="utf-8") as f:
                f.write(s)
    csv_f.close()
    lbl_f.close()
    img_f.close()

# 出力件数を指定 --- (※4)
to_csv("train", 1000)
to_csv("t10k", 500)

3.画像データを学習させる

書籍では、下記のようなモジュールの読み込ませ方が紹介されていました。

from sklearn import cross_validation

ただ、scikit-learnの0.20バージョンからcross_validationモジュールはなくなり、代わりにmodel_selectionモジュールが使われるようになりました。

# coding:utf-8
from sklearn.model_selection import cross_val_score # ここの書き方注意
from sklearn import svm, metrics

# CSVファイルを読んで学習用データに整形
def load_csv(fname):
    labels = []
    images = []
    with open(fname, "r") as f:
        for line in f:
            cols = line.split(",")
            if len(cols) < 2: continue
            labels.append(int(cols.pop(0)))
            vals = list(map(lambda n: int(n) / 256, cols))
            images.append(vals)
    return {"labels":labels, "images":images}

data = load_csv("./mnist/train.csv")
test = load_csv("./mnist/t10k.csv")

# 学習
clf = svm.SVC()
clf.fit(data["images"], data["labels"])

# 予測
predict = clf.predict(test["images"])

# 精度の確認
ac_score = metrics.accuracy_score(test["labels"], predict)
cl_report = metrics.classification_report(test["labels"], predict)
print("正解率=", ac_score)
print("レポート=")
print(cl_report)

このプログラムの実行結果が下記です。

正解率が78.6%です。何もチューニングしていないためまずまずな精度かと言えます。

正解率= 0.7884231536926147
レポート=
              precision    recall  f1-score   support

           0       0.87      0.93      0.90        42
           1       0.81      1.00      0.89        67
           2       0.84      0.69      0.76        55
           3       0.87      0.57      0.68        46
           4       0.76      0.75      0.75        55
           5       0.63      0.80      0.71        50
           6       0.97      0.67      0.79        43
           7       0.74      0.86      0.79        49
           8       0.91      0.72      0.81        40
           9       0.71      0.81      0.76        54

   micro avg       0.79      0.79      0.79       501
   macro avg       0.81      0.78      0.78       501
weighted avg       0.80      0.79      0.79       501

まとめ

Pythonスクレイピングしたデータを使ってscikit-learnで機械学習をしてみました。

サンプルデータなのでチューニングはしていませんが、今度は公開されているAPIからデータを取得して実践的な使い方を記事にしたいと思います。

【15日目】毎日勉強や

タダです。

やる気の問題で更新が滞ってました。。

日課

Python 文法

  • 辞書型のデータの定義は、hoge = {}

100本ノック

元素記号 "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の>単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

# coding:utf-8
output_num = (0, 4, 5, 6, 7, 8, 14, 15, 18)
words = 'Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can'
result = {}
wordssplits = words.split(' ')

i = 0

for (num, wordssplit) in enumerate(wordssplits, i):
    if num in output_num:
        result[wordssplit[0:1]] = num
    else:
        result[wordssplit[0:2]] = num

print(result)

enumerate関数てのがあるんですな...

note.nkmk.me

Pythonスクレイピング

Pythonの文法を勉強してきたので、実践編としてスクレイピングでも作りたいと思ってやってみました。

やってみたこと

Twitterのタイムラインスクレイピング

必要な要素

  • Requestsライブラリを使ってWebページを取得する
  • requests_oauthlibでTwitterの認証情報をもたせる

実際に書いたコード

import requests
from requests_oauthlib import OAuth1Session

# Twitterの認証情報
access_token = 'アクセストークン
access_token_secret = 'アクセストークンシークレットキー'
consumer_key = 'コンシューマーキー'
cosumer_secret_key = 'コンシューマーシークレットキー'

# タイムラインの取得
url = "https://api.twitter.com/1.1/statuses/user_timeline.json"

# リクエストのパラメーター
params = {'screen_name':'tada_infra',
... 'exclude_replies':True,
... 'include_rts':False,
... 'count':200}


tw = OAuth1Session(consumer_key, cosumer_secret_key, access_token, access_token_secret)
resp = tw.get(url, params = params)
print(resp)
>>> <Response [200]>

今日はAPIにアクセスするための準備までだったので、明日以降にツイートとってきたいと思います。

参考

www.randpy.tokyo

また明日

【14日目】毎日勉強や

タダです。

日課

Python文法

今日はクラスとメソッドあたりを学びました

  • クラス(設計図)からインスタンス(実際のもの)を作る
    • クラス内に定義するメソッドは、クラスメソッド
    • クラスメソッドを使うときは、インスタンス化してから
    • クラスメソッドはselfを引数にするし、その他自由な引数を持たせることができる
  • initメソッドはクラス名()でインスタンスを生成した直後に呼び出される(インスタンスを生成と同時にインスタンス変数を作れる)

100本ノック

  1. 元素記号

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

解ききれなかったので、今日リベンジする