scipy有关距离的函数在spatial库中

(1)计算同一个数据中两点的距离pdist,可以求各种类型的数据

欧氏距离:euclidean 公式为d=((x1-x2)^2+(y1-y2)^2)^(1/2)

#1 计算欧式距离
x=np.array([[1,2,10,3],[3,4,5,3],[5,6,6,3]])
distances = spatial.distance.pdist(x,'euclidean')
print(distances)# 这三个值分别是:点1和点2的距离,点1和点3的距离,点2和点3的距离

曼哈顿距离:d=|X1-X2|+|Y1-Y2|+|Z1-Z2|

#2计算曼哈顿距离
#d=|X1-X2|+|Y1-Y2|+|Z1-Z2|
distances = spatial.distance.pdist(x,'cityblock')
print(distances)# 这三个值分别是:点1和点2的距离,点1和点3的距离,点2和点3的距离

明氏距离:d(x,y) = (|x1-y1|^p + |x2-y2|^p + ... + |xn-yn|^p)^(1/p),当p=1时为曼哈顿距离,p=2时为欧式距离,p为无穷时是切比雪夫距离,参数p用于调整距离的度量方式,p越大越关注最大差值,p越小越关注所有差值的总和。

distances = spatial.distance.pdist(x,'minkowski',p=4)
print(distances)# 这三个值分别是:点1和点2的距离,点1和点3的距离,点2和点3的距离

余弦距离:是衡量两个向量之间相似度的方法,他计算两个向量的余弦值并取倒数,于两个n维向量x=(x1,x2,...,xn)和y=(y1,y2,...,yn),余弦距离定义为 #d(x,y) = 1 - cosθ = 1 - (x·y) / (||x||·||y||)

# 计算余弦距离
dist1 =spatial.distance.pdist([vector1, vector2], metric='cosine')
dist2 =spatial.distance.pdist([vector1, vector3], metric='cosine')
print(f"相同方向的向量距离: {dist1}")  # 输出接近0
print(f"相反方向的向量距离: {dist2}")  # 输出接近2

(2)计算两组数据之间的距离 cdist函数,用法与pdist相似

import numpy as np
from scipy.spatial.distance import cdist
# 定义两组点
XA = np.array([[1, 2], [3, 4]])  # 2个2维点
XB = np.array([[5, 6], [7, 8], [9, 10]])  # 3个2维点

#计算的是XA中的每个点与XB中的每个点的距离
# 计算欧氏距离
distances = cdist(XA, XB,metric='euclidean')
print("欧氏距离矩阵:")
print(distances)

# 使用不同的距离度量
# 曼哈顿距离
manhattan_dist = cdist(XA, XB, metric='cityblock')
print("\n曼哈顿距离矩阵:")
print(manhattan_dist)

# 余弦距离
cosine_dist = cdist(XA, XB, metric='cosine')
print("\n余弦距离矩阵:")
print(cosine_dist)

(3)squareform压缩,用于在压缩距离向量和方阵距离格式之间转换的函数,它主要用于处理 pdist 计算出的距离向量,把他转化为矩阵形式。

a=np.array([[1, 2], [3, 4],[5,6]])
dis=spatial.distance.pdist(a,metric='euclidean')
print('压缩的距离向量:',dis)
#[2.82842712 5.65685425 2.82842712]
# 将压缩的距离向量转换为方阵距离格式
dist_matrix = spatial.distance.squareform(dis)
print('方阵距离格式:',dist_matrix)
#[[0.         2.82842712 5.65685425]
# [2.82842712 0.         2.82842712]
# [5.65685425 2.82842712 0.        ]]
# 将方阵距离格式转换回压缩的距离向量
dis_back = spatial.distance.squareform(dist_matrix)
print('转换回的距离向量:',dis_back)

pdist直接输出的是[2.82842712 5.65685425 2.82842712],通过一次squaredorm转换为:

[[0.         2.82842712 5.65685425]
 [2.82842712 0.         2.82842712]
 [5.65685425 2.82842712 0.        ]]

再经过一次转换为:[2.82842712 5.65685425 2.82842712]

(4)近邻搜索 kdtree

import numpy as np
from scipy.spatial import KDTree
import matplotlib.pyplot as plt
#创建数据
np.random.seed(42)
points = np.random.rand(20, 2) * 10  # 生成20个随机点
#创建KDTree
tree=KDTree(points)
#设置查询点
query_point = np.array([5, 5])
#查询最近邻点(最近的一个点)
dist, index = tree.query(query_point, k=1)
nearest_point = points[index]#index是索引
print("查询点:",query_point)
print("最近点:",nearest_point)
print("最近距离:",dist)

主要用的函数是KDTree(样本点)创建KD树,dist, index = tree.query(query_point, k=1)用于查找与已知点最近的k个样本点,第一个参数是距离,第二个参数是查到的点在样本集合中的索引。

可通过以下可视化方法显示效果

def plot_kdtree(points, query_point, nearest_points):
    plt.figure(figsize=(8, 6))
    # 绘制所有点
    plt.scatter(points[:, 0], points[:, 1], c='blue', label='Data Points', alpha=0.6)
    # 绘制查询点
    plt.scatter(query_point[0], query_point[1], c='red', s=100, label='Query Point', marker='*')

    # 处理单个或多个最近邻点
    #原来是[]一个列表
    if len(nearest_points.shape) == 1:  # 如果只有一个最近邻点
        nearest_points = nearest_points.reshape(1, -1) #将其转换为二维的,1行两列
    # 绘制所有最近邻点
    plt.scatter(nearest_points[:, 0], nearest_points[:, 1],
                c='green', s=100, label='Nearest Neighbors', marker='o')

    # 连接查询点和所有最近邻点
    for i in range(len(nearest_points)):
        plt.plot([query_point[0], nearest_points[i, 0]],
                 [query_point[1], nearest_points[i, 1]],
                 'k--', alpha=0.5)

    # 添加距离标注
    for i, point in enumerate(nearest_points):
        dist = np.linalg.norm(point - query_point)
        mid_point = (query_point + point) / 2
        plt.annotate(f'd={dist:.2f}',
                     xy=mid_point,
                     xytext=(mid_point[0] + 0.1, mid_point[1] + 0.1),
                     fontsize=8)

    plt.xlabel('X')
    plt.ylabel('Y')
    plt.title('KDTree K-Nearest Neighbors Search')
    plt.legend()
    plt.grid(True)
    plt.show()
plot_kdtree(points, query_point, nest_points)

这里不只能查找最邻近点,还能查找k个邻近点,还能查找半径范围内的点

#最近的k个点
dist, index = tree.query(query_point, k=3)
nest_points=points[index]
plot_kdtree(points, query_point, nest_points)

# 3. 查找半径内的所有点
indices = tree.query_ball_point(query_point, 2)
print(indices)#返回的是点的位置列表
#显示
plot_kdtree(points, query_point, points[indices])

(5)凸包操作:用多边形将所有点都包含在内的最小多边形,点可以在多边形的边上

#计算凸包
np.random.seed(0)
points = np.random.rand(30, 2)  # 30个点,每个点有2个坐标

hull=spatial.ConvexHull(points)
#绘制凸包
plt.plot(points[:, 0], points[:, 1], 'o')
for simplex in hull.simplices:
    plt.plot(points[simplex, 0], points[simplex, 1], 'k-')
plt.title('Convex Hull')
plt.show()

(6)三角包分:太凸包内部用一个个小三角形分这个凸包,只有点和边能共用,其他不能重合。

#三角包分
# 1. 生成一组随机的二维点
np.random.seed(0)
points = np.random.rand(30, 2)  # 30个点,每个点有2个坐标

# 2. 计算 Delaunay 三角剖分
tri = spatial.Delaunay(points)
print(tri)

# 3. 可视化结果
plt.figure(figsize=(8, 8))

# 绘制所有点
plt.plot(points[:, 0], points[:, 1], 'o', label='Points')

# 绘制三角剖分
# tri.simplices 是构成每个三角形的三个顶点的索引
plt.triplot(points[:, 0], points[:, 1], tri.simplices, color='k', label='Triangulation')

# 为了美观,可以只显示一次图例
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())

plt.title('2D Delaunay Triangulation with SciPy')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()

更多推荐