Packages

A collection of useful mathematical functions in Elixir with a slant towards statistics, linear algebra and machine learning

Current section

Files

Jump to
numerix lib distance.ex
Raw

lib/distance.ex

defmodule Numerix.Distance do
@moduledoc """
Distance functions between two vectors.
"""
alias Numerix.{Common, Correlation, Math}
@doc """
The Pearson's distance between two vectors.
"""
@spec pearson([number], [number]) :: Common.maybe_float
def pearson(vector1, vector2) do
case Correlation.pearson(vector1, vector2) do
nil -> nil
correlation -> 1.0 - correlation
end
end
@doc """
The Minkowski distance between two vectors.
"""
@spec minkowski([number], [number], integer) :: Common.maybe_float
def minkowski(vector1, vector2, lambda \\ 3)
def minkowski([], _, _lambda), do: nil
def minkowski(_, [], _lambda), do: nil
def minkowski(vector1, vector2, lambda) do
vector1
|> Stream.zip(vector2)
|> Stream.map(fn {x, y} -> :math.pow(abs(x - y), lambda) end)
|> Enum.sum
|> Math.nth_root(lambda)
end
@doc """
The Euclidean distance between two vectors.
"""
@spec euclidean([number], [number]) :: Common.maybe_float
def euclidean(vector1, vector2) do
minkowski(vector1, vector2, 2)
end
@doc """
The Manhattan distance between two vectors.
"""
@spec manhattan([number], [number]) :: Common.maybe_float
def manhattan(vector1, vector2) do
minkowski(vector1, vector2, 1)
end
@doc """
The Jaccard distance (1 - Jaccard index) between two vectors.
"""
@spec jaccard([number], [number]) :: Common.maybe_float
def jaccard([], []), do: 0.0
def jaccard([], _), do: nil
def jaccard(_, []), do: nil
def jaccard(vector1, vector2) do
vector1
|> Stream.zip(vector2)
|> Enum.reduce({0, 0}, fn {x, y}, {intersection, union} ->
case {x, y} do
{x, y} when x == 0 or y == 0 ->
{intersection, union}
{x, y} when x == y ->
{intersection + 1, union + 1}
_ ->
{intersection, union + 1}
end
end)
|> to_jaccard_distance
end
defp to_jaccard_distance({intersection, union}) do
1 - (intersection / union)
end
end