前回の続きです。
アイドルマスターシンデレラガールズの183人(2017/4現在)のプロフィールデータから、3つのタイプ(Cu,Co,Pa)の予測を行います。
取得した項目は、以下の16つ。183×16の行列です。
[タイプ,名前,年齢,誕生,星座,血液型,身長,体重,B,W,H,利き手,出身地,趣味,CV,実装日]
※タイプだけ項目名が入っていなかったため手動で追加しました。
この内、今回は以下の6つのデータを使用し、タイプの予測を行います。
[年齢,身長,体重,B,W,H]
#データの整形
取得したデータのtypeはすべてobjectとなっているため、数値型に変換します。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import csv
import pandas as pd
from pandas import DataFrame
import matplotlib
import matplotlib.pyplot as plt
def translate(df):
#データのタイプをfloatに変換
df['年齢']=df['年齢'].str.extract('([0-9]+)').astype(float)
df['身長']=df['身長'].astype(float)
df['体重']=df['体重'].str.extract('([0-9]+)').astype(float)
df['B']=df['B'].str.extract('([0-9]+)').astype(float)
df['W']=df['W'].str.extract('([0-9]+)').astype(float)
df['H']=df['H'].str.extract('([0-9]+)').astype(float)
#属性値を数値変換
df.loc[df['属性'] == "Cu", '属性'] = 0
df.loc[df['属性'] == "Co", '属性'] = 1
df.loc[df['属性'] == "Pa", '属性'] = 2
df['属性']=df['属性'].astype(int)
return df
if __name__ == '__main__':
#データ読み込み
df = pd.read_csv('aimasudata.csv')
df=translate(df)
- 年齢等のデータにはたまに日本語が混じっているため、数字だけを抽出するためにstr.extract('([0-9]+)')を使っています。([永遠の○歳]→[○]となります。やったね!)
- 属性値は、SVMの判定に使用するために数値変換しています。
#データの確認
機械学習によって本当に判別可能かを確認するためにデータをグラフ化してみます。
def checkdata(df,index):
#各タイプ毎のデータを取得
x1 = [df[index][df['属性']==0]]
x2 = [df[index][df['属性']==1]]
x3 = [df[index][df['属性']==2]]
#ヒストグラムの生成
plt.hist([x1,x2,x3], bins=16)
#画像の保存
plt.savefig("%s_graph.png" %index)
#画像の表示
plt.show()
if __name__ == '__main__':
#データ読み込み
df = pd.read_csv('row_data.csv')
df=translate(df)
checkdata(df,"年齢")
##結果
####年齢
青:Cu、橙:Co、緑:Paです。
Coは年齢高めの割合が多い。
####身長
Cuは低め、Coは高めか。このデータが最も差が出ている。
####体重
差は大きくないがCoがやや高め。全体的に軽すぎ。
####H
身体データ系は全体的にCoは値が高い。CuとPaの分離が微妙か?
#グリッドサーチ
今回は、SVMを用いて3つのクラス(Co,Cu,Pa)を判定します。
SVMを実装する際はパラメータ設定が必要ということなので、
まずはグリッドサーチを用いてSVM適用するパラメータを決定します。
[Scikit learnより グリッドサーチによるパラメータ最適化]
(http://qiita.com/SE96UoC5AfUt7uY/items/c81f7cea72a44a7bfd3a)
def gridsearch(df):
tuned_parameters = [{'C': [1, 10, 100, 1000, 10000], 'kernel': ['rbf'], 'gamma': [0.01,0.001, 0.0001]}]
score = 'f1'
clf = GridSearchCV(
SVC(), # 識別器
tuned_parameters, # 最適化したいパラメータセット
cv=5, # 交差検定の回数
scoring='%s_weighted' % score ) # モデルの評価関数の指定
df = df.dropna(subset=['年齢','身長','体重','B','W','H'])
X = df[['年齢','身長','体重','B','W','H']]
y = df["属性"]
clf.fit(X, y)
print"mean score for cross-validation:\n"
for params, mean_score, all_scores in clf.grid_scores_:
print "{:.3f} (+/- {:.3f}) for {}".format(mean_score, all_scores.std() / 2, params)
print clf.best_params_
結果
C=100, gamma=0.0001のときに結果がもっともよくなるみたいです。
#SVMの実装
グリッドサーチで得たパラメータを用い、SVMを実装します。
def dosvm(df):
#欠損値のある行を削除
df=df.dropna(subset=['年齢','身長','体重','B','W','H'])
X = df[['年齢','身長','体重','B','W','H']]
y = df["属性"]
data_train,data_test,label_train,label_test=train_test_split(X,y,test_size=0.2)
clf = svm.SVC(kernel="rbf",C=100,gamma=0.0001)
clf.fit(data_train, label_train)
result=clf.predict(data_test)
cmat=confusion_matrix(label_test,result)
acc=accuracy_score(label_test,result)
print cmat
print acc
100試行くらい行ったところ、だいたい0.45くらいの精度で判別できました。
混同行列を見る限り、やはりPaの予測がうまくできてないみたいです。
#メモ
- 始めた時は全く識別できないかと思っていたが、意外と識別できた。
- SVMを用いる際はパラメータの設定が必須。(設定せずやったら結果が0.3くらいになった)
- 今回6つのパラメータを用いてタイプの予測を行なったが、身長だけのパラメータを用いても約0.42くらいの精度が出る。逆に、身長を除いた5つのパラメータを使うと、約0.36の精度。このあたりの結果の原因分析の方法を学びたい
- 私はCoでした(予測通り)