PandasのデータフレームをScikit-learnの入力データに変換する方法(2.コーディング)

概要

前回記事で検討した以下の要件定義を元にコーディングを進めていきます。

  1. 説明変数のデータ列と目的変数のデータ列に分ける
  2. 説明変数のデータを下記の通り変換する
    • 数値データはそのまま
    • カテゴリデータはバイナリ化
    • それ以外のデータ(時系列等)は除外
  3. 説明変数のデータとカラム名を分けてオブジェクトのメンバに割り付ける
  4. 目的変数のデータをシリアル化する
  5. 目的変数の値と名称を分けてオブジェクトのメンバに割り付ける
  6. データセットの名称をオブジェクトのメンバに割り付ける

コーディング

説明も兼ねて部分部分に分けて解説していきます。全体のソースコードは末尾を参照ください。

必要モジュールのインポート

本機能を実装するにあたり必要なモジュールをインポートします。

import pandas as pd
import numpy as np
from sklearn import datasets
import sklearn.preprocessing as sp

datasetsはscikit-learnのデータセットの構造を使うためにインポート、preprocessingは同前処理機能を使うためにインポートしています。preprocessingについては下記記事に詳しく書きましたので参考にしてください。pandas、numpyはお馴染みのモジュールのため、説明は省略します。

Sklearnのpreprocessingの全メソッドを解説


関数名と引数

関数名はpan2sk(パン○好き)としました。引数はデータフレームと目的変数、そしてデータ名です。データ名に関してはデフォルトでDataという名称を与えています。”””で挟まれた部分はhelp扱いとなり、help(pan2sk)と打つと表示される内容になります。

def pan2sk(df, target, name="Data"):
    """
    <概要>
    pandasのデータフレームをscikit-learnの入力データに変換する関数
    
    <引数>
    df:データフレーム
    target:目的変数のカラム名
    
    <出力>
    Bunch:scikit-learn形式に変換したデータ
    """

説明変数のデータ列と目的変数のデータ列の分離

dfからtargetに一致しないデータを説明変数(expdata)、一致するデータを目的変数(objdata)としています。

    #説明変数のデータ列と目的変数のデータ列に分ける    
    expdata = df[df.columns[df.columns!=target]]
    objdata = df[target].copy()

説明変数のデータ変換

数値データはそのまま、カテゴリデータはバイナリ化、それ以外のデータは除外します。カテゴリデータの処理は①tempにバイナリ後のデータを格納、②expdataに結合、③もともとの列を削除という手順で実施しています。面倒そうな処理ですが、実はunique()とlabel_binarize()を使うことで簡単に実現します。

    for column in expdata.columns:
        #数値データはそのまま
        if (expdata[column].dtypes == int) or (expdata[column].dtypes == float):
            pass
        
        #カテゴリデータはバイナリ化
        elif expdata[column].dtypes == object:
            temp = pd.DataFrame(index=expdata[column].index, columns=column + " = "  + expdata[column].unique()
            , data=sp.label_binarize(expdata[column], expdata[column].unique()))
            expdata = pd.concat([expdata, temp], axis=1)
            del expdata[column]
            
        #それ以外のデータ(時系列等)は除外
        else:
            del expdata[column]

    #説明変数のデータとカラム名を分けておく
    data=np.array(expdata)
    feature_names=np.array(expdata.columns)

目的変数のデータ変換

数値データはそのまま、カテゴリデータはシリアル化します。これも同様に、unique()とLabelEncoder()を使うことで簡単に実現します。

    #目的変数のデータをシリアル化する
    #数値データはそのまま登録
    if (objdata.dtypes == int) or (objdata.dtypes == float):
        targetData = np.array(objdata)
        target_names = []

    #カテゴリデータはシリアル化して登録
    if objdata.dtypes == object:
        
        le = sp.LabelEncoder()
        le.fit(objdata.unique())
        
        targetData = le.transform(objdata)
        target_names = objdata.unique()

オブジェクト作成

最後にオブジェクトに割り当てれば完成です。

    #データセットの名称を用意
    DESCR = name
    
    #オブジェクト作成
    skData = datasets.base.Bunch(DESCR=DESCR, data=data, feature_names=feature_names, target=targetData, target_names=target_names)
    
    return skData

使い方

pan2skにpandasのデータフレームと目的変数のカラム名、データフレーム名(なくても可)を渡すだけで、汎用的に変換されます。

    df = pd.read_csv("iris.csv", index_col=0)   
    skData = pan2sk(df, target='Name', name='iris')

skDataを確認すると以下のようになっており、目論見通り動作していることが確認できました。


pan2sk_iris

まとめ

「pandasで読み込んだデータをそのままscikit-learnの分析ライブラリに投入」するためのライブラリ[pan2sk]を作ってみました。
今後は細かいエラー処理や並列計算、正規化や教師なし学習への対応等を進めていきたいです。





全ソースコード

GitHubにて、ソースコードを公開しています。

import pandas as pd
import numpy as np
from sklearn import datasets
import sklearn.preprocessing as sp

def pan2sk(df, target, name="Data"):
    """
    <概要>
    pandasのデータフレームをscikit-learnの入力データに変換する関数
    
    <引数>
    df:データフレーム
    target:目的変数のカラム名
    
    <出力>
    Bunch:scikit-learn形式に変換したデータ
    """
    
    #説明変数のデータ列と目的変数のデータ列に分ける    
    expdata = df[df.columns[df.columns!=target]]
    objdata = df[target].copy()
    
    #説明変数の各データについて変換
    for column in expdata.columns:
        #数値データはそのまま
        if (expdata[column].dtypes == int) or (expdata[column].dtypes == float):
            pass
        
        #カテゴリデータはバイナリ化
        elif expdata[column].dtypes == object:
            temp = pd.DataFrame(index=expdata[column].index, columns=column + " = "  + expdata[column].unique()
            , data=sp.label_binarize(expdata[column], expdata[column].unique()))
            expdata = pd.concat([expdata, temp], axis=1)
            del expdata[column]
            
        #それ以外のデータ(時系列等)は除外
        else:
            del expdata[column]
    
    #説明変数のデータとカラム名を分けておく
    data=np.array(expdata)
    feature_names=np.array(expdata.columns)
    
    #目的変数のデータをシリアル化する
    #数値データはそのまま登録
    if (objdata.dtypes == int) or (objdata.dtypes == float):
        targetData = np.array(objdata)
        target_names = []

    #カテゴリデータはシリアル化して登録
    if objdata.dtypes == object:
        
        le = sp.LabelEncoder()
        le.fit(objdata.unique())
        
        targetData = le.transform(objdata)
        target_names = objdata.unique()

    #データセットの名称を用意
    DESCR = name
    
    #オブジェクト作成
    skData = datasets.base.Bunch(DESCR=DESCR, data=data, feature_names=feature_names, target=targetData, target_names=target_names)
    
    return skData

if __name__ == "__main__":
    
    df = pd.read_csv("iris.csv", index_col=0)   
    skData = pan2sk(df, target='Name', name='iris')


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA