scipy在机器学习中的应用(4):空间距离
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()
更多推荐
所有评论(0)