Up

共通数量化Pythonプログラム

カテゴリ項目のデータ前処理

2023.11更新:Excelファイルへの出力スクリプトの更新。説明の増補。

 

カテゴリ変数に数値を与える方法として機械学習ではOne Hot Encodingと呼ばれている処理がある。各カテゴリ値に対応してダミー変数を用意する方法である。これに対して共通数量化では各カテゴリ値を数値で置き換える。数値に置き換えたときの分散が最大(極大)になるように数値が決められる。indicator 行列を

とおけば、

である。

制約条件

のもとで、分散

が最大になるようにカテゴリに割り当てる数値のベクトル  を求める。これは、の中心化行列

に対して、次式の固有分解

の固有ベクトルとして得ることができる。固有分解については、岡本(2009pp. 41-45で説明している。

詳しくは、岡本(2019第8章、あるいはOkamoto (2015)を参照されたい。

岡本安晴「いまさら聞けないPythonでデータ分析」丸善出版>の第8章では、質問紙データの共通数量化による前処理に基づいて主成分分析、回帰分析を行い、主成分分析の結果を利用してクロス表の作成を行っている。作成したクロス表は第12章および第15章でベイズ分析を行っている。

One Hot Encodingと共通数量化との比較を行動計量学会大会2020で報告した。

以下に共通数量化のPythonプログラム例の使用法について説明する。

 

プログラムの使用法

 共通数量化を行うプログラムとサンプルデータのファイルを圧縮ファイルcommonqfiles.zipにまとめた。ダウンロード・解凍すれば、自由に利用できる。

プログラムでは、数量化はモジュールmymodule.pyで行っているが、このスクリプトは本サイト後半のリスト1に示した。メインプログラムは本サイト後半のリスト2に示すMainCommonQ.pyである。リスト2のプログラムを実行すると、入力データファイル名の設定が求められる。

 

Data File Name (*.xlsx) =

 

データファイルは、Excelで図1のように用意する。

図1 ファイル名Data.xlsx

 

1行目に変数名を書く。2行目は、それぞれの変数の処理法、なにもしないときは0、標準化するときは1、数量化を行うときは、そのカテゴリ変数のカテゴリ数を書く。カテゴリ数がKのときはカテゴリ値は1からKまでの整数値で表す。データは3行目以降に書く。

図1のExcelファイルを入力ファイルとするときは、次のようにファイル名を設定する。

 

Data File Name (*.xlsx) = Data.xlsx

 

入力データファイル名を設定すると、計算が始まるが、モジュールxlrdあるいはopenpyxlがないというようなメッセージが出るときがある。このときは、pipcondaコマンドでモジュールをインストールしてから、あらためてリスト2のプログラムを実行すればよい。

入力データファイル名の設定後、プログラムの実行が終了すると、端末には図3のような出力が表示されている。

 

Quantified Data was saved in cq_Data.xlsx

 

Log file = q_Data.txt

 

数量化の処理後のデータファイルは、cq_Data.xlsxに出力されている。これは入力データファイル名の先頭に「cq_」が付いたものである。このファイルをExcelで開くと、図2のようになっている。

図2

 

図1のデータの2行目で指定された通りに処理されていることがわかる。標準化を行った変数は、変数名の先頭に「z_」を付けて表されている。数量化を行った変数は、変数名の先頭に「q_」が付けられ、さらに同じカテゴリ変数における異なる数量化は変数名の末尾に「_0」などと通し番号を付けて区別されている。

Log fileの名前「q_Data.txt」は、入力ファイルの先頭に「q_」を付け、ファイル拡張子を「.txt」に替えたものである。開くと以下のようになっている。

 

Data file = Data.xlsx

 

Quantification of CA

eigen values = [8.88178420e-16 4.56642909e+00 6.49239444e+00]

Created...q_CA_0   for lambda = 6.4924

                           with omega = 0.74653   -0.65965   -0.08688  

Created...q_CA_1   for lambda = 4.5664

                           with omega = -0.33069   -0.48117   0.81186  

 

Quantification of CB

eigen values = [8.88178420e-16 4.56642909e+00 6.49239444e+00]

Created...q_CB_0   for lambda = 6.4924

                           with omega = 0.74653   -0.65965   -0.08688  

Created...q_CB_1   for lambda = 4.5664

                           with omega = -0.33069   -0.48117   0.81186  

 

Output file = cq_Data.xlsx

 

 

数量化を行った変数について、固有値、固有ベクトルが出力されている。

なお、固有ベクトル、それから導かれた数量化の値の符号が実行環境によって反転することがあるが、これは(1)の解が固有ベクトルの符号を反転したものも解であることによる。いずれの解も正しい。

 

数量化の結果は図2のようにExcelファイルとして得られるので、他の量的変数と同じように分析すればよい。本安晴(2015、行動計量学会大会発表要旨)岡本安晴(2019、「いまさら聞けないPythonでデータ分析」丸善出版、8章)などを参照されたい。

 

 

リスト1 数量化を行うモジュールmymodule.py

import numpy as np

import scipy as sc

 

def common_q(K, vname, X, fout):

    fout.write('\n\nQuantification of {}'.format(vname))

    nq = K - 1

    n = len(X)

    G = np.zeros((n, K))

    for i in range(n):

        G[i, X[i] - 1] = 1.0

    f = G.sum(axis = 0)

    for k in range(K):

        if f[k] == 0:

            print('Category-{0} of variable {1} is not used.'.format(k+1, vname))

            fout.write('\n\nCategory-{0} of variable {1} is not used.'.format(k+1, vname))

            fout.close()

            raise Exception('Category Error !')

    One_n = np.ones((n, 1))

    f = np.reshape(f, (1, K))

    H = G - One_n @ f / n

 

    HpH = H.T @ H

 

    wt, vctr = np.linalg.eig(HpH)

    idx = np.argsort(wt)

    wt = wt[idx]

    vctr = vctr.T[idx].T

    fout.write('\neigen values = {}'.format(wt))

 

    nq = K - 1

    qnames = []

    qvars = []

    for h in range(K - 1):

        qnames.append('q_' + vname + '_{}'.format(h))

        z = H @ np.reshape(vctr[:, K-1-h], (K, 1)) / ((wt[K-1-h]/n) ** 0.5)

        qvars.append(z)

        fout.write('\nCreated...{0:s}   for lambda = {1:.5}\n'.format(qnames[-1], wt[K-1-h]))

        fout.write('                           with omega = ')

        for j in range(K):

            fout.write('{0:.5}   '.format(vctr[j][K-1-h]))

                     

   

    return nq, qnames, qvars

 

 

リスト2 主プログラムMainCommonQ.py

 

import pandas as pd

import scipy.stats as ss

import numpy as np

import mymodule as mm

 

flnm = input('Data File Name (*.xlsx) = ')

 

fout_nm = 'q_' + flnm[:-4] + 'txt'

fout = open(fout_nm, 'w')

fout.write('Data file = ' + flnm)

 

xlsx = pd.ExcelFile(flnm)  

data = pd.read_excel(xlsx)

print(data)

print(data.columns)

print(data.columns.values)

print(data.values)

 

X = data.values[1:]

print('X =\n', X)

print('X[:,0] =\n', X[:,0])

ndata = len(X)

print('ndata = ', ndata)

 

indx = data.columns.values

cndtn = data.values[0]

nvar = len(indx)

print('nvar = ', nvar)

print('indx =\n', indx)

print('cndtn =\n', cndtn)

 

 

temp_df = pd.DataFrame()

for i in range(nvar):

    if (cndtn[i] < 0):

        print('condition for var-{} < 0'.format(i))

        raise 'var_cond error.'

    else:

        if (cndtn[i] == 0):

            temp_df[indx[i]] = X[:, i]

        elif (cndtn[i] == 1):

            temp_df[indx[i] + '_z'] = ss.zscore([x for x in X[:, i]])

        else:

            nq, varnames, qvars = mm.common_q(cndtn[i], indx[i], X[:, i], fout)

            for j in range(nq):

                temp_df[varnames[j]] = qvars[j]

                

with pd.ExcelWriter('cq_' + flnm) as xl_writer:

    temp_df.to_excel(xl_writer, index = False)

print('\nQuantified Data was saved in ' + 'cq_' + flnm)

fout.write('\n\nOutput file = ' + 'cq_' + flnm)

   

fout.close()

print('\nLog file = ' + fout_nm + '\n')

 

 

 

Up