20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

カテゴリ変数に負けずに python で機械学習する(ダミー変数化)

Last updated at Posted at 2017-07-11

いつも同じことを調べているので、
これを機にメモにしておきました。

ここでは実際に python でcsv を読み込み、
ダミー変数化などの前処理を行ってSVMで予測を行いました。

モチベ

データを機械学習に突っ込む際に、データにカテゴリ変数(例:性別、出身国)が入っている場合があります。
そのときただの数値(例:日本なら1、アメリカなら2)に変えた場合、意図しない意味をデータに
与えてしまうので、学習がうまくいかないことがあります。

ここではダミー変数という方法でカテゴリ変数を数値に変換して対処します。

ダミー変数とは

例えば、以下のようなデータを想定します。

  • ここでは国という一列だけ持っている
  • 国は全部で {日本, アメリカ, 中国} しかない
  • 元のデータでは という列があって、その中に {日本, アメリカ, 中国} のいずれかが
    格納されているとする

ダミー変数化では、 という列を、国.日本, 国.アメリカ, 国.中国 という3つの列にして、
該当する値だけ 1 にして、その他を 0 とした形に変換します。

ダミー変数化前データ例

日本

ダミー変数化後データ例

国.日本 国.アメリカ 国.中国
1 0 0

実装

データの取得

今回は「Adult Income Data Set」という匿名化加工などの実験で用いられるデータを用いました。
おそらくググっても手に入りますが、今回は R で取得しました(python と言っているのに早速 R を使っているのは気にしないでください)。

また、このデータセットには income(収入) という項目があり、large, small, NaN の3つの値があります。
今回の実装では NaN(欠損値) に対し、large or small を予測したいとします。

そのため NaN が入っていない行を訓練データ、入っているデータを評価用データとしました。

library('arules')
data("AdultUCI")
id <- 1:nrow(AdultUCI)
d <- data.frame(id, AdultUCI)
write.csv(d, "AdultDataSet.csv", quote = FALSE, fileEncoding = 'cp932', row.names = FALSE)

ライブラリとcsvファイルの読み込み

import numpy as np
import pandas as pd
from sklearn import svm

df = pd.read_csv("AdultDataSet.csv", encoding='cp932', low_memory=False)

前処理(ダミー変数化も行う)

# 訓練ラベル
Y_train = df.copy()
Y_train['income'] = Y_train['income'].map({"large":1, "small":0})
Y_train = Y_train[Y_train['income'].notnull()]
Y_train = Y_train.iloc[:, 15].values #  income のみ

# カテゴリ変数のダミー変数作成
X = df.iloc[:, 0:15] #  income 以外
colnames_categorical = ['workclass', 'marital.status', 'occupation', 'relationship', 'race', 'sex', 'native.country']
X_dummy = pd.get_dummies(X[colnames_categorical], drop_first=True)

# ダミー変数の結合
X = pd.merge(X, X_dummy, left_index=True, right_index=True)

# 使わない、重複している列の削除
X = X.drop(colnames_categorical, axis=1)
X = X.drop(['id', 'education'], axis=1)

# income が NaN か否かで train と test を分ける
X_train = X[df['income'].notnull()].values
X_test  = X[df['income'].isnull()].values

学習と予測

# 学習
clf = svm.LinearSVC() #  学習が速いから。他には svm.SVC(kernel='rbf') 等がある
print('start!')
clf.fit(X_train, Y_train)
print('end!')

# 予測
Y_predict = clf.predict(X_test)

予測した結果の結合

# 予測した値を加える
df2 = df.copy()
df2.loc[df2['income'].isnull(), 'income'] = Y_predict
df2['income'] = df2['income'].map({1.:"large", 0.:"small", "small":"small", "large":"large"})
df2.head()

結果の確認

本来は予め正解ラベルがついているデータを分類して性能を評価するべきだと思いますが、
今回は欠損しているデータに対して予測したことと、趣旨はダミー変数化の適用ですので
とりあえず欠損値がなくなっていることを確認してみます。

# 学習前の income の集計値
count_before = df['income'].value_counts(dropna=False)
pd.DataFrame(count_before) #  print(count_before) でもよい
# 学習後の income の集計値
count_after = df2['income'].value_counts(dropna=False)
pd.DataFrame(count_after)

これで学習後に NaN が消えていればひとまずOKです。

結果の出力

df2.to_csv('AfterAdultDataSet.csv', index=False)

さいごに

そこまで難しいことではないはずなのに、pandas の使い方とかscikit learn への
入力等で苦労した…悲しい…

20
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?