2014年12月10日

データサイエンス

scikit-learnでよく利用する関数の紹介

  • このエントリーをはてなブックマークに追加

Yahoo! JAPAN Tech Advent Calendar 2014の10日目の記事です。一覧はこちら

はじめに

こんにちは。ヤフーで広告プロダクトのデータ分析をしている田中と申します。

今回のAdvent Calendar 2014では、データサイエンスのプロセスの中の「分析・モデリング」で私がよく利用しているツールについて書いています。
どうぞよろしくお願い致します。

データサイエンスのプロセスについては、いろいろと定義があると思いますが
基本的に以下の5つのプロセスからなると自分は考えています。

・問題設定
・データ抽出・加工
・分析・モデリング
・評価
・ビジネス提案/プロダクト実装

どのプロセスもとても大事で、例えば「問題設定」では、ビジネス的な課題(売上低迷・KPI低下)を分析課題に落とすのですが、ここを間違えてしまうと、後が続かなくなってしまいます。一番大事な所といってもいいかもしれません。

「データ抽出・加工」は、データを抽出して分析できる形に加工する必要があります。
ヤフーではHadoop・Teradataにある格納しているデータを独自プラットフォームやSQLを利用し抽出・加工をしています。
アクセシビリティーは昔よりとても高くなってはきましたが、とても時間のかかるプロセスです。

今回は「分析・モデリング」の部分の話です。
ヤフーでは、このプロセスはとても自由で、最新の研究論文の手法を実装し適用する人・R言語を利用する人・BIツールを利用する人などさまざまです。

私は機械学習のライブラリscikit-learnを使う事が多いので今回はこのライブラリについて紹介させていただきます。

本稿では、あくまでライブラリの使い方の話で、細かい理論・用語の説明をはぶいてしまっているので、書いてある事が理解できない事もあると考えられますがご容赦くださいませ。

scikit-learnとは

オープンソースのpythonで書かれた機械学習のライブラリです。
インストールなどはこちらを参考にしていただければと思います。

http://scikit-learn.org/stable/install.html

必要なライブラリは以下となります。また便利なPandasも入れておくと便利なので入れておきましょう。

・Numpy
・Scipy
・scikit-learn
・Pandas

NumpyとScipyはscikit-learnより先にインストールする必要があります。

よく利用する関数の紹介

(1)tsv/csvの読み込み

基本となるデータの読み込みです。これはnumpyとpandasを使います。

import numpy as np
import pandas as p

data = np.array(p.read_csv(filepath_or_buffer='data.txt', header=None, sep=','))[:,:]

#少しずつ読み込みたい時
data = p.read_csv(filepath_or_buffer='data.txt', sep=',',header=None, iterator=True, chunksize=100000)

data_first = np.array(data.get_chunk())[:,:]
data_seccond = np.array(data.get_chunk())[:,:]

配列としてデータを読み込む事ができます。sepで区切り文字を指定します。ヘッダーがある場合はheader=Noneをとりましょう。
読み込むファイルの規模が大きくて、メモリに一度に乗り切らないときはiteratorとchunksizeを使います。
上記のように書くとdata_firstには最初の10万行が読み込まれdata_seccondは次の10万行が読み込まれています。
詳しい仕様は以下をご参照下さい。

http://pandas.pydata.org/pandas-docs/stable/generated/
pandas.io.parsers.read_csv.html

(2)svmlight/libsvm形式のファイルを読み込み

svmlight/libsvm形式のファイルも読み込む事ができます。
svmlight/libsvm形式とは以下のような形式の事をいいます。

#ラベル 素性id:値 素性id:値
1 2:1 3:1
1 1:2 3:1 5:1
-1 1:1 2:1 3:1 5:2

scikit-learnの load_svmlight_filesという関数を使い読み込みます。

from sklearn.datasets import load_svmlight_files

x,y,x_test,y_test = load_svmlight_files(('train.txt','test.txt'))

#疎行列を通常の配列形式に変換
x = x.toarray()
x_test = x_test.toarray()

yとy_testにはラベルが読み込まれ、xとx_testに素性が疎行列として読み込まれます。
scikit-learnのRandomForestなどは疎行列に対応していないので上記のように変換してあげる必要があります。
詳しい仕様は以下をご参照下さい。

http://scikit-learn.org/dev/modules/generated/
sklearn.datasets.load_svmlight_files.html

(3)TFIDFベクトルの作成

英文・形態素解析済みの文章などをtfidfベクトルに変換する事も可能です。
このような頭ではわかっているものの実装が面倒だったり、バグが入りやすかったりするところなので、簡単にライブラリを使って処理できると便利だと考えています。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS

tfv = TfidfVectorizer(encoding='utf-8', lowercase=True, stop_words=ENGLISH_STOP_WORDS,token_pattern='(?u)\b\w\w+\b', ngram_range=(1,2))

tfv.fit(data)
tfv_vector = tfv.transform(data)

tfv.fitの引数は文章の配列となります。文字の単位もngram_rangeで設定する事が可能です。ストップワードも設定可能です。
上記の設定でscikit-learnのENGLISH_STOP_WORDSを読み込んでいます。ベクトルは疎行列として読み込まれます。詳しい仕様は以下をご参照下さい。

http://scikit-learn.org/dev/modules/generated/sklearn.feature_extraction.text.
TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer

(4)特徴量の次元圧縮

特徴量の次元圧縮も可能です。
疎行列などを数十次元の規模に落として密行列にします。
本来は大規模データを扱えるようにしたりするための処理ですが、scikit-learnでは
RandomForestの関数が疎行列に対応していないがために、圧縮する事が多いです。

from sklearn.decomposition import TruncatedSVD

decomp = TruncatedSVD(n_components=50,n_iterations=5)
decomp.fit(x) 
x = decomp.transform(x)

n_componentsが圧縮後の次元数となります。TFIDFベクトル作成後上記の関数に入れるという事が個人的には多いです。

詳しい仕様は以下をご参照下さい。

http://scikit-learn.org/dev/modules/generated/sklearn.decomposition.
TruncatedSVD.html#sklearn.decomposition.TruncatedSVD

(5)BaggingClassifier / BaggingRegressor(関数)

待望の関数がscikit-learn-0.15から?実装されました。
今まで同じ機能を自前で書いていました。それぐらい強力だと個人的に考えています。
この関数は通常の手法(以下の例ではロジスティック回帰)をバギングする関数です。バギングは素性とレコード両方可能なところが使い勝手が良いです。

from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import BaggingRegressor
from sklearn.linear_model import LogisticRegression

#ロジスティック回帰
clf = LogisticRegression()
clf = BaggingClassifier(base_estimator=clf, n_estimators=100, max_samples=0.9, max_features=0.2,n_jobs=4)

#データのリサンプリング(念のためレコードをシャッフルしています)
num = len(y)
x,y = resample(x,y,n_samples=num)

#トレーニング
clf.fit(x,y)

#テスト
predict = clf.predict_proba(x_test)[:,1]

n_jobsで解くときのプロセス数が調整できるのもまた便利です。
上記の記述ではレコードを0.9の確率、素性を0.2の確率でサンプリングしたレコードについてロジスティック回帰を100回解きます。
テストでは100回の学習結果の平均が利用されます。kaggleなどのコンペティションでは、この関数を利用するのとしないのとではスコアに大きな違いがでてくると考えています。
また、この関数も合わせて2値分類などで、精度をあげるための個人的な使い方も以下で紹介させていただきます。

from sklearn.utils import resample
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors.KNeighborsClassifier
from sklearn.linear_model import LogisticRegression

#ロジスティック回帰
clf1 = LogisticRegression()
clf1 = BaggingClassifier(base_estimator=clf1, n_estimators=100, max_samples=0.9, max_features=0.2,n_jobs=4)
#k-nearest neighbors
clf2 = KNeighborsClassifier()
clf2 = BaggingClassifier(base_estimator=clf2, n_estimators=100, max_samples=0.9, max_features=0.2,n_jobs=4)
#RandomForest
clf3 = RandomForestClassifier()

#データのリサンプリング
num = len(y)
x,y = resample(x,y,n_samples=num)

#トレーニング
clf1.fit(x,y)
clf2.fit(x,y)
clf3.fit(x,y)

#テスト
predict1 = clf.predict_proba(x_test)[:,1]
predict2 = clf.predict_proba(x_test)[:,1]
predict3 = clf.predict_proba(x_test)[:,1]
w1 = 0.5
w2 = 0.3
w3 = 1 - w - w2
out = w1*predict1 + w2*predict2 + w2*predict3

上記のように3つのモデルをブレンディングする事で精度が上がる事もあります。(もちろんパラメータなどは調整しないとだめです)
また、各関数の詳しい仕様は以下をご参照下さい。

リサンプリング
http://scikit-learn.org/dev/modules/generated/
sklearn.utils.resample.html#sklearn.utils.resample


ロジスティック回帰
http://scikit-learn.org/dev/modules/generated/
sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression


BaggingClassifier/BaggingRegressor
http://scikit-learn.org/dev/modules/generated/
sklearn.ensemble.BaggingClassifier.html#sklearn.ensemble.BaggingClassifier

http://scikit-learn.org/dev/modules/generated/
sklearn.ensemble.BaggingRegressor.html#sklearn.ensemble.BaggingRegressor


k-nearest neighbors
http://scikit-learn.org/dev/modules/generated/
sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier


RandomForest
http://scikit-learn.org/dev/modules/generated/
sklearn.ensemble.RandomForestClassifier.html#sklearn.ensemble.RandomForestClassifier

(6)作成したモデルを保存/読み込む

モデルの保存や読み込みもする事ができます。

from sklearn.externals import joblib
from sklearn.linear_model import LogisticRegression

#ロジスティック回帰
clf = LogisticRegression()

#データのリサンプリング
num = len(y)
x,y = resample(x,y,n_samples=num)

#トレーニング
clf.fit(x,y)

#モデルの保存
joblib.dump(clf,"model_dir/model")

#モデルの読み込み
clf = joblib.load("model_dir/model")

#テスト
predict = clf.predict_proba(x_test)[:,1]

指定のファイルに変数を保存できます。またそのファイルを変数として読み込む事ができます。
tfidfのベクトルなども保存できるので、学習に時間がかかるものや・ベクトルとして使い回すものに
対して利用するといいかもしれません。

詳しい仕様は以下をご参照下さい。

http://scikit-learn.org/0.10/tutorial.html#model-persistence

おわりに

今回は「分析・モデリング」の部分について紹介させていただきました。
しかしデータサイエンスとして一番重要なのは最後の「ビジネス提案/プロダクト実装」をした結果、どれだけビジネスを動かせたか、またその結果から次のPDCAがきちんと回せるかです。
分析・モデリング手法にフォーカスするだけでなく、データ視点でも考えていく事が大切なのを忘れないようにしましょう。
また、今回紹介しきれなかった役に立つ関数もあります。カテゴリーデータの数値化・素性のスケーリングなどもまた紹介できたらいいなと考えてます。

以上、ここまで読んでいただきありがとうございました。

Yahoo! JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。

  • このエントリーをはてなブックマークに追加