新闻  |   论坛  |   博客  |   在线研讨会
KNN中不同距离度量对比和介绍(1)
数据派THU | 2023-05-22 21:28:21    阅读:220   发布文章

k近邻算法KNN是一种简单而强大的算法,可用于分类和回归任务。他实现简单,主要依赖不同的距离度量来判断向量间的区别,但是有很多距离度量可以使用,所以本文演示了KNN与三种不同距离度量(Euclidean、Minkowski和Manhattan)的使用。

图片


KNN算法概述


KNN是一种惰性、基于实例的算法。它的工作原理是将新样本的特征与数据集中现有样本的特征进行比较。然后算法选择最接近的k个样本,其中k是用户定义的参数。新样本的输出是基于“k”最近样本的多数类(用于分类)或平均值(用于回归)确定的。
有很多距离度量的算法,我们这里选取3个最常用度量的算法来进行演示:
1. 欧氏距离 Euclidean Distance

 def euclidean_distance(x1, x2):     return math.sqrt(np.sum((x1 - x2)**2))

euclidean_distance函数计算多维空间中两点(x1和x2)之间的欧氏距离,函数的工作原理如下:

  • 从x1元素中减去x2,得到对应坐标之间的差值。
  • 使用**2运算将差值平方。
  • 使用np.sum()对差的平方求和。
  • 使用math.sqrt()取总和的平方根。


欧几里得距离是欧几里得空间中两点之间的直线距离。通过计算欧几里得距离,可以识别给定样本的最近邻居,并根据邻居的多数类(用于分类)或平均值(用于回归)进行预测。在处理连续的实值特征时,使用欧几里得距离很有帮助,因为它提供了一种直观的相似性度量。
2. 曼哈顿距离 Manhattan Distance
两点坐标的绝对差值之和。

 def manhattan_distance(x1, x2):     return np.sum(np.abs(x1 - x2))


Manhattan _distance函数计算多维空间中两点(x1和x2)之间的曼哈顿距离,函数的工作原理如下:

  • 用np计算x1和x2对应坐标的绝对差值。Abs (x1 - x2)
  • 使用np.sum()对绝对差进行求和。


曼哈顿距离,也称为L1距离或出租车距离,是两点坐标的绝对差值之和。它代表了当运动被限制为网格状结构时,点之间的最短路径,类似于在城市街道上行驶的出租车。
在数据特征具有不同尺度的情况下,或者当问题域的网格状结构使其成为更合适的相似性度量时,使用曼哈顿距离可能会有所帮助。曼哈顿距离可以根据样本的特征来衡量样本之间的相似性或差异性。
与欧几里得距离相比,曼哈顿距离对异常值的敏感性较低,因为它没有对差异进行平方。这可以使它更适合于某些数据集或异常值的存在可能对模型的性能产生重大影响的问题。
3. 闵可夫斯基距离 Minkowski Distance
它是欧几里得距离和曼哈顿距离的一般化的表现形式,使用p进行参数化。当p=2时,它变成欧氏距离,当p=1时,它变成曼哈顿距离。



 def minkowski_distance(x1, x2, p):    return np.power(np.sum(np.power(np.abs(x1 - x2), p)), 1/p)

minkowski_distance函数计算多维空间中两点(x1和x2)之间的闵可夫斯基距离。
当你想要控制单个特征的差异对整体距离的影响时,使用闵可夫斯基距离会很有帮助。通过改变p值,可以调整距离度量对特征值或大或小差异的灵敏度,使其更适合特定的问题域或数据集。
闵可夫斯基距离可以根据样本的特征来衡量样本之间的相似性或不相似性。该算法通过计算适当p值的闵可夫斯基距离,识别出给定样本的最近邻居,并根据邻居的多数类(用于分类)或平均值(用于回归)进行预测。

KNN 算法的代码实现


因为KNN算法的原理很简单,所以我们这里直接使用Python实现,这样也可以对算法有一个更好的理解:


































def knn_euclidean_distance(X_train, y_train, X_test, k):     # List to store the predicted labels for the test set     y_pred = []
    # Iterate over each point in the test set     for i in range(len(X_test)):         distances = []         # Iterate over each point in the training set         for j in range(len(X_train)):             # Calculate the distance between the two points using the Euclidean distance metric             dist = euclidean_distance(X_test[i], X_train[j])             distances.append((dist, y_train[j]))
        # Sort the distances list by distance (ascending order)         distances.sort()
        # Get the k nearest neighbors         neighbors = distances[:k]
        # Count the votes for each class         counts = {}         for neighbor in neighbors:             label = neighbor[1]             if label in counts:                 counts[label] += 1             else:                 counts[label] = 1
        # Get the class with the most votes         max_count = max(counts, key=counts.get)         y_pred.append(max_count)
    return y_pred

这个' knn_euclidean_distance '函数对于解决分类问题很有用,因为它可以根据' k '个最近邻居中的大多数类进行预测。该函数使用欧几里得距离作为相似性度量,可以识别测试集中每个数据点的最近邻居,并相应地预测它们的标签。我们实现的代码提供了一种显式的方法来计算距离、选择邻居,并根据邻居的投票做出预测。
在使用曼哈顿距离时,KNN算法与欧氏距离保持一致,只需要将距离计算函数euclidean_distance修改为manhattan_distance。而闵可夫斯基距离则需要多加一个参数p,实现代码如下:



































def knn_minkowski_distance(X_train, y_train, X_test, k, p):     # List to store the predicted labels for the test set     y_pred = []
    # Iterate over each point in the test set     for i in range(len(X_test)):         distances = []         # Iterate over each point in the training set         for j in range(len(X_train)):             # Calculate the distance between the two points using the Minkowski distance metric             dist = minkowski_distance(X_test[i], X_train[j], p)             distances.append((dist, y_train[j]))
        # Sort the distances list by distance (ascending order)         distances.sort()
        # Get the k nearest neighbors         neighbors = distances[:k]
        # Count the votes for each class         counts = {}         for neighbor in neighbors:             label = neighbor[1]             if label in counts:                 counts[label] += 1             else:                 counts[label] = 1
        # Get the class with the most votes         max_count = max(counts, key=counts.get)         y_pred.append(max_count)
    return y_pred


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客