Python pandas / scikit-learn 向けのちょっとしたパッケージ作った <前編>
こちらの続き。
pandas
のデータを scikit-learn
でうまく処理するためのパッケージを作ったのでその使い方を書きたい。今回は 適当なデータをファイルから読み込み -> 前処理してクラスタリングする、という例を書く。
このパッケージ 基本的には pandas
と使い方は同じなので、以下 追加機能にあたる部分を中心に記載する。
- データは 説明変数 / 目的変数の定義をもち、それぞれプロパティから参照 / 上書きできる。
scikit-learn
の各サブパッケージにプロパティからアクセスできる。また、メソッド呼び出し時の引数を省略できる。
インストール
pip install pandas_ml
補足 今後 別パッケージへの拡張を考えているため、scikit-learn
への依存は optional にしている。そのため、scikit-learn
をインストールしていない方は別途インストールを。
データの読み込み
こういう例を書くとき、 iris 以外のデータがぱっと出てくる人ってかっこいいと思う。
# おまじない import numpy as np import pandas as pd pd.options.display.max_rows = 8 state = np.random.RandomState(1) # csv からデータ読み込み # http://aima.cs.berkeley.edu/data/iris.csv names = ['Sepal.Length', 'Sepal.Width', 'Petal.Length', 'Petal.Width', 'Species'] iris = pd.read_csv('iris.csv', header=None, names=names) iris # Sepal.Length Sepal.Width Petal.Length Petal.Width Species # 0 5.1 3.5 1.4 0.2 setosa # 1 4.9 3.0 1.4 0.2 setosa # 2 4.7 3.2 1.3 0.2 setosa # 3 4.6 3.1 1.5 0.2 setosa # .. ... ... ... ... ... # 146 6.3 2.5 5.0 1.9 virginica # 147 6.5 3.0 5.2 2.0 virginica # 148 6.2 3.4 5.4 2.3 virginica # 149 5.9 3.0 5.1 1.8 virginica # # [150 rows x 5 columns] type(iris) # <class 'pandas.core.frame.DataFrame'>
上で読み込んだデータを pandas_ml
で処理するには、一度 pandas_ml.ModelFrame
インスタンスに変換する必要がある。ModelFrame
を作成するには、
- 第一引数には、
pd.DataFrame
に変換できる何か (DataFrame
自体, 辞書など) を渡す target
キーワードには、目的変数として扱いたい 列名の文字列、もしくはpd.Series
に変換できる何か (Series
、もしくはリスト-like )を渡す
詳しくは ドキュメント を。
今回は 第一引数には pd.DataFrame
、 target
には 目的変数として扱いたい列名である "Species" を指定する。
import pandas_ml as pdml df = pdml.ModelFrame(iris, target='Species') type(df) # <class 'pandas_ml.core.frame.ModelFrame'> # ModelFrame は DataFrame のサブクラス isinstance(df, pd.DataFrame) # True
補足 target
キーワードを指定しない場合、目的変数をもたない ModelFrame
インスタンスが作成される。
作成した ModelFrame
は pd.DataFrame
と同じように扱える。一部、 pd.DataFrame
にないメソッド / プロパティを持つ。
df # Sepal.Length Sepal.Width Petal.Length Petal.Width Species # 0 5.1 3.5 1.4 0.2 setosa # 1 4.9 3.0 1.4 0.2 setosa # 2 4.7 3.2 1.3 0.2 setosa # 3 4.6 3.1 1.5 0.2 setosa # .. ... ... ... ... ... # 146 6.3 2.5 5.0 1.9 virginica # 147 6.5 3.0 5.2 2.0 virginica # 148 6.2 3.4 5.4 2.3 virginica # 149 5.9 3.0 5.1 1.8 virginica # # [150 rows x 5 columns] # データが目的変数を持っているかを確認 df.has_target() # True # 説明変数は data プロパティで参照 df.data # Sepal.Length Sepal.Width Petal.Length Petal.Width # 0 5.1 3.5 1.4 0.2 # 1 4.9 3.0 1.4 0.2 # 2 4.7 3.2 1.3 0.2 # 3 4.6 3.1 1.5 0.2 # .. ... ... ... ... # 146 6.3 2.5 5.0 1.9 # 147 6.5 3.0 5.2 2.0 # 148 6.2 3.4 5.4 2.3 # 149 5.9 3.0 5.1 1.8 # # [150 rows x 4 columns] # 目的変数は target プロパティで参照 df.target # 0 setosa # 1 setosa # ... # 148 virginica # 149 virginica # Name: Species, Length: 150, dtype: object # 目的変数の列名を取得 df.target_name # 'Species' # これも一緒 (target の name 属性を見ているので) df.target.name # 'Species'
このとき、ModelFrame.data
は 目的変数のない ModelFrame
インスタンスに、また ModelFrame.target
は pd.Series
を継承した ModelSeries
インスタンスになっている。
type(df.data) # <class 'pandas_ml.core.frame.ModelFrame'> df.data.has_target() # False type(df.target) # <class 'pandas_ml.core.series.ModelSeries'> isinstance(df.target, pd.Series) # True
データの前処理
いくつか前処理を行う。まず、target
についているラベル ( "setosa", "versicolor", "virginica" ) を数値 (0, 1, 2) に変換する。この処理は pandas
の map
がカンタン。
df.target.map({'setosa': 0, 'versicolor': 1, 'virginica': 2}) # 0 0 # 1 0 # ... # 148 2 # 149 2 # Name: Species, Length: 150, dtype: int64 # これをそのまま target に代入すればよい df.target = df.target.map({'setosa': 0, 'versicolor': 1, 'virginica': 2}) df # Species Sepal.Length Sepal.Width Petal.Length Petal.Width # 0 0 5.1 3.5 1.4 0.2 # 1 0 4.9 3.0 1.4 0.2 # 2 0 4.7 3.2 1.3 0.2 # 3 0 4.6 3.1 1.5 0.2 # .. ... ... ... ... ... # 146 2 6.3 2.5 5.0 1.9 # 147 2 6.5 3.0 5.2 2.0 # 148 2 6.2 3.4 5.4 2.3 # 149 2 5.9 3.0 5.1 1.8 # # [150 rows x 5 columns]
次に、(特に理由はないが) "Sepal.Length" と "Sepal.Width" のみを正規化する。これは pandas
にはない処理なので、 sklearn.preprocessing.normalize
を使う。
ModelFrame
は scikit-learn
の各サブパッケージに対応したプロパティ (アクセサ) を持っており、サブパッケージをロードしなくても 対応する関数をメソッドとして利用できる。このとき、呼び出し元のデータが自動的に引数として渡されるため データの引数指定は不要。
サブパッケージとプロパティの対応一覧はドキュメント を。
df[['Sepal.Length', 'Sepal.Width']].preprocessing.normalize() # Sepal.Length Sepal.Width # 0 0.824513 0.565842 # 1 0.852851 0.522154 # 2 0.826599 0.562791 # 3 0.829266 0.558853 # .. ... ... # 146 0.929491 0.368846 # 147 0.907959 0.419058 # 148 0.876812 0.480833 # 149 0.891385 0.453247 # # [150 rows x 2 columns] # これもそのまま代入すればよい df[['Sepal.Length', 'Sepal.Width']] = df[['Sepal.Length', 'Sepal.Width']].preprocessing.normalize() df # Species Sepal.Length Sepal.Width Petal.Length Petal.Width # 0 0 0.824513 0.565842 1.4 0.2 # 1 0 0.852851 0.522154 1.4 0.2 # 2 0 0.826599 0.562791 1.3 0.2 # 3 0 0.829266 0.558853 1.5 0.2 # .. ... ... ... ... ... # 146 2 0.929491 0.368846 5.0 1.9 # 147 2 0.907959 0.419058 5.2 2.0 # 148 2 0.876812 0.480833 5.4 2.3 # 149 2 0.891385 0.453247 5.1 1.8 # # [150 rows x 5 columns]
クラスタリング
ModelFrame.cluster.k_means
で、sklearn.cluster.k_means
を呼び出せる。このメソッドの返り値は centroid, label, inertia の 3つになる。
centroid, label, inertia = df.cluster.k_means(n_clusters=3, random_state=state) centroid # array([[ 0.82602947, 0.56251635, 1.464 , 0.244 ], # [ 0.91055414, 0.41171559, 5.59583333, 2.0375 ], # [ 0.90545279, 0.42259059, 4.26923077, 1.34230769]]) label # 0 0 # 1 0 # ... # 148 1 # 149 1 # Length: 150, dtype: int32 inertia # 31.598367459843072
もしくは、ModelFrame.cluster.KMeans
から sklearn.cluster.KMeans
インスタンスを作成して fit
-> predict
する。メソッドの呼び出しを ModelFrame
側から行うことで引数を省略できる。
kmeans = df.cluster.KMeans(n_clusters=3, random_state=state) df.fit(kmeans) # KMeans(copy_x=True, init='k-means++', max_iter=300, n_clusters=3, n_init=10, # n_jobs=1, precompute_distances=True, # random_state=<mtrand.RandomState object at 0x104053410>, tol=0.0001, # verbose=0) df.predict(kmeans) # 0 1 # 1 1 # ... # 148 0 # 149 0 # Length: 150, dtype: int32
直前に利用された estimator は ModelFrame.estimator
から参照できる。また、直近のクラスタリング結果は ModelFrame.predicted
にキャッシュされている。
df.estimator # KMeans(copy_x=True, init='k-means++', max_iter=300, n_clusters=3, n_init=10, # n_jobs=1, precompute_distances=True, # random_state=<mtrand.RandomState object at 0x104053410>, tol=0.0001, # verbose=0) df.predicted # 0 1 # 1 1 # ... # 148 0 # 149 0 # Length: 150, dtype: int32
ModelFrame.metrics
はsklearn.metrics
の各メソッドを引数省略して呼び出せる。このとき、内部的には上のキャッシュが利用されている。
df.metrics.completeness_score()
# 0.8643954288752761
引数省略時の内部処理について
scikit-learn
の各メソッドと 内部的に渡すデータの対応関係一覧は以下ドキュメントに記載している。何かおかしなことをやっていたら GitHub からご指摘ください。
まとめ
pandas_ml
を利用して データの読み込み / 前処理 / クラスタリングを行う方法を記載した。
次は、Pipeline, Cross Validation, Grid Search あたりを。
Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理
- 作者: Wes McKinney,小林儀匡,鈴木宏尚,瀬戸山雅人,滝口開資,野上大介
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/12/26
- メディア: 大型本
- この商品を含むブログ (10件) を見る
9/12追記 パッケージ名変更。