Help us understand the problem. What is going on with this article?

[Rust] ベクトルが並んだ ndarray から各ベクトルのノルムをまとめて計算 [Python/numpy]

d 次元ベクトルが N 個並んだ ndarray x が与えられたとします. 例えば d=3 次元空間ならこんな感じ.

>>> x = np.random.normal(size=(8,3))
>>> x
array([[-0.35165099,  0.75272535,  0.2327542 ],
[ 0.1591356 , -0.42135054, -0.47746836],
[-0.65012207,  0.42038207,  1.46586837],
[ 1.89249086, -0.9594884 ,  1.49124505],
[-2.04557264, -1.00044391, -3.70700719],
[-0.53573469, -0.91952356,  0.02255211],
[ 1.19644064,  0.13071411, -1.80561646],
[-0.68594263, -0.53059182, -0.47844146]])
>>> 
>>> x.shape
(8, 3)

本記事ではこの N 個のデータに対して一斉に Euclid ノルムを計算するといった問題を扱います. 従って欲しいものは shape (N,) の ndarray になります. なお以下では x, y は同じ shape (N, d) の 2 つのベクトルを表します.

Python (numpy) 版

for i in range(N) みたいな感じで順番に処理するのはとても遅いのでやめましょう. そのための numpy です. 要点は np.sum または np.max するときに axis=1 と指定することです.

Euclid 距離

$$\left| x, y \right| = \left[ \sum_{i=0}^{d-1} (x_i - y_i)^2 \right]^\frac{1}{2}$$

Euclid 距離

euclid = np.sqrt(np.sum( (x-y)**2, axis=1)) 

Euclid ノルム

euclid = np.sqrt(np.sum( (x**2, axis=1)) 

マンハッタン距離

$$\left| x, y \right| = \sum_{i=0}^{d-1} \left| x_i - y_i \right|$$

マンハッタン距離

manhattan = np.sum(np.fabs(x-y), axis=1)) 

マンハッタンノルム

manhattan = np.sum(np.fabs(x), axis=1)) 

Chebyshev 距離

$$\left| x, y \right| = \max ( | x - y | )$$

Chebyshev 距離

chebyshev = np.amax(np.fabs(x - y), axis=1)

Chebyshev ノルム

chebyshev = np.amax(np.fabs(x), axis=1)

Minkowski 距離 (Lp ノルム)

$$\left| x, y \right| = \left[ \sum_{i=0}^{d-1} \left| x_i - y_i \right|^p \right]^\frac{1}{p}$$

Minkowski 距離

minkowski = (np.sum( np.fabs(x-y)**p, axis=1))**(1./p)

$L^p$ ノルム

minkowski = (np.sum( np.fabs(x)**p, axis=1))**(1./p)

Rust 版

D: usize をコンパイル時定数として x: Vec<[f64;D]> に対して同じことをしてみます. 書くのが面倒になってきたのでノルムだけ.

Euclid 距離

let euclid = x.iter()
    .map(|v| v.iter().map(|&u| u*u).sum::<f64>().sqrt())
    .collect::<Vec<_>>();

マンハッタン距離

let manhattan = x.iter()
    .map(|v| v.iter().map(|&u| u.abs()).sum::<f64>())
    .collect::<Vec<_>>();

Chebyshev 距離

let chebyshev = x.iter()
    .map(|v| v.iter().map(|&u| u.abs()).fold(0.0/0.0, f64::max))
    .collect::<Vec<_>>();

参考: Rustでf32やf64の配列の最大値を得る方法

Minkowski 距離

let minkowski = x.iter()
    .map(|v| v.iter().map(|&u| u.abs().powf(p)).sum::<f64>().powf(1./p))
    .collect::<Vec<_>>();

Rust - ndarray 版

let euclid = (&x*&x).sum_axis(Axis(1))
    .mapv_into(|v| v.sqrt());
let manhattan = &x.mapv_into(|v| v.abs())
    .sum_axis(Axis(1));
let chebyshev = &x.mapv_into(|v| v.abs())
    .fold_axis(Axis(1), 0.0 / 0.0, |&p, &u| { f64::max(p,u)});
let minkowski = &x.mapv_into(|v| v.abs().powf(p))
    .sum_axis(Axis(1))
    .mapv_into(|v| v.powf(1./p));

関連項目

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away