やりたいこと
StandardScalerやMinMaxScalerで正規化処理をするときに、ある変数だけinverse_transformしたいときなどがあります。しかし、n変数まとめてfitしてしまっていると、特定の変数だけを逆変換するわけにはいきません。
非常にナイーブな実装ですが、n変数に対してn個のscaler()を用意して、リストに格納してぶん回します。
これだとあまりに記事にするほどの価値がないので、このリストに入ったScalerをsave/loadして使いまわす方法も紹介しておきます。
やったこと
変換対象の配列を用意します。ここでは3変数とします。
ar1 = np.arange(10)
ar2 = np.arange(10)+10
ar3 = np.arange(10)+20
arrs = np.block([[ar1], [ar2], [ar3]])
arrs = arrs.T
print(arrs)
# array([[ 0, 10, 20],
# [ 1, 11, 21],
# [ 2, 12, 22],
# [ 3, 13, 23],
# [ 4, 14, 24],
# [ 5, 15, 25],
# [ 6, 16, 26],
# [ 7, 17, 27],
# [ 8, 18, 28],
# [ 9, 19, 29]])
Scalerをn個(この例では3つ)用意します。
from sklearn.preprocessing import StandardScaler, MinMaxScaler
n = arrs.shape[1] # 変数の数, ここでは3
scaler_list = [StandardScaler() for i in range(n)]
for文でぶん回しながらfitします
for i in range(3):
scaler_list[i].fit(arrs[:,i].reshape(-1, 1))
各列についてtransform
していきます。
格納先として乱数の入った配列trans
を用意しておきます。
ポイントは、2つ。
1. 一次元の配列は(m, 1)次元にしないと受け付けてもらえないのでreshape(-1,1)しているところ
2. それを配列trans
に格納するときには逆に(m, )というshapeに戻しておかないといけないのでnp.ndarray.squeeze()
しているところ
trans= np.random.random(arrs.shape)
for i in range(n):
trans[:,i] = scaler_list[i].transform(arrs[:,i].reshape(-1, 1)).squeeze()
print(trans)
# array([[-1.5666989 , -1.5666989 , -1.5666989 ],
# [-1.21854359, -1.21854359, -1.21854359],
# [-0.87038828, -0.87038828, -0.87038828],
# [-0.52223297, -0.52223297, -0.52223297],
# [-0.17407766, -0.17407766, -0.17407766],
# [ 0.17407766, 0.17407766, 0.17407766],
# [ 0.52223297, 0.52223297, 0.52223297],
# [ 0.87038828, 0.87038828, 0.87038828],
# [ 1.21854359, 1.21854359, 1.21854359],
# [ 1.5666989 , 1.5666989 , 1.5666989 ]])
これをscaler.inverse_transform()
で戻します。さっきのコードをちょっとだけいじれば終わりですね。ここでも格納先にinv
という配列を用意しておきます。
inv = np.random.random(arrs.shape)
for i in range(n):
inv[:,i] = scaler_list[i].inverse_transform(res[:,i].reshape(-1, 1)).squeeze()
print(inv)
# array([[ 0, 10, 20],
# [ 1, 11, 21],
# [ 2, 12, 22],
# [ 3, 13, 23],
# [ 4, 14, 24],
# [ 5, 15, 25],
# [ 6, 16, 26],
# [ 7, 17, 27],
# [ 8, 18, 28],
# [ 9, 19, 29]])
無事に元の配列arrs
に戻っていることが確認できました。成功です。今回はすべてnumpy.ndarrayに閉じていますが、pandas.DataFrameに格納しておけば必要な時に特定のカラムだけ逆変換して戻すといったことができそうです。そのときはscaler_list
の何番目がどのカラムに対応しているのか、という対応表を辞書で持っておくと安全でしょうか。
Scalerでこういうことができるということは、sklearn.preprocessingに入っているメソッド(のオブジェクト)なら同じことができると思います。