Pythonを使ってベクトルをL2正規化(normalization)する方法が色々あるのでまとめます。
※L2正則化(regularization)= Ridgeではありません。
L2正規化とは
ベクトル$x = (x_1,x_2,...,x_n)$に対応するL2正規化は以下のように定式化されます。
x_{L2\,norm} = \frac{x}{||x||_2}
ここで、$||x||_2$は、以下の式で求まる$x$のL2ノルムです。
||x||_2 = \sqrt{(\sum_i x_i^2)} = \sqrt{x_1^2 + x_2^2 + ... + x_n^2}
ベクトル$x$をL2正規化すると、長さが1のベクトルになります。
2次元空間で考えた場合、この操作は任意の2次元ベクトルを原点を中心とした半径1の円上へのベクトルに変換していると考えることができます。
3次元の場合は原点を中心とした半径1の球面上へのベクトルに変換します。
4次元以上はイメージが難しいですが、同じように原点を中心とする半径1の超球面上へのベクトルに変換すると考えれば良いと思います。
pythonでの計算方法
上記のようなL2正規化ですが、pythonでは色々と計算方法があるようなので以下にまとめます。
他にもあると思うので、見つけたら追記します。
直接計算する
定義に従って計算すれば良いです。
# 定義に従って計算
x = np.array([1,2,3,4,5])
x_l2_norm = sum(x**2)**0.5
x_l2_normalized = x / x_l2_norm
# 検算
np.linalg.norm(x_l2_normalized,ord=2)
# 1.0
numpy.linalg.norm
numpy.linalg.norm
を使って計算することも可能です。
こいつはベクトルx
のL2ノルムを返すので、L2ノルムを求めた後にx
を割ってあげる必要があります。
# numpy.linalg.normを使う
x = np.array([1,2,3,4,5])
x_l2_norm = np.linalg.norm(x,ord=2)
x_l2_normalized = x / x_l2_norm
# 検算
np.linalg.norm(x_l2_normalized,ord=2)
# 1.0
sklearn.preprocessing.normalize
みんな大好きscikit-learnでも計算可能です。
2次元の場合はaxis
で軸の指定します。axis=0
で列方向、axis=1
(デフォルト)で行方向に正規化を行います。
# sklearn.preprocessing.normalizeを使う
from sklearn.preprocessing import normalize
x = [[1,2,3,4,5],]
x_l2_normalized = normalize(x,norm='l2')
x_2d = [[1,2,3,4,5],[6,7,8,9,10]]
x_2d_l2_normalized = normalize(x_2d,norm='l2')
x_2d_l2_normalized2 = normalize(x_2d,norm='l2',axis=0)
# 検算
print(np.linalg.norm(x_l2_normalized,ord=2))
print(np.linalg.norm(x_2d_l2_normalized[0,:],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[1,:],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[:,0],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[:,1],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[:,2],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[:,3],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[:,4],ord=2))
# 1.0
# 1.0
# 1.0
# 1.0
# 1.0
# 1.0
# 1.0
# 0.9999999999999999
keras.backend.l2_normalize
kerasにもあります。backendはtensorflowです。
(tf.keras.backend.l2_normalize
というものもありました)
# keras.backend.l2_normalizeを使う
from keras import backend as K
x = [1.,2.,3.,4.,5.]
x_2d = [[1.,2.,3.,4.,5.],[6.,7.,8.,9.,10.]]
x_l2_normalized = K.l2_normalize(x,axis=0)
x_2d_l2_normalized = K.l2_normalize(x_2d,axis=0)
x_2d_l2_normalized2 = K.l2_normalize(x_2d,axis=1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
x_l2_normalized = sess.run(x_l2_normalized)
x_2d_l2_normalized = sess.run(x_2d_l2_normalized)
x_2d_l2_normalized2 = sess.run(x_2d_l2_normalized2)
# 検算
print(np.linalg.norm(x_l2_normalized,ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,0],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,1],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,2],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,3],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,4],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[0,:],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[1,:],ord=2))
#1.0000001
#1.0
#0.99999994
#1.0
#0.99999994
#1.0
#1.0000001
#1.0
tf.math.l2_normalize
※tensorflow 1.11まではtf.nn.l2_normalize
として提供されていたようです。
import tensorflow as tf
x = tf.Variable([1,2,3,4,5], dtype=tf.float32)
x_2d = tf.Variable([[1,2,3,4,5],[6,7,8,9,10]], dtype=tf.float32)
x_l2_normalized = tf.math.l2_normalize(x,axis=0)
x_2d_l2_normalized = tf.math.l2_normalize(x_2d,axis=0)
x_2d_l2_normalized2 = tf.math.l2_normalize(x_2d,axis=1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
x_l2_normalized = sess.run(x_l2_normalized)
x_2d_l2_normalized = sess.run(x_2d_l2_normalized)
x_2d_l2_normalized2 = sess.run(x_2d_l2_normalized2)
# 検算
print(np.linalg.norm(x_l2_normalized,ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,0],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,1],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,2],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,3],ord=2))
print(np.linalg.norm(x_2d_l2_normalized[:,4],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[0,:],ord=2))
print(np.linalg.norm(x_2d_l2_normalized2[1,:],ord=2))
#1.0000001
#1.0
#0.99999994
#1.0
#0.99999994
#1.0
#1.0000001
#1.0
おわりに
いろいろありますねー。用途に合わせて使い分けていきましょー(?)
(pythonは変数のスコープどうなってんすか。。。)