Pythonのscikit-learnでグリッドサーチを使ってSVMのパラメータチューニングをしよう

2016-03-09
このエントリーをはてなブックマークに追加

SVMはパラメータが多すぎる。全部試すとか手間が掛かり過ぎる。
そんな悩みを解決したいグリッドサーチの使い方です。

from sklearn.svm import SVC
from sklearn.grid_search import GridSearchCV


def main():
    _s = GridSearchCV(
            SVC(),
            {
                "C": [0.1, 0.5, 1.0, 1.5],
                "kernel": ["rbf", "linear"],
                "gamma": [1, 1e-2, 1e-3, 1e-4],
            }
    )
    _s.fit(
        [
            [1, 0, 0, 0, 0],
            [1, 1, 0, 0, 0],
            [1, 1, 0, 0, 1],
            [0, 1, 1, 1, 1],
            [0, 0, 0, 1, 1],
            [0, 0, 1, 1, 1],
            [0, 0, 1, 1, 1]
        ],
        [1, 1, 1, 0, 0, 0, 0]
    )

    print(_s.best_estimator_)
    print(_s.best_score_)

if __name__ == "__main__":
    main()

上のコードだとCとカーネルとガンマだけを設定してますけど、SVCで指定できるパラメータは全部設定できます。

出力のところは見やすいように成形してます。便利すぎる。。。
全部のパラメータを1回で指定できるわけでもなくて、併用できないものは途中でエラー吐いたりもします。それでも、かなり実施回数は減らせます。

$ python grid.py
SVC(
    C=0.5,
    cache_size=200,
    class_weight=None,
    coef0=0.0,
    degree=3,
    gamma=1,
    kernel='linear',
    max_iter=-1,
    probability=False,
    random_state=None,
    shrinking=True,
    tol=0.001,
    verbose=False
)
1.0

Pythonでscikit-learnを使ってSVMによる分類

2016-02-25
このエントリーをはてなブックマークに追加

SVMなので二値分類です。多値分類でもSVMを使うこともありますが、あれは二値分類の繰り返しなのでやっぱりSVMを使うのであれば二値分類なんだろうなぁと思います。

LinearSVC、線形カーネルのサンプルです。相変わらずこんなに簡単にできるPythonってすごいって感心しちゃう。

from sklearn.svm import LinearSVC


def main():

    _training = [
        [0, 1, 0],
        [0, 0, 0]
    ]
    _estimator = LinearSVC()
    _estimator.fit(_training, [1, 0])

    _prediction = _estimator.predict([0, 1, 1])
    print(_prediction)

if __name__ == "__main__":
    main()
$ python sample.py
[1]

無事、1と分類されました。

scikit-learnでトレーニングデータとテストデータを分割する

2016-02-19
このエントリーをはてなブックマークに追加

機械学習させるときに用意したデータの9割を学習用データに、1割をテストデータに使ったりします。その分割を手軽にしてくれます。scikit-learnを使いたくてPython書いてるようなもんです。

from sklearn.cross_validation import train_test_split
import numpy as np

def main():

    _train_x, _train_y, _test_x, _test_y = train_test_split(
        np.array([
            [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [2, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [3, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [4, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [5, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [6, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [7, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [8, 1, 0, 1, 0, 1, 0, 1, 0, 1],
            [9, 1, 0, 1, 0, 1, 0, 1, 0, 1]
        ]),
        np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1]),
        test_size=0.1
    )
    print(_train_x)

if __name__ == "__main__":
    main()

test_size=0.1、で10%をテスト用データとして分割してくれます。

[[0 1 0 1 0 1 0 1 0 1]
 [8 1 0 1 0 1 0 1 0 1]
 [7 1 0 1 0 1 0 1 0 1]
 [4 1 0 1 0 1 0 1 0 1]
 [2 1 0 1 0 1 0 1 0 1]
 [5 1 0 1 0 1 0 1 0 1]
 [6 1 0 1 0 1 0 1 0 1]
 [1 1 0 1 0 1 0 1 0 1]
 [3 1 0 1 0 1 0 1 0 1]]

これだけでシャッフルして指定した割合で分割してくれるからありがたい。

Pythonのスクリプトを起動するときのオプションを指定する方法

2016-01-26
このエントリーをはてなブックマークに追加

以前は optparse 使ってましたけど、廃止予定だそうです。で、今は argparse 使います。2.7以降はargparseが標準で入ってるそうなので、今時はもうoptparseも使えはするけどargparse一択でしょう。

from argparse import ArgumentParser

if __name__ == "__main__":

    _parser = ArgumentParser()

    _parser.add_argument(
        '-s',
        '--string',
        type=str,
        dest='string',
        required=True,
        help='String Value'
    )

    _parser.add_argument(
        '-n',
        '--number',
        type=int,
        dest='number',
        required=True,
        help='Number Value'
    )

    _args = _parser.parse_args()

    print(_args.string, _args.number)

なんのオプションも指定しないで起動すると

$ python sample.py
usage: sample.py [-h] -s STRING -n NUMBER
sample.py: error: argument -s/–string is required

「-sで文字列、-nで値を指定してね。-sは必須オプションだからエラーだよ。」
ってメッセージがでます。親切です。

$ python sample.py -s S -n N
usage: sample.py [-h] -s STRING -n NUMBER
sample.py: error: argument -n/–number: invalid int value: ‘N’

-n に文字列を与えてもエラーが出ます。ちゃんと型チェックしてくれます。親切です。

$ python sample.py -s Hello -n 123
(‘Hello’, 123)

便利。

電気自動車に乗り換えて1年経った

2015-12-31
このエントリーをはてなブックマークに追加

日産のLEAFという電気自動車に乗り換えて1年経ったのでどんなもんかブログに書いておきましょう。電気自動車に興味のある方、購入を検討している方の参考になれば幸いです。

なお、このエントリは電気自動車を否定するものではありません。むしろ応援しています。電気自動車はいいぞ。

まず気になるのは走行距離でしょうか。たしかカタログ上の走行距離は100%充電で220kmくらいだったと思います。まあ当然そんなに走りません。

thumb_IMG_6992_1024

「今の充電量だったらxxkm走りますよ」、っていうのがコンソールに表示されるのです。写真の右側にある「159」という数字がこの時の走行可能距離です。100%充電で160kmいくかいかないかくらい。カタログ値の2/3くらいでしょうか。まあガソリンエンジンの燃費もそれくらいだから妥当でしょう。

thumb_IMG_6993_1024

ちなみに、エアコンをオンにすると10%ちょっと走行可能距離が減ります。エアコンがどれだけ電気を消費するのか実感します。

この走行可能距離は電費(燃費)の悪い乗り方をしていると下がります。ディーラーさん曰く、「最近の消費電力と走行距離から算出」しているそうなのですが、その「最近」がどれくらいの期間なのかは不明とのことでした。

なお、高速道路を走るとビビるくらい電気を消費します。1km走るごとに1%減ってるんじゃないかと思うくらい。ちょっとおおげさですけど、そう思っちゃうくらい減ります。

回生ブレーキシステムで充電しているらしいですけど、多少減りにくくなってる程度でしょう。正直充電量が増えたところは見たことありません。ソーラーパネルも搭載していますが、同様です。真夏に外に駐車してても1%も増えません。

購入時に無料で自宅に充電設備を設置してくれたのですが、自宅で充電することはほぼありません。1年間で2〜3回しか自宅で充電してません。近所のイオンモールに無料の充電器があるので概ねそこで充電しています。イオンモールで買い物してる間に充電が終わるので非常にお世話になっています。あとは日産のディーラーさんのところでも充電できます。ショールームの中で飲み物出してもらってのんびり待てます。

自宅で充電しても300円くらいで満タンになるそうです。

10009312_809120102457573_4328280958089988453_n

乗り心地はガソリンエンジン車とはまったく違います。圧倒的に静かです。振動も少なく、排気ガス臭くもありません。静かで振動が無いというのがこんなに快適だとは思いませんでした。

静かなのに、びっくりするくらいパワフルです。4,000ccエンジン相当のトルクだそうです。たしかにecoモードをオフにして静止状態からベタ踏みするとホイールスピンします。マーチサイズのボディで暴れるので面白いです。

静かでパワフルで無料で充電できていいコトづくめですが、まあ走行可能距離が短くて急速充電器でも充電に30分かかるのは正直きつい。

  • 近所に無料の充電設備がある
  • あんまり遠出しない
  • あんまり毎日距離走らない

っていう人だったらいいですけど、そうでもなければ現時点で電気自動車を選択するのは相当の覚悟がいると思います。

正直、細かいこと気にする人はやめておいた方がいいと思います。100キロちょっと走ったら充電で30分足止めになっても「まあそういうもんだよね」って休憩兼ねて停まれるくらいがいいでしょう。そんな感じでゆるく乗ってあげるといい車だと思います。

PythonでWord2Vecを使って類義語抽出

2015-11-12
このエントリーをはてなブックマークに追加

今更のWord2Vec。

分かち書きしたテキストファイルを読み込ませて学習データを作って保存。保存した学習データを読み込んで類義語を出力するところまで。毎回学習してから類義語抽出っていう訳にもいかないから学習データの保存は必要ですよね、っていうサンプル。

Word2Vecはおもしろいし、いろいろ触ってるので今後もブログに書いていこう。このエントリも下書きのまま1年くらい放置されててちゃんとブログ書かねばと反省中。。。

from gensim.models import word2vec

def main():

    data = word2vec.Text8Corpus("/path/to/file")
    model = word2vec.Word2Vec(data, size=250, window=5, min_count=2, workers=4)
    model.save("./teacher.bin")

    model = word2vec.Word2Vec.load("./teacher.bin")
    for _w in model.most_similar(positive=['ジャケット']):
        print(_w)

if __name__ == "__main__":
    main()

elasticsearchでcopy_toを使ってみる

2015-11-01
このエントリーをはてなブックマークに追加

SolrでいうところのCopyField。全文検索で複数フィールドを束ねて検索したい時には便利です。フィールドごとにスコアブーストしたいとなると別の方法を取るしかないかな。

{
    "title": {
        "type": "string",
        "copy_to": "text"
    },
    "description": {
        "type": "string",
        "copy_to": "text"
    },
    "text": {
        "type": "string",
        "index": "analyzed",
        "analyzer": "text_ja"
    }
}

これでtextフィールドにクエリ投げればtitleかdescriptionのどちらかに適合するドキュメントが返ってくる。データ元になるtitleとかdescriptionはindexをfalseにしておけばインデックスサイズも小さくなる。elasticsearch1.7.3で動きました。

Pythonでscikit-learnを使ってランダムフォレストの分類器を書いて、学習結果を保存してみた

2015-10-01
このエントリーをはてなブックマークに追加

分類するだけじゃなくて学習したデータを保存もしています。学習データがあったらデータを読み込んで利用します。

import os

from sklearn.ensemble import RandomForestClassifier
from sklearn.externals import joblib


class RandomForest(object):
    def __init__(self):
        if os.path.exists('./.supervised/data.bin'):
            self._m = joblib.load('./.supervised/data.bin')

        else:
            _training_data = [
                [2, 0, 0, 0],
                [0, 2, 0, 0],
                [0, 0, 2, 0],
                [0, 0, 0, 2],
            ]
            _training_label = [1, 2, 3, 4]

            self._m = RandomForestClassifier()
            self._m.fit(_training_data, _training_label)

            joblib.dump(self._m, './.supervised/data.bin')

    def start(self):
        _test_data = [
            [0, 4, 0, 0],
            [0, 0, 0, 2]
        ]
        _out = self._m.predict(_test_data)

        print(_out)

if __name__ == "__main__":
    _obj = RandomForest()
    _obj.start()

結果出力
[2 4]

Pythonでnumpyを使って値を正規化する

2015-09-24
このエントリーをはてなブックマークに追加
$ import numpy as np
$ _array = np.array([1, 2, 3])
$ _n_array = _array / np.amax(_array) * 1
$ print(_n_array)

[ 0.33333333  0.66666667  1.        ]

0から1の間に収めます。
こんなに簡単にできちゃうって素晴らしい。

Tags:

「人間のためのHTTP」Requestsでオレオレ証明書かつベーシック認証を突破する

2015-08-14
このエントリーをはてなブックマークに追加

Requests は「人間のためのHTTP」という謳い文句のhttpライブラリ。確かにとても便利。Python3であれば http.client 使えばいいんですけど、ついついRequestsを使ってしまう。

_response = requests.get(
     'https://TARGET_URL',
     auth=('user_name', 'passwd'),
     verify=False
)

auth=の部分がベーシック認証、verify=Falseがオレオレ証明書の許容。これだけです。簡単。

まあ、

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised.

ってWarning吐きまくってるんですけどね。

Requestsが動くならPython2でも3でも動くはずです。