sklearn DBSCAN内存相关问题

本文探讨了在使用sklearn.cluster.DBSCAN进行聚类时遇到的内存问题,特别是随着数据规模扩大导致的内存占用过高。文章分析了内存过高的原因,并提供了四个优化方案:预计算稀疏邻域、删除重复点、自定义DBSCAN算法和升级sklearn版本。通过这些方案,可以在一定程度上降低内存使用,提高大规模数据集的聚类效率。
摘要由CSDN通过智能技术生成

写在前面

其实在大规模数据集下(数据在百万级以上且特征在百维以上)进行聚类,最好是使用分布式进行计算,本人也没有太多经验,仅此稍稍提下。

对于中等规模数据集(数据在十万级左右且特征在百维以上),优先推荐的还是使用sklearn的MiniBatchKMeans,但是有时候类别个数参数调整远比最大距离参数调整来的困难时,自然而然会想到使用基于密度聚类的DBSCAN。

但是在sklearn.cluster.DBSCAN实际的使用过程中,有时会面临因为数据集规模扩大,重新聚类时占用内存过高,导致memory error,从而使程序被kill。本文就是说一说一些可选取的内存优化方案。

PS:仅针对内存相关问题,速度上的比如多进程相关内容不涵盖。

内存占用过高原因

其实这个问题,sklearn官方文档中也给出了对应说明。

This implementation bulk-computes all neighborhood queries, which increases the memory complexity to O(n.d) where d is the average number of neighbors, while original DBSCAN had memory complexity O(n). It may attract a higher memory complexity when querying these nearest neighborhoods, depending on the algorithm.
谷歌翻译:该实现对所有邻居查询进行批量计算,从而将内存复杂度增加到O(n*d),其中d是邻居的平均数量,而原始DBSCAN的内存复杂度为O(n)。根据选取算法的不同,在查询这些最近的邻域时,它可能会吸引更高的内存复杂度。

大概意思是,为了支持批量计算,在算法初期,就需要构建各点间的距离矩阵,此时会引入额外内存。注意这里的文档应该是在0.16版本之后进行优化的,距离矩阵使用稀疏矩阵表示,之前版本的内存复杂度应该是O(n^2)。(对于具体什么版本优化存疑,我只是从gayhub项目下issue中进行推断的,并非查阅提交记录。)

优化方案

方案一

One way to avoid the query complexity is to pre-compute sparse neighborhoods in chunks using NearestNeighbors.radius_neighbors_graph with mode=‘distance’, then using metric=‘precomputed’ here.
谷歌翻译:避免查询复杂性的一种方法是使用NearestNeighbors.radius_neighbors_graph方法并且设置参数mode='distance’预先计算的稀疏矩阵,然后传入并使用参数metric=‘precomputed’。

代码示例(使用余弦距离):

def dbscan(train_data):
    """
    聚类
    :param train_data: 训练数据np.array[[]]
    :return:
    """
    neigh = NearestNeighbors(radius=0.5, metric='cosine').fit(X=train_data)
    train_x = neigh.radius_neighbors_graph(mode='distance')
    cluster = DBSCAN(eps=0.5, min_samples=3, metric='precomputed', n_jobs=1).fit_predict(X=train_x)

个人理解上,这样做最大的好处可以节约原输入矩阵所需内存,尤其是在n_jobs>=2或者n_jobs=-1情况下可以直观感受到内存消耗的减少。

PS:其实也可以直接传入n*n的距离矩阵进行计算,同样metric=‘precomputed’。

方案二

Another way to reduce memory and computation time is to remove (near-)duplicate points and use sample_weight instead.
谷歌翻译:另一种减少内存和计算时间的方法是删除(接近)重复的点并使用sample_weight取代,有几个点就把权重设为几,默认为1。

代码示例:

train_x = np.array([[1, 
DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的空间聚类算法,该算法将具有足夜高密度的区域划分为簇,并能在带有噪声的空间数据库中发现任意形状的聚类。`sklearn`库中的`sklearn.cluster.DBSCAN`类实现了这种算法。 DBSCAN算法的主要思想是: 1. 根据给定的邻域半径(eps)和邻域内的最小点数(min_samples),定义核心对象(核心点、边界点和噪声点)。 2. 对于每个核心对象,如果它未被访问过,则创建一个新簇。 3. 搜索核心对象的邻域内所有可达的对象,将这些对象合并到当前簇中。 4. 重复步骤3,直到所有的点都被访问过。 5. 所有点要么被分配到一个簇中,要么被认为是噪声。 在`sklearn`中使用`DBSCAN`聚类的基本步骤如下: 1. 导入`DBSCAN`类。 2. 创建`DBSCAN`对象,并设置相应的参数。 3. 使用`fit`方法对数据进行聚类。 4. 查看聚类结果。 下面是一个简单的代码示例: ```python from sklearn.cluster import DBSCAN from sklearn.datasets import make_blobs # 创建测试数据 X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0) # 创建DBSCAN对象 dbscan = DBSCAN(eps=0.3, min_samples=10) # 拟合模型 dbscan.fit(X) # 查看聚类标签 labels = dbscan.labels_ # 进一步处理聚类结果,例如可视化等 ``` 需要注意的是,DBSCAN算法的性能高度依赖于参数`eps`和`min_samples`的选择。参数`eps`定义了点之间的距离邻域半径,而`min_samples`定义了一个区域成为核心对象所需的核心点数(包括核心点本身)。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值