温故知新,数学之美,机器学习中十大常用距离计算数学公式

image

欧几里得距离

欧几里得距离公式(Euclidean Distance Formula)是一种用来计算两个点之间直线距离的数学公式。它基于欧几里得几何学,即经典的平面和空间几何学。

欧几里得距离是两点之间最短的路径,它是在各维度上的差值的平方和的平方根。这是我们通常在日常生活中所理解的“直线距离”。

二维空间

对于平面上两个点A(\(x_1\),\(y_1\))和B(\(x_2\),\(y_2\))它们的欧几里得距离公式为

\[d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} \]

三维空间

对于空间中两个点A(\(x_1\),\(y_1\),\(z_1\))和B(\(x_2\),\(y_2\),\(z_2\)),欧几里得距离的公式为:

\[d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2} \]

高维空间

对于\(n\)维空间里面两个点A(\(x_1\),\(x_2\),\(\dots\),\(x_n\))和B(\(y_1\),\(y_2\),\(\dots\),\(y_n\)),欧几里得距离的公式为:

\[d = \sqrt{(x_1 - y_1)^2 + (x_2 - y_2)^2 + \dots + (x_n - y_n)^2} \]

适用场景

  • 几何学:最基础的几何距离概念。
  • 物理学:计算两物体之间的距离。
  • 数据科学和机器学习:用于衡量数据点之间的相似性。
  • 计算机视觉:用来计算图像中物体的空间位置。

代码实现

  1. 首先检查两个点的维度是否相同,如果不同则抛出异常。
  2. 通过遍历每个维度,计算各个坐标差的平方和。
  3. 最后,计算平方和的平方根得到两点之间的欧几里得距离。
public static double EuclideanDistance(double[] point1, double[] point2)
{
    if (point1.Length != point2.Length)
        throw new ArgumentException("Both points must have the same dimensions");

    double sum = 0;

    for (int i = 0; i < point1.Length; i++)
    {
        sum += Math.Pow(point2[i] - point1[i], 2);
    }

    return Math.Sqrt(sum);
}

对于二维点来说

double[] pointA = { 3, 4 };
double[] pointB = { 7, 1 };
double distance2D = EuclideanDistance(pointA, pointB);
Console.WriteLine($"二维空间中的距离: {distance2D}");

对于三位点来说

double[] pointA = { 1, 2, 3 };
double[] pointB = { 4, 5, 6 };
double distance3D = EuclideanDistance(pointA, pointB);
Console.WriteLine($"三维空间中的距离: {distance3D}");

曼哈顿距离

曼哈顿距离(Manhattan Distance)也称为城市街区距离L1范数。它计算的是两点之间在各个维度上的绝对差之和,常用于城市网格中的距离计算(如在棋盘格状的道路中行走的距离)

二维空间

\[d = |x_2 - x_1| + |y_2 - y_1| \]

三维空间

\[d = |x_2 - x_1| + |y_2 - y_1| + |z_2 - z_1| \]

适用场景

在网格结构中的路径规划(如自动驾驶、机器人等)

代码实现

public static double ManhattanDistance(double[] point1, double[] point2)
{
    double distance = 0;
    for (int i = 0; i < point1.Length; i++)
    {
        distance += Math.Abs(point2[i] - point1[i]);
    }
    return distance;
}

切比雪夫距离

切比雪夫距离(Chebyshev Distance)也称为棋盘距离,它表示在二维或三维网格中,从一个点移动到另一个点所需的最少步数(在国王走法中,国王每次可以在任意方向上走一格,包括对角线)

二维空间

\[d = \max(|x_2 - x_1|, |y_2 - y_1|) \]

三维空间

\[d = \max(|x_2 - x_1|, |y_2 - y_1|, |z_2 - z_1|) \]

适用场景

棋盘游戏(如国际象棋中的国王移动)

代码实现

public static double ChebyshevDistance(double[] point1, double[] point2)
{
    double maxDiff = 0;
    for (int i = 0; i < point1.Length; i++)
    {
        maxDiff = Math.Max(maxDiff, Math.Abs(point2[i] - point1[i]));
    }
    return maxDiff;
}

闵可夫斯基距离

闵可夫斯基距离(Minkowski Distance)是欧几里得距离和曼哈顿距离的广义形式,适用于任意维空间。它引入了一个可调参数\(^p\),通过不同的\(^p\)值,可以表示不同的距离。

公式

\[d = \left( \sum_{i=1}^n |x_i - y_i|^p \right)^{\frac{1}{p}} \]

常见特例:

\(^p\)=1时,闵可夫斯基距离为曼哈顿距离。
\(^p\)=2时,闵可夫斯基距离为欧几里得距离。
\(^p\)=\(\infty\)时,闵可夫斯基距离为切比雪夫距离。

适用场景

灵活调整距离测量标准的场景,如某些机器学习算法。

代码实现

public static double MinkowskiDistance(double[] point1, double[] point2, double p)
{
    double sum = 0;
    for (int i = 0; i < point1.Length; i++)
    {
        sum += Math.Pow(Math.Abs(point2[i] - point1[i]), p);
    }
    return Math.Pow(sum, 1 / p);
}

可以通过改变参数p来计算不同的距离,如p=1代表曼哈顿距离,p=2代表欧几里得距离。

余弦相似度

余弦相似度(Cosine Similarity)并不是真正意义上的"距离",而是度量两个向量之间的夹角。余弦值越接近1,表示两个向量越相似。它特别适用于高维空间中的文本或文档分析。

公式

\[\text{Cosine Similarity} = \frac{A \cdot B}{\|A\| \|B\|} \]

其中\(A \cdot B\)代表两个向量的点积,\(\|A\|\)\(\|B\|\)分别为两个向量的模。

适用场景

文本分析、自然语言处理(如衡量两个文本的相似度)

代码实现

public static double CosineSimilarity(double[] vectorA, double[] vectorB)
{
    double dotProduct = 0, magnitudeA = 0, magnitudeB = 0;
    for (int i = 0; i < vectorA.Length; i++)
    {
        dotProduct += vectorA[i] * vectorB[i];
        magnitudeA += Math.Pow(vectorA[i], 2);
        magnitudeB += Math.Pow(vectorB[i], 2);
    }
    return dotProduct / (Math.Sqrt(magnitudeA) * Math.Sqrt(magnitudeB));
}

汉明距离

汉明距离(Hamming Distance)用于衡量两个等长的字符串(或二进制序列)之间不同字符的个数。它常用于纠错码或信息论中。

公式

\[d = \sum_{i=1}^n \delta(x_i, y_i) \]

其中\(\delta(x_i, y_i)\)\(x_i\) \(\neq\) \(y_i\)时取1,当\(x_i\) = \(y_i\)时取0。

适用场景

编码理论、网络通信(如比特串之间的错误检测)

代码实现

public static int HammingDistance(string str1, string str2)
{
    if (str1.Length != str2.Length)
        throw new ArgumentException("Strings must be of equal length");

    int distance = 0;
    for (int i = 0; i < str1.Length; i++)
    {
        if (str1[i] != str2[i])
        {
            distance++;
        }
    }
    return distance;
}

汉明距离通常用于比较等长的二进制序列或字符串

马氏距离

马氏距离(Hamming Distance)是一种考虑数据分布的距离,它用于衡量点与分布中心之间的距离,考虑了数据的协方差结构。它在高维空间中比欧几里得距离更加精确,尤其是在多变量数据中。

公式

\[d = \sqrt{(x - \mu)^T S^{-1} (x - \mu)} \]

其中:

  • \(x\)是样本点,
  • \(\mu\)是数据的均值向量,
  • \(S\)是协方差矩阵。

适用场景

多变量统计分析、异常检测

代码实现

马氏距离相对复杂,因为它需要计算协方差矩阵的逆。以下是实现的思路:

  1. 计算数据集的均值向量。
  2. 计算协方差矩阵并取其逆矩阵。
  3. 根据马氏距离公式计算距离。

由于协方差矩阵及其逆矩阵的计算在C#中需要线性代数库,如MathNet.Numerics,具体实现可以通过该库进行。

这里是一个简化版本,假设你已经计算了协方差矩阵的逆矩阵\(S^{-1}\)

public static double MahalanobisDistance(double[] point, double[] mean, double[,] invCovMatrix)
{
    double[] diff = new double[point.Length];
    for (int i = 0; i < point.Length; i++)
    {
        diff[i] = point[i] - mean[i];
    }

    double[] temp = new double[point.Length];
    for (int i = 0; i < invCovMatrix.GetLength(0); i++)
    {
        for (int j = 0; j < invCovMatrix.GetLength(1); j++)
        {
            temp[i] += diff[j] * invCovMatrix[j, i];
        }
    }

    double distance = 0;
    for (int i = 0; i < diff.Length; i++)
    {
        distance += temp[i] * diff[i];
    }

    return Math.Sqrt(distance);
}

杰卡德距离

杰卡德距离(Jaccard Distance)用于衡量两个集合的相似性或相异性,定义为交集与并集的差异程度。

公式

\[d = 1 - \frac{|A \cap B|}{|A \cup B|} \]

适用场景

集合相似度分析(如推荐系统、信息检索)

代码实现

杰卡德距离用于集合,你可以使用HashSet来计算交集和并集

public static double JaccardDistance<T>(HashSet<T> set1, HashSet<T> set2)
{
    var intersection = new HashSet<T>(set1);
    intersection.IntersectWith(set2);

    var union = new HashSet<T>(set1);
    union.UnionWith(set2);

    return 1.0 - (double)intersection.Count / union.Count;
}

动态时间规整距离

动态时间规整距离(Dynamic Time Warping, DTW)是用于比较两个时间序列的距离度量,特别是当两个序列的长度不同时,它通过"对齐"时间序列来最小化距离。

公式

\[d = \text{DTW}(A, B) \]

其中\(A\)\(B\)是待比较的时间序列

适用场景

语音识别、时间序列分析

代码实现

DTW的实现需要动态规划算法,计算时间序列的最小对齐路径。下面是一个简单的实现:

public static double DynamicTimeWarping(double[] sequence1, double[] sequence2)
{
    int n = sequence1.Length;
    int m = sequence2.Length;
    double[,] dtw = new double[n + 1, m + 1];

    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= m; j++)
            dtw[i, j] = double.PositiveInfinity;

    dtw[0, 0] = 0;

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            double cost = Math.Abs(sequence1[i - 1] - sequence2[j - 1]);
            dtw[i, j] = cost + Math.Min(Math.Min(dtw[i - 1, j], dtw[i, j - 1]), dtw[i - 1, j - 1]);
        }
    }

    return dtw[n, m];
}

布哈曼距离

布哈曼距离(Bhattacharyya Distance)用于度量两个概率分布的相似度,通常用于图像分析和模式识别。

公式

\[d = -\ln \left( \sum \sqrt{p(x)q(x)} \right) \]

适用场景

模式识别、图像处理

代码实现

布哈曼距离常用于概率分布的比较,以下是实现两个概率分布的距离度量:

public static double BhattacharyyaDistance(double[] p, double[] q)
{
    double sum = 0;
    for (int i = 0; i < p.Length; i++)
    {
        sum += Math.Sqrt(p[i] * q[i]);
    }
    return -Math.Log(sum);
}

参考

posted @ 2024-10-19 21:18  TaylorShi  阅读(61)  评论(0编辑  收藏  举报