温故知新,数学之美,机器学习中十大常用距离计算数学公式
欧几里得距离
欧几里得距离公式(Euclidean Distance Formula
)是一种用来计算两个点之间直线距离的数学公式。它基于欧几里得几何学,即经典的平面和空间几何学。
欧几里得距离是两点之间最短的路径,它是在各维度上的差值的平方和的平方根。这是我们通常在日常生活中所理解的“直线距离”。
二维空间
对于平面上两个点A(\(x_1\),\(y_1\))和B(\(x_2\),\(y_2\))它们的欧几里得距离公式为
三维空间
对于空间中两个点A(\(x_1\),\(y_1\),\(z_1\))和B(\(x_2\),\(y_2\),\(z_2\)),欧几里得距离的公式为:
高维空间
对于\(n\)维空间里面两个点A(\(x_1\),\(x_2\),\(\dots\),\(x_n\))和B(\(y_1\),\(y_2\),\(\dots\),\(y_n\)),欧几里得距离的公式为:
适用场景
- 几何学:最基础的几何距离概念。
- 物理学:计算两物体之间的距离。
- 数据科学和机器学习:用于衡量数据点之间的相似性。
- 计算机视觉:用来计算图像中物体的空间位置。
代码实现
- 首先检查两个点的维度是否相同,如果不同则抛出异常。
- 通过遍历每个维度,计算各个坐标差的平方和。
- 最后,计算平方和的平方根得到两点之间的欧几里得距离。
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范数。它计算的是两点之间在各个维度上的绝对差之和,常用于城市网格中的距离计算(如在棋盘格状的道路中行走的距离)
二维空间
三维空间
适用场景
在网格结构中的路径规划(如自动驾驶、机器人等)
代码实现
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
)也称为棋盘距离,它表示在二维或三维网格中,从一个点移动到另一个点所需的最少步数(在国王走法中,国王每次可以在任意方向上走一格,包括对角线)
二维空间
三维空间
适用场景
棋盘游戏(如国际象棋中的国王移动)
代码实现
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\)值,可以表示不同的距离。
公式
常见特例:
当\(^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,表示两个向量越相似。它特别适用于高维空间中的文本或文档分析。
公式
其中\(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
)用于衡量两个等长的字符串(或二进制序列)之间不同字符的个数。它常用于纠错码或信息论中。
公式
其中\(\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
)是一种考虑数据分布的距离,它用于衡量点与分布中心之间的距离,考虑了数据的协方差结构。它在高维空间中比欧几里得距离更加精确,尤其是在多变量数据中。
公式
其中:
- \(x\)是样本点,
- \(\mu\)是数据的均值向量,
- \(S\)是协方差矩阵。
适用场景
多变量统计分析、异常检测
代码实现
马氏距离相对复杂,因为它需要计算协方差矩阵的逆。以下是实现的思路:
- 计算数据集的均值向量。
- 计算协方差矩阵并取其逆矩阵。
- 根据马氏距离公式计算距离。
由于协方差矩阵及其逆矩阵的计算在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
)用于衡量两个集合的相似性或相异性,定义为交集与并集的差异程度。
公式
适用场景
集合相似度分析(如推荐系统、信息检索)
代码实现
杰卡德距离用于集合,你可以使用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
)是用于比较两个时间序列的距离度量,特别是当两个序列的长度不同时,它通过"对齐"时间序列来最小化距离。
公式
其中\(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
)用于度量两个概率分布的相似度,通常用于图像分析和模式识别。
公式
适用场景
模式识别、图像处理
代码实现
布哈曼距离常用于概率分布的比较,以下是实现两个概率分布的距离度量:
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);
}