Scholar.Metrics.Distance (Scholar v0.5.0)

Copy Markdown View Source

Distance metrics between multi-dimensional tensors. They all support distance calculations between any subset of axes.

Summary

Functions

Chebyshev or $L_{\infty}$ distance.

Cosine distance.

Standard euclidean distance ($L_{2}$ distance).

Hamming distance.

Hamming distance in weighted version.

Manhattan, Taxicab, or $L_{1}$ distance.

Minkowski distance.

Pairwise cosine distance. It is equivalent to Scholar.Metrics.Distance.pairwise_euclidean(x, x)

Pairwise cosine distance.

Pairwise euclidean distance. It is equivalent to Scholar.Metrics.Distance.pairwise_euclidean(x, x)

Pairwise euclidean distance.

Computes the pairwise Minkowski distance.

Pairwise squared euclidean distance. It is equivalent to Scholar.Metrics.Distance.pairwise_squared_euclidean(x, x)

Pairwise squared euclidean distance.

Squared euclidean distance.

Functions

chebyshev(x, y, opts \\ [])

Chebyshev or $L_{\infty}$ distance.

$$ D(x, y) = \max_i |x_i - y_i| $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([3, 2])
iex> Scholar.Metrics.Distance.chebyshev(x, y)
#Nx.Tensor<
  f32
  2.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2])
iex> Scholar.Metrics.Distance.chebyshev(x, y)
#Nx.Tensor<
  f32
  0.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.chebyshev(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 5], [3, 4, 3]])
iex> y = Nx.tensor([[8, 3, 1], [2, 5, 2]])
iex> Scholar.Metrics.Distance.chebyshev(x, y, axes: [1])
#Nx.Tensor<
  f32[2]
  [7.0, 1.0]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.chebyshev(x, y)
#Nx.Tensor<
  f32
  8.0
>

cosine(x, y, opts \\ [])

Cosine distance.

$$ D(u, v) = 1 - \frac{u \cdot v}{\|u\|_2 \|v\|_2} $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([5, 2])
iex> Scholar.Metrics.Distance.cosine(x, y)
#Nx.Tensor<
  f32
  0.25259072
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.cosine(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 3], [0, 0, 0], [5, 2, 4]])
iex> y = Nx.tensor([[1, 5, 2], [2, 4, 1], [0, 0, 0]])
iex> Scholar.Metrics.Distance.cosine(x, y, axes: [1])
#Nx.Tensor<
  f32[3]
  [0.17048502, 1.0, 1.0]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.cosine(x, y)
#Nx.Tensor<
  f32
  0.10575336
>

euclidean(x, y, opts \\ [])

Standard euclidean distance ($L_{2}$ distance).

$$ D(x, y) = \sqrt{\sum_i (x_i - y_i)^2} $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([3, 2])
iex> Scholar.Metrics.Distance.euclidean(x, y)
#Nx.Tensor<
  f32
  2.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2])
iex> Scholar.Metrics.Distance.euclidean(x, y)
#Nx.Tensor<
  f32
  0.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.euclidean(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 5], [3, 4, 3]])
iex> y = Nx.tensor([[8, 3, 1], [2, 5, 2]])
iex> Scholar.Metrics.Distance.euclidean(x, y, axes: [0])
#Nx.Tensor<
  f32[3]
  [7.071068, 1.4142135, 4.1231055]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.euclidean(x, y)
#Nx.Tensor<
  f32
  10.630146
>

hamming(x, y, opts \\ [])

Hamming distance.

$$ hamming(x, y) = \frac{\left \lvert x\_{i, j, ...} \neq y\_{i, j, ...}\right \rvert}{\left \lvert x\_{i, j, ...}\right \rvert} $$ where $i, j, ...$ are the aggregation axes

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 0, 0])
iex> y = Nx.tensor([0, 1, 0])
iex> Scholar.Metrics.Distance.hamming(x, y)
#Nx.Tensor<
  f32
  0.6666667
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.hamming(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 3], [0, 0, 0], [5, 2, 4]])
iex> y = Nx.tensor([[1, 5, 2], [2, 4, 1], [0, 0, 0]])
iex> Scholar.Metrics.Distance.hamming(x, y, axes: [1])
#Nx.Tensor<
  f32[3]
  [0.6666667, 1.0, 1.0]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.hamming(x, y)
#Nx.Tensor<
  f32
  1.0
>

hamming(x, y, w, opts)

Hamming distance in weighted version.

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 0, 0])
iex> y = Nx.tensor([0, 1, 0])
iex> weights = Nx.tensor([1, 0.5, 0.5])
iex> Scholar.Metrics.Distance.hamming(x, y, weights)
#Nx.Tensor<
  f32
  0.75
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> weights = Nx.tensor([1, 0.5, 0.5])
iex> Scholar.Metrics.Distance.hamming(x, y, weights, axes: [1])
#Nx.Tensor<
  f32[2]
  [1.0, 1.0]
>

manhattan(x, y, opts \\ [])

Manhattan, Taxicab, or $L_{1}$ distance.

$$ D(x, y) = \sum_i |x_i - y_i| $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([3, 2])
iex> Scholar.Metrics.Distance.manhattan(x, y)
#Nx.Tensor<
  f32
  2.0
>

iex> x = Nx.tensor([1.0, 2.0])
iex> y = Nx.tensor([1, 2])
iex> Scholar.Metrics.Distance.manhattan(x, y)
#Nx.Tensor<
  f32
  0.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.manhattan(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 5], [3, 4, 3]])
iex> y = Nx.tensor([[8, 3, 1], [2, 5, 2]])
iex> Scholar.Metrics.Distance.manhattan(x, y, axes: [0])
#Nx.Tensor<
  f32[3]
  [8.0, 2.0, 5.0]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.manhattan(x, y)
#Nx.Tensor<
  f32
  21.0
>

minkowski(x, y, opts \\ [])

Minkowski distance.

$$ D(x, y) = \left(\sum_i |x_i - y_i|^p\right)^{\frac{1}{p}} $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

  • :p - A positive parameter of Minkowski distance or :infinity (then Chebyshev metric computed). The default value is 2.0.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([5, 2])
iex> Scholar.Metrics.Distance.minkowski(x, y)
#Nx.Tensor<
  f32
  4.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2])
iex> Scholar.Metrics.Distance.minkowski(x, y)
#Nx.Tensor<
  f32
  0.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.minkowski(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 5], [3, 4, 3]])
iex> y = Nx.tensor([[8, 3, 1], [2, 5, 2]])
iex> Scholar.Metrics.Distance.minkowski(x, y, p: 2.5, axes: [0])
#Nx.Tensor<
  f32[3]
  [7.0215483, 1.319508, 4.049539]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.minkowski(x, y, p: 2.5)
#Nx.Tensor<
  f32
  9.621805
>

pairwise_cosine(x)

Pairwise cosine distance. It is equivalent to Scholar.Metrics.Distance.pairwise_euclidean(x, x)

Examples

iex> x = Nx.iota({6, 6})
iex> Scholar.Metrics.Distance.pairwise_cosine(x)
#Nx.Tensor<
  f32[6][6]
  [
    [0.0, 0.07934183, 0.11396426, 0.1302976, 0.13970923, 0.14581436],
    [0.07934183, 0.0, 0.003281951, 0.0066241026, 0.008954287, 0.010607183],
    [0.11396426, 0.003281951, 0.0, 5.822778e-4, 0.001398027, 0.002094984],
    [0.1302976, 0.0066241026, 5.822778e-4, 0.0, 1.7595291e-4, 4.6867132e-4],
    [0.13970923, 0.008954287, 0.001398027, 1.7595291e-4, 0.0, 7.0273876e-5],
    [0.14581436, 0.010607183, 0.002094984, 4.6867132e-4, 7.0273876e-5, 0.0]
  ]
>

pairwise_cosine(x, y)

Pairwise cosine distance.

Examples

iex> x = Nx.iota({6, 6})
iex> y = Nx.reverse(x)
iex> Scholar.Metrics.Distance.pairwise_cosine(x, y)
#Nx.Tensor<
  f32[6][6]
  [
    [0.20501536, 0.21226388, 0.2239579, 0.24592704, 0.3015697, 0.6363636],
    [0.031281054, 0.034291506, 0.039331675, 0.04936534, 0.07760531, 0.3015697],
    [0.014371514, 0.01644367, 0.02000463, 0.027365208, 0.04936534, 0.24592704],
    [0.009181917, 0.010854602, 0.013785064, 0.02000463, 0.039331675, 0.2239579],
    [0.006820023, 0.008272231, 0.010854602, 0.01644367, 0.034291506, 0.21226388],
    [0.005507469, 0.006820023, 0.009181917, 0.014371514, 0.031281054, 0.20501536]
  ]
>

pairwise_euclidean(x)

Pairwise euclidean distance. It is equivalent to Scholar.Metrics.Distance.pairwise_euclidean(x, x)

Examples

iex> x = Nx.iota({6, 6})
iex> Scholar.Metrics.Distance.pairwise_euclidean(x)
#Nx.Tensor<
  f32[6][6]
  [
    [0.0, 14.6969385, 29.393877, 44.090816, 58.787754, 73.484695],
    [14.6969385, 0.0, 14.6969385, 29.393877, 44.090816, 58.787754],
    [29.393877, 14.6969385, 0.0, 14.6969385, 29.393877, 44.090816],
    [44.090816, 29.393877, 14.6969385, 0.0, 14.6969385, 29.393877],
    [58.787754, 44.090816, 29.393877, 14.6969385, 0.0, 14.6969385],
    [73.484695, 58.787754, 44.090816, 29.393877, 14.6969385, 0.0]
  ]
>

pairwise_euclidean(x, y)

Pairwise euclidean distance.

Examples

iex> x = Nx.iota({2, 3})
iex> y = Nx.reverse(x)
iex> Scholar.Metrics.Distance.pairwise_euclidean(x, y)
#Nx.Tensor<
  f32[2][2]
  [
    [5.91608, 2.828427],
    [2.828427, 5.91608]
  ]
>

pairwise_minkowski(x, y, opts \\ [])

Computes the pairwise Minkowski distance.

Examples

iex> x = Nx.iota({2, 3})
iex> y = Nx.reverse(x)
iex> Scholar.Metrics.Distance.pairwise_minkowski(x, y)
#Nx.Tensor<
  f32[2][2]
  [
    [5.91608, 2.828427],
    [2.828427, 5.91608]
  ]
>

pairwise_squared_euclidean(x)

Pairwise squared euclidean distance. It is equivalent to Scholar.Metrics.Distance.pairwise_squared_euclidean(x, x)

Examples

iex> x = Nx.iota({6, 6})
iex> Scholar.Metrics.Distance.pairwise_squared_euclidean(x)
#Nx.Tensor<
  s32[6][6]
  [
    [0, 216, 864, 1944, 3456, 5400],
    [216, 0, 216, 864, 1944, 3456],
    [864, 216, 0, 216, 864, 1944],
    [1944, 864, 216, 0, 216, 864],
    [3456, 1944, 864, 216, 0, 216],
    [5400, 3456, 1944, 864, 216, 0]
  ]
>

pairwise_squared_euclidean(x, y)

Pairwise squared euclidean distance.

Examples

iex> x = Nx.iota({6, 6})
iex> y = Nx.reverse(x)
iex> Scholar.Metrics.Distance.pairwise_squared_euclidean(x, y)
#Nx.Tensor<
  s32[6][6]
  [
    [5470, 3526, 2014, 934, 286, 70],
    [3526, 2014, 934, 286, 70, 286],
    [2014, 934, 286, 70, 286, 934],
    [934, 286, 70, 286, 934, 2014],
    [286, 70, 286, 934, 2014, 3526],
    [70, 286, 934, 2014, 3526, 5470]
  ]
>

squared_euclidean(x, y, opts \\ [])

Squared euclidean distance.

$$ D(x, y) = \sum_i (x_i - y_i)^2 $$

Options

  • :axes - Axes to calculate the distance over. By default the distance is calculated between the whole tensors.

Examples

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([3, 2])
iex> Scholar.Metrics.Distance.squared_euclidean(x, y)
#Nx.Tensor<
  f32
  4.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1.0, 2.0])
iex> Scholar.Metrics.Distance.squared_euclidean(x, y)
#Nx.Tensor<
  f32
  0.0
>

iex> x = Nx.tensor([1, 2])
iex> y = Nx.tensor([1, 2, 3])
iex> Scholar.Metrics.Distance.squared_euclidean(x, y)
** (ArgumentError) tensors must be broadcast compatible, got tensors with shapes {2} and {3}

iex> x = Nx.tensor([[1, 2, 5], [3, 4, 3]])
iex> y = Nx.tensor([[8, 3, 1], [2, 5, 2]])
iex> Scholar.Metrics.Distance.squared_euclidean(x, y, axes: [0])
#Nx.Tensor<
  f32[3]
  [50.0, 2.0, 17.0]
>

iex> x = Nx.tensor([[6, 2, 9], [2, 5, 3]])
iex> y = Nx.tensor([[8, 3, 1]])
iex> Scholar.Metrics.Distance.squared_euclidean(x, y)
#Nx.Tensor<
  f32
  113.0
>