向量搜索之 k-means 算法(向量搜索框架)
ztj100 2025-06-15 20:40 20 浏览 0 评论
一直好奇向量数据库的索引是如何实现的,我们可以推断向量搜索的简单实现:把数据存入向量数据库时,会计算每个分段文档的向量(文档向量),然后把分段文档和文档向量同时存入向量数据库。从向量数据库中搜索文档时,会把待搜索问题转为向量(问题向量),然后计算问题向量与所有文档向量的距离,数据库会返回距离最短的一个或多个文档。
上面计算方式,返回的文档与问题最相关,但文档多时,耗费的计算资源同样多,有没有更好的方法?最容易想到的方法是把存入数据库中的文档向量先聚类为 K 个簇,从向量数据库中搜索文档时,先找到最相近的簇,再和簇内的每个文档向量比较找到与问题向量距离最短的一个或多个文档。这样需要的计算量就会少很多。
K-means算法简介
怎么把文档向量聚类为 K 个簇?可以使用K-means 算法。
- 初始化:随机选择K个数据点作为初始簇中心 。
- 分配样本:计算每个数据点到各簇中心的距离(通常用欧氏距离),将其分配到最近的簇 。
- 更新簇中心:重新计算每个簇的均值作为新中心 。
- 迭代:重复分配和更新步骤,直到中心不再变化或达到最大迭代次数
K-means 算法 python 实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
# 生成模拟数据,300个数据点,4个簇,每个簇的标准差为0.6,随机种子为0
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# K-means算法实现
def k_means(X, K, max_iters=100):
np.random.seed(42)
# 1. 随机初始化:从数据集中随机选择K个点作为初始簇中心
# np.random.choice 是随机抽样函数
# X.shape[0] 表示模拟数据个数;
# replace=False 表示无放回抽样,即每个数据只能被选中一次,不允许重复
centroids = X[np.random.choice(X.shape[0], K, replace=False)]
original_centroids = centroids.copy()
for iteration in range(max_iters):
# 2. 分配数据点:计算每个数据点到各个簇中心的距离
# X[:, np.newaxis] 表示为 X 添加一个新维度,使其形状变为 (n_samples, 1, n_features)。
# 目的是通过广播机制与 centroids 的维度 (K, n_features) 对齐,便于后续逐元素计算
# X[:, np.newaxis] - centroids 广播机制会将 X 扩展为 (n_samples, K, n_features),
# centroids 扩展为 (n_samples, K, n_features)(实际仅逻辑扩展,不占用额外内存)
distances = np.linalg.norm(X[:, np.newaxis] - centroids, axis=2)
# 3. 将每个数据点分配到最近的簇
labels = np.argmin(distances, axis=1)
# 4. 更新簇中心:重新计算每个簇的中心点,即簇内所有点的均值
# labels == k 生成布尔掩码(Boolean Mask),筛选出 labels 数组中标签等于 k 的所有样本索引
# X[labels == k] 根据布尔掩码从数据矩阵 X 中提取属于第 k 个簇的所有样本
# .mean(axis=0) 沿列方向(axis=0)计算均值,得到第 k 个簇的中心坐标
new_centroids = np.array([X[labels == k].mean(axis=0) for k in range(K)])
# 5. 迭代优化:检查簇中心是否变化
if np.all(centroids == new_centroids):
print(f"算法在第{iteration + 1}次迭代后收敛")
break
centroids = new_centroids
return original_centroids, centroids, labels
# 使用K-means算法进行聚类
K = 4 # 指定簇的数量
original_centroids, centroids, labels = k_means(X, K)
# 结果可视化
plt.figure(figsize=(8, 6))
# 每个簇的数据使用不同颜色展示
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis', edgecolor='k')
# 最终得到的簇心用红色展示
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=200, alpha=0.5, marker='X')
# 最初得到的簇心用蓝色展示
plt.scatter(origcentroids[:, 0], origcentroids[:, 1], c='blue', s=200, alpha=0.5, marker='X')
plt.title("K-means Clustering")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
# 保存到本地图片
plt.savefig("k_means_clustering.png")
上面实现中 distances = np.linalg.norm(X[:, np.newaxis] - centroids, axis=2) 等价于下面代码,计算每个数据点到各个簇中心的距离。
distances = np.zeros((X.shape[0], centroids.shape[0]))
for i in range(X.shape[0]):
for j in range(centroids.shape[0]):
distances[i, j] = np.sqrt(np.sum((X[i] - centroids[j])**2))
展示最终得到的簇中心与各个簇如下图所示
同时展示 K-means 算法最初随机选择的簇中心,使用蓝色叉展示如下,与最终的簇中心位置相隔较远,可见算法帮我们动态调整了簇中心。
向量数据库进行实际的向量搜索时,并不是简单通过 K-meams 算法创建索引,本文是从一个算法小白角度推导向量搜索如何实现,接下来会逐步介绍实际使用的向量搜索算法。
相关推荐
- Linux集群自动化监控系统Zabbix集群搭建到实战
-
自动化监控系统...
- systemd是什么如何使用_systemd/system
-
systemd是什么如何使用简介Systemd是一个在现代Linux发行版中广泛使用的系统和服务管理器。它负责启动系统并管理系统中运行的服务和进程。使用管理服务systemd可以用来启动、停止、...
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
-
Linux系统日常巡检脚本,巡检内容包含了,磁盘,...
- 7,MySQL管理员用户管理_mysql 管理员用户
-
一、首次设置密码1.初始化时设置(推荐)mysqld--initialize--user=mysql--datadir=/data/3306/data--basedir=/usr/local...
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
-
1.1数据库的核心概念在开始Python数据库编程之前,我们需要先理解几个核心概念。数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它就像一个电子化的文件柜,能让我们高效...
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
-
设置WGCloud开机自动启动服务init.d目录下新建脚本在/etc/rc.d/init.d新建启动脚本wgcloudstart.sh,内容如下...
- linux系统启动流程和服务管理,带你进去系统的世界
-
Linux启动流程Rhel6启动过程:开机自检bios-->MBR引导-->GRUB菜单-->加载内核-->init进程初始化Rhel7启动过程:开机自检BIOS-->M...
- CentOS7系统如何修改主机名_centos更改主机名称
-
请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言本文将讲解CentOS7系统如何修改主机名。...
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
-
在Linux服务器管理中,SSH(SecureShell)是远程操作的核心工具。以下是SSH终端操作的常用命令和技巧,涵盖连接、文件操作、系统管理等场景:一、SSH连接服务器1.基本连接...
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
-
为什么需要配置开机自启?想象一下:电商服务器重启后,MySQL和Nginx没自动启动,整个网站瘫痪!这就是为什么开机自启是Linux运维的必备技能。自启服务能确保核心程序在系统启动时自动运行,避免人工...
- Kubernetes 高可用(HA)集群部署指南
-
Kubernetes高可用(HA)集群部署指南本指南涵盖从概念理解、架构选择,到kubeadm高可用部署、生产优化、监控备份和运维的全流程,适用于希望搭建稳定、生产级Kubernetes集群...
- Linux项目开发,你必须了解Systemd服务!
-
1.Systemd简介...
- Linux系统systemd服务管理工具使用技巧
-
简介:在Linux系统里,systemd就像是所有进程的“源头”,它可是系统中PID值为1的进程哟。systemd其实是一堆工具的组合,它的作用可不止是启动操作系统这么简单,像后台服务...
- Linux下NetworkManager和network的和平共处
-
简介我们在使用CentoOS系统时偶尔会遇到配置都正确但network启动不了的问题,这问题经常是由NetworkManager引起的,关闭NetworkManage并取消开机启动network就能正...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
这一次,彻底搞懂Java并发包中的Atomic原子类
-
- 最近发表
-
- Linux集群自动化监控系统Zabbix集群搭建到实战
- systemd是什么如何使用_systemd/system
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
- 7,MySQL管理员用户管理_mysql 管理员用户
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
- linux系统启动流程和服务管理,带你进去系统的世界
- CentOS7系统如何修改主机名_centos更改主机名称
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)