我想根据数字与邻居的比较数字将其分组在一个列表中,但是我想连续地进行此操作,并尽可能通过聚类。为了澄清,让我给你一个例子:
假设您有列表
lst = [10, 11.1, 30.4, 30.0, 32.9, 4.5, 7.2]
然后,如果我们有3个群组,则显而易见如何进行聚类。运行sklearn的k-means算法(参见代码)可以确认这一点。但是,当列表中的数字不是那么“方便”时,我就会遇到麻烦。假设您有列表:
lst = [10, 11.1, 30.4, 30.0, 32.9, 6.2, 31.2, 29.8, 12.3, 10.5]
我的问题现在有两个方面:
我想要某种“保留顺序的线性”聚类,它考虑了数据的顺序。对于上面的列表,聚类算法应为我提供所需的格式
lst = [0,0,1,1,1,1,1,1,2,2]
如果您查看上面的输出,还看到我希望值6.2在第二个集群中集群,即,我希望集群算法将其视为异常值,而不是一个全新的集群。
编辑为澄清起见,我希望能够指定线性聚类过程中的聚类数量,即聚类的“最终总数”。
代码:
import numpy as np
from sklearn.cluster import KMeans
lst = [10, 11.1, 30.4, 30.0, 32.9, 4.5, 7.2]
km = KMeans(3,).fit(np.array(lst).reshape(-1,1))
print(km.labels_)
# [0 0 1 1 1 2 2]: OK output
lst = [10, 11.1, 30.4, 30.0, 32.9, 6.2, 31.2, 29.8, 12.3, 10.5]
km = KMeans(3,).fit(np.array(lst).reshape(-1,1))
print(km.labels_)
# [0 0 1 1 1 2 1 1 0 0]. Desired output: [0 0 1 1 1 1 1 1 2 2]
答案 0 :(得分:1)
如上所述,我认为获得理想结果的一种直接方法是仅使用常规的K均值聚类,然后根据需要修改生成的输出。
说明:该想法是获取K-means输出,然后对其进行迭代:跟踪上一个项目的集群组和当前集群组,并控制根据条件创建的新集群。代码中的解释。
import numpy as np
from sklearn.cluster import KMeans
lst = [10, 11.1, 30.4, 30.0, 32.9, 4.5, 7.2]
km = KMeans(3,).fit(np.array(lst).reshape(-1,1))
print(km.labels_)
# [0 0 1 1 1 2 2]: OK output
lst = [10, 11.1, 30.4, 30.0, 32.9, 6.2, 31.2, 29.8, 12.3, 10.5]
km = KMeans(3,).fit(np.array(lst).reshape(-1,1))
print(km.labels_)
# [0 0 1 1 1 2 1 1 0 0]. Desired output: [0 0 1 1 1 1 1 1 2 2]
def linear_order_clustering(km_labels, outlier_tolerance = 1):
'''Expects clustering outputs as an array/list'''
prev_label = km_labels[0] #keeps track of last seen item's real cluster
cluster = 0 #like a counter for our new linear clustering outputs
result = [cluster] #initialize first entry
for i, label in enumerate(km_labels[1:]):
if prev_label == label:
#just written for clarity of control flow,
#do nothing special here
pass
else: #current cluster label did not match previous label
#check if previous cluster label reappears
#on the right of current cluster label position
#(aka current non-matching cluster is sandwiched
#within a reasonable tolerance)
if (outlier_tolerance and
prev_label in km_labels[i + 1: i + 2 + outlier_tolerance]): label = prev_label #if so, overwrite current label
else:
cluster += 1 #its genuinely a new cluster
result.append(cluster)
prev_label = label
return result
请注意,我只测试了1个异常值的容差,并且不能保证它在所有情况下都可以开箱即用。但是,这应该可以帮助您入门。
输出:
print(km.labels_)
result = linear_order_clustering(km.labels_)
print(result)
[1 1 0 0 0 2 0 0 1 1]
[0, 0, 1, 1, 1, 1, 1, 1, 2, 2]
答案 1 :(得分:0)
我将通过几步来解决这个问题。首先,我将具有第一个函数/方法来进行分析以确定每个组的聚类中心,并返回这些中心的数组。然后,我会将这些中心与列表一起放入另一个函数/方法中,以组装列表中每个数字的群集ID的列表。然后,我将返回排序后的列表。
答案 2 :(得分:0)
定义一个阈值。
如果x [i]和x [i-1]的值相差太大,请开始一个新的 segment 。
要获得更好的结果,请查看KDE和CUSUM方法。
不要使用群集。它有不同的目标。
答案 3 :(得分:0)
我遇到了类似的问题,并按如下方式解决了该问题:
自下而上的方法似乎提供了更好的结果,但YMMV。
这是自下而上方法的代码(R中)。它建立:
merge
矩阵,其中每行包括两列,并合并下两件事的索引-元素的负索引和先前创建的子集群的正索引(R使用基于1的索引)height
数组,其中包含两个合并的元素/子群集之间的距离。这被添加到合并对象的最大高度中(叶元素的高度为0),因此高度始终在增加(对于树的显示,或者对于R来说,它是“树状图”)。这可用于创建R hclust
个对象,这些对象可以通过各种方式显示和操作。
这不是最有效的实现,但是可以在合理的时间内完成工作。一种更有效的方法是减小距离矩阵的大小(这将需要更多簿记来跟踪较小矩阵和原始元素之间的索引映射):
bottom_up <- function(distances, aggregation) {
aggregate <- switch(aggregation, mean=mean, min=min, max=max)
rows_count <- dim(distances)[1]
diag(distances) <- Inf
merge <- matrix(0, nrow=rows_count - 1, ncol=2)
height <- rep(0, rows_count - 1)
merged_height <- rep(0, rows_count)
groups <- -(1:rows_count)
for (merge_index in 1:(rows_count - 1)) {
adjacent_distances <- pracma::Diag(distances, 1)
low_index <- which.min(adjacent_distances)
high_index <- low_index + 1
grouped_indices <- sort(groups[c(low_index, high_index)])
merged_indices <- which(groups %in% grouped_indices)
groups[merged_indices] <- merge_index
merge[merge_index,] <- grouped_indices
height[merge_index] <- max(merged_height[merged_indices]) + adjacent_distances[low_index]
merged_height[merged_indices] <- height[merge_index]
merged_distances <- apply(distances[,merged_indices], 1, aggregate)
distances[,merged_indices] <- merged_distances
distances[merged_indices,] <- rep(merged_distances, each=length(merged_indices))
distances[merged_indices, merged_indices] <- Inf
}
return (list(merge=merge, height=height))
}
pracma::Diag(distances, 1)
获取1对角线偏移量(在主对角线上方)。