見出し画像

前処理

実務におけるデータに対しては前処理が重要になる。Pythonだとscipy.statsかscikit-learnのpreprocessingを使う。

以前使ったPM2.5のデータを用いて解説する。


import pandas as pd
%matplotlib inline
df = pd.read_csv("http://logopt.com/data/PRSA.csv")
df.head()

>>>
No year month day hour pm2.5 DEWP TEMP PRES cbwd Iws Is Ir
0 1 2010 1 1 0 NaN -21 -11.0 1021.0 NW 1.79 0 0
1 2 2010 1 1 1 NaN -21 -12.0 1020.0 NW 4.92 0 0
2 3 2010 1 1 2 NaN -21 -11.0 1019.0 NW 6.71 0 0
3 4 2010 1 1 3 NaN -21 -14.0 1019.0 NW 9.84 0 0
4 5 2010 1 1 4 NaN -20 -12.0 1018.0 NW 12.97 0 0

pm2.5の列の分布を正規化しよう。NaNがたくさんあるので、消しておく。

df.dropna(inplace=True)

ヒストグラムを描いてみると正規分布から大きく外れていることが確認できる。

df["pm2.5"].hist();

以前行った時系列解析では、小さな数を加えてから対数をとった。これは、Box-Cox変換の特殊系でパラメータlmbda(Pythonだとlambdaが予約後なのでちょっと変えたものを使う)が0の場合だ。一般には、以下の変換を行う。

y = (x**lmbda - 1) / lmbda, for lmbda > 0
       log(x), for lmbda = 0

G.E.P. Box and D.R. Cox, “An Analysis of Transformations”, Journal of the Royal Statistical Society B, 26, 211-252 (1964).

Box-Cox変換では全てのデータが正の値をとる必要があるが、その条件を緩和した一般化としてYeo-Johnson変換がある。

y = ((x + 1)**lmbda - 1) / lmbda, for x >= 0, lmbda != 0
      log(x + 1), for x >= 0, lmbda = 0
     -((-x + 1)**(2 - lmbda) - 1) / (2 - lmbda), for x < 0, lmbda != 2
    -log(-x + 1), for x < 0, lmbda = 2

scikit-learnだとPowerTransformを用いる。2つの変換は引数で使い分ける。規定値はYeo-Johnsonで、method='box-cox'とするとBox-Coxに切り替わる。使い方はscikit-learn共通で、クラス生成、fitでパラメータ最適化、transformで変換実行である。

from sklearn.preprocessing import PowerTransformer
pt = PowerTransformer()
data = df["pm2.5"].values.reshape(-1,1)
pt.fit(data)
df["normanized_pm"] = pt.transform(data)
df["normanized_pm"].hist();

PowerTransformerの引数standardizeの規定値はTrueであるので、平均0、標準偏差1になるように正規化されている。

データフレームを直接入れるのではなく、NumPyの配列をvaluesで取り出してから、さらにreshapeで型変換しなければいけない。初学者には難しいかもしれないので、scipyを使った場合も示す。stats.yeojohnsonもしくはstats.boxcoxにデータフレームの列(系列;シリーズ)を切り出して呼ぶだけで良い。Box-Coxだと0の値を許さないので、微小量を加えてから変換を行う。

from scipy import stats
data, lmbda = stats.boxcox(df["pm2.5"]+0.001)
df["boxcox"] = data
df["boxcox"].hist();

どちらの方法を用いても正規分布に近い形に変換できる。正規分布に従うかどうかは、probplotを描くとわかる。表題に示したのがそれだ。

import matplotlib.pyplot as plt
result = stats.probplot(data, dist=stats.norm,plot=plt)

この記事が気に入ったらサポートをしてみませんか?