機械学習の学習を進めるうえで、データクレンジング等大量のデータを扱うのは面倒な作業です。今回は、これらの作業が少し楽になるPostgresqlとカテゴリ化の実装およびライブラリを紹介します。
PostgreSQL
学習に用いるデータは、一旦PostgreSQLに格納しています。傾向を確認したり、データの選別にとても便利だからです。PostgreSQLに書き込んだり、読み込んだりする時に便利な関数およびライブラリを下記に示します。
データ書き込み
データ書き込みは、一旦ディクショナリに格納して名前付きでデバッグ時に見やすくしています。その名前をデータベースのカラム名と一致させておけば、そのまま書き込むことが可能です。
また、execute_values関数を用いることで、executemany関数使用時より高速で書き込みを行ってくれます。
import psycopg2 as pg2
from psycopg2 import extras
import pandas.io.sql as sqlio
import category_encoders as ce
import pandas as pd
def insert(cur, tablename, array_dict_data):
# dictionaryをtupleに変換する
columns, array_tuples = get_dict_to_tuple(array_dict_data)
# クエリ文字列を構成する
sql = 'insert into {0} ({1}) values {2}'.format(tablename, columns, '%s')
extras.execute_values(cur, sql, array_tuples)
def get_dict_to_tuple(array_dict_data):
# カラム名のカンマ区切り文字列を作成する
columns = ','.join(array_dict_data[0].keys())
# 代入する値をタプルで作成する
array_tuples = []
for dic in array_dict_data:
values = dic.values()
tuple_data = tuple(values)
array_tuples.append(tuple_data)
return columns, array_tuples
def main():
host = 'localhost'
port = 5432
dbname = 'test'
username = 'postgres'
pwd = 'P@ssw0rd'
tablename ='test_table'
with pg2.connect("host='{}' port={} dbname='{}' user={} password={}".format(host, port, dbname, username, pwd)) as conn:
# postgresにデータを追加する
data_array = [
{'id': 0, 'name':'x', 'num':100, 'address':'b'},
{'id': 1, 'name':'y', 'num':200, 'address':'c'},
{'id': 2, 'name':'x', 'num':300, 'address':'d'},
{'id': 3, 'name':'y', 'num':400, 'address':'c'},
{'id': 4, 'name':'z', 'num':500, 'address':'c'}
]
insert(conn.cursor(), tablename, data_array)
conn.commit()
データ読み込み
PostgreSQLからselect文でデータを読み出すときは、pandas.io.sqlを用いると、戻り値を直接DataFrameに格納してくれます。これにより、この後のデータ処理が大変楽になります。
# postgresからdataframeで取得する
sql = "select * from {};".format(tablename)
data = sqlio.read_sql_query(sql, conn)
print(data.head())
結果は、DataFrameにセットされており、先ほど書き込んだデータが取り出せています。
id name num address
0 0 x 100.0 b
1 1 y 200.0 c
2 2 x 300.0 d
3 3 y 400.0 c
4 4 z 500.0 c
カテゴリ化
機械学習を進めるうえで、データクレンジング作業はとても大切ですが、文字列が含まれると厄介です。面倒なので除去したり、戻り値型が変わったり、ダイレクト変更できないものを渋々エンコード処理したりしているかと思います。
ここで紹介するCategory Encodersを用いると、文字列のカテゴリ化を簡単に処理できます。
OneHotエンコード
カテゴリ化の代表的な手法である、OneHotエンコードを行います。ここでは、”address”列を指定しています。複数列同時に指定することも可能です。
# OnehotEncodingする
cols = ['address']
onehotEncoder = ce.OneHotEncoder(cols=cols, handle_unknown='impute')
ohe = onehotEncoder.fit_transform(data)
print(ohe.head())
結果は、address列がデータ登場パターンである3つに展開しています。メモリの許す限り、この処理を自動的に実施してくれます。
id name num address_1 address_2 address_3
0 0 x 100.0 1 0 0
1 1 y 200.0 0 1 0
2 2 x 300.0 0 0 1
3 3 y 400.0 0 1 0
4 4 z 500.0 0 1 0
オーディナリエンコード
製品番号の様に特徴量のパターンが多すぎてOneHotエンコードでは収まりきらない場合、1から連番をつけるオーディナリエンコードを用いる方法があります。こちらは、”name”列に適用してみます。
# OrdinalEncodingする
cols = ['name']
ordinalEncoder = ce.OrdinalEncoder(cols=cols, handle_unknown='impute')
oe = ordinalEncoder.fit_transform(ohe)
print(oe.head())
結果は、こちらも3パターンで、同じ文字の時に同じ数値を示していることが分かります。OneHotエンコードの様に列が爆発的に増加することはありません。
id name num address_1 address_2 address_3
0 0 1 100.0 1 0 0
1 1 2 200.0 0 1 0
2 2 1 300.0 0 0 1
3 3 2 400.0 0 1 0
4 4 3 500.0 0 1 0
まとめ
機械学習を進めるときに、学習のチューニング等に時間を費やしたいので、データ処理は出来るだけ手軽に済ませたいものです。今回紹介したような手法を用いて、データ処理を簡潔に完了させて作業を減らしていきましょう。
以上、機械学習をサポートするPythonのデータ処理小技の紹介でした。
コメント