スゲェ面白い!「scikit-learn」で機械学習入門

自己紹介

サンライズコーポレーションの@uedaです 普段は渋谷系大手広告代理店でアプリ製作をお手伝いしています。

激アツの機械学習にチャレンジしてチートシートを作ってみます。 自分の備忘録として書いているのでツッコミは一切受け付けておりません(キリッ)

機械学習って何ができんの

昔から人工知能の開発は行われており、パターンから次を予測するようなモノは実現していたんですが、人間のように画像を見て何を意味するかを読み取ったり、違うパターンが来た時も自分で規則性を見出したりする事はできなかった、しかし深層学習(DeepLeaning)って云う脳と同じ構造をもたせる事でそれらが可能になってきたっつー発展途上中だけど確実に次世代に花咲くテクノロジー確定なのです(キリッ) 東大の教授曰く言語分野における深層学習ブームは2014年11月頃に終息したみたいですが... まだまだ激アツなのは間違いない。 昔見たロボットアニメなんかで戦闘データを元に次世代マシーンを作っていく世界がすぐそこまで来ているような気がします

今回やりたい事

コーパスと呼ばれる文章を形態素解析で分解して モデルで処理する事によってベクトル毎に分類させてみます。 使うのは入門ではおなじみscikit-learn

http://upload.wikimedia.org/wikipedia/en/9/99/Scikit-learn_logo.png

環境を準備する

  1. 動作環境をインストールしていきます。
  2. pythonのバージョン管理ツールpyenv
  3. 数学関数ライブラリnumpy
  4. 科学技術計算ルーチンパッケージscipy
  5. 今回のメインディッシュschikit-lean

環境構築チートシート(max yosemite)

いろいろやったのでいらないヤツが入ってるかも

Xcode&HomeBrew&pip
$ xcode-select --install
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ sudo easy_install pip
Python
$ brew update
$ brew install pyenv
$ brew install pyenv-virtualenv # これは任意
$ pyenv install 2.7.8
numpy & scipy&nose & scikit-learn & mecab
$ sudo pip install numpy
$ sudo pip install scipy
$ sudo pip install nose
$ pip install scikit-learn
$ brew install mecab
$ brew install mecab-ipadic
$ sudo pip install https://mecab.googlecode.com/files/mecab-python-0.996.tar.gz

仕様

コーパスと呼ばれる文章単位でベクトル化して コーパス達を分類してみます。 GitHubににたコードが転がっていたので そのまま動かしてみました。ありがたやー

  1. twitterの記事を食わせる
  2. mecubで分解する
  3. ゴミをとる
  4. 次元削減してベクトルを作成する
  5. 記事をベクトルでソートしてみる
  6. ソートした記事をベクトル毎にクラスタリング(分類)します
  7. クラスタリングしたデータをとりあえずファイル出力します

ソースコード

import csv
import codecs
import numpy as np
import MeCab

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans, MiniBatchKMeans
from sklearn.decomposition import TruncatedSVD
from sklearn.preprocessing import Normalizer

FILENAME = 'tweets.csv'
#FILENAME = '~/Documents/scikit-learn-test/tweets.csv'

#NUM_CLUSTERS = 1000
#LSA_DIM = 500
NUM_CLUSTERS = 3
LSA_DIM = 2
MAX_DF = 0.8
MAX_FEATURES = 10000
MINIBATCH = True

#リプライと3文字以下は除外する
def get_tweets_from_csv(filename):
    ret = csv.reader(open(filename))
    tweets = [r[5].decode('utf-8') for r in ret]

    for tweet in tweets[:]:
        if u'@' in tweet:
            tweets.remove(tweet)
        if len(tweet) <= 3:
            tweets.remove(tweet)
    return tweets

#単語をBug-of-Wordsで表現する
def analyzer(text):
    ret = []
    tagger = MeCab.Tagger('-Ochasen')
    node = tagger.parseToNode(text.encode('utf-8'))
    node = node.next
    while node.next:
        ret.append(node.feature.split(',')[-3].decode('utf-8'))
        node = node.next

    return ret


def main(filename):
    # load tweets
    tweets = get_tweets_from_csv(filename)

    # feature extraction
    # scikit-learn に単語の重みづけをおまかせ

    vectorizer = TfidfVectorizer(analyzer=analyzer, max_df=MAX_DF)
    vectorizer.max_features = MAX_FEATURES
    X = vectorizer.fit_transform(tweets)


    # dimensionality reduction by LSA
    # 次元削減をして同じ意味の単語をグルーポン

    lsa = TruncatedSVD(LSA_DIM)
    X = lsa.fit_transform(X)
    X = Normalizer(copy=False).fit_transform(X)


    # clustering by KMeans
    # クラスタリング開始
    if MINIBATCH:
        km = MiniBatchKMeans(n_clusters=NUM_CLUSTERS, init='k-means++', batch_size=1000, n_init=10, max_no_improvement=10, verbose=True)
    else:
        km = KMeans(n_clusters=NUM_CLUSTERS, init='k-means++', n_init=1, verbose=True)
    km.fit(X)
    labels = km.labels_

    transformed = km.transform(X)
    dists = np.zeros(labels.shape)
    for i in range(len(labels)):
        dists[i] = transformed[i, labels[i]]


    # sort by distance
    # tweetsをクラスタへ振り分け
    clusters = []
    for i in range(NUM_CLUSTERS):
        cluster = []
        ii = np.where(labels==i)[0]
        dd = dists[ii]
        di = np.vstack([dd,ii]).transpose().tolist()
        di.sort()
       for d, j in di:
            cluster.append(tweets[int(j)])
        clusters.append(cluster)

    return clusters

if __name__ == '__main__':
    clusters = main(FILENAME)
    f = codecs.open('%s.txt' % FILENAME, 'w', 'utf-8')
    for i,tweets in enumerate(clusters):
        for tweet in tweets:
            f.write('%d: %s\n' % (i, tweet.replace('/n', '')))
    f.close()

使い道

単語で検索して近いベクトルのコーパスを呼び出す処理なんかに使える。はず

大事な事

言語分野での機械学習はいかに次元削減してコーパスをベクトル化するかが全てです。 それを学習させた調教済のモデルが結構転がってるので面白いですね。

ここからは宣伝です

サンライズコーポレーションでは仲間を探しています。 エンジニア経験者はもちろん、未経験でもチャレンジ魂があれば連絡してください!!! お待ちしています。 現在はEメールで受け付けていますのまずは問い合わせをお願いします。 連絡先:recruit@sunrise-cp.com 募集要項などを記載した求人ページはこちら