Scikit learn K表示有条件
我想将K均值(或任何其他简单的聚类算法)应用于具有两个变量的数据,但我希望聚类考虑一个条件:每个聚类的第三个变量的总和>某个_值。Scikit learn K表示有条件,scikit-learn,cluster-analysis,k-means,Scikit Learn,Cluster Analysis,K Means,我想将K均值(或任何其他简单的聚类算法)应用于具有两个变量的数据,但我希望聚类考虑一个条件:每个聚类的第三个变量的总和>某个_值。 这可能吗?处理这一问题的一种方法是在聚类之前过滤数据 >>> cluster_data = df.loc[df['third_variable'] > some_value] >>> from sklearn.cluster import KMeans >>> y_pred = KMeans(n_clus
这可能吗?处理这一问题的一种方法是在聚类之前过滤数据
>>> cluster_data = df.loc[df['third_variable'] > some_value]
>>> from sklearn.cluster import KMeans
>>> y_pred = KMeans(n_clusters=2).fit_predict(cluster_data)
如果“总和”是指每个簇的第三个变量的总和,则可以使用
RandomSearchCV
查找符合或不符合条件的KMeans
超参数。处理此问题的一种方法是在聚类之前过滤数据
>>> cluster_data = df.loc[df['third_variable'] > some_value]
>>> from sklearn.cluster import KMeans
>>> y_pred = KMeans(n_clusters=2).fit_predict(cluster_data)
如果“求和”是指每个簇的第三个变量的总和,则可以使用
RandomSearchCV
查找满足或不满足条件的KMeans
超参数。K-means本身就是一个优化问题
您的附加约束也是一个相当常见的优化约束
所以我宁愿用一个优化解算器来解决这个问题。K-means本身就是一个优化问题 您的附加约束也是一个相当常见的优化约束
因此,我宁愿使用优化解算器来解决这个问题。注释:
-K是簇的数目
-假设前两个变量是点坐标(x,y)
-V表示第三个变量
-Ci:每个簇i上V的总和
-S总金额(sum Ci)
-阈值T
问题定义:
据我所知,目标是运行一个算法,在尊重约束的同时保持kmeans的精神。
任务1-通过接近质心[kmeans]对点进行分组
任务2-对于每个集群i,Ci>T*[约束]
常规kmeans约束问题的限制:
一个规则的kmeans,通过按任意顺序将点分配给质心。在我们的例子中,这将导致Ci在添加点时无法控制增长 例如,K=2,T=40和4个点,第三个变量等于V1=50,V2=1,V3=50,V4=50。 还假设点P1、P3、P4更靠近质心1。点P2更接近质心2 让我们运行常规kmeans的赋值步骤并跟踪Ci:
1——取点P1,将其分配给簇1。C1=50>T
2——取点P2,将其分配给簇2 C2=1
3——取点P3,将其分配给簇1。C1=100>T=>C1增长过多
4——取点P4,将其分配给集群1。C1=150>T=>
修改的kmeans:
在上一节中,我们希望防止C1增长过多,并帮助C2增长 这就像把香槟倒进几只玻璃杯里:如果你看到一只杯子里的香槟更少,你就去把它装满。你这样做是因为你有限制:香槟的数量有限(S是有界的),因为你希望每一杯都有足够的香槟(Ci>T) 当然,这只是一个类比。我们修改后的kmeans将使用最少的Ci向集群添加新的点,直到实现约束(Task2)。现在我们应该按什么顺序添加点?通过接近质心(任务1)。在为所有集群i实现所有约束之后,我们可以在剩余的未分配点上运行常规kmeans 实施:
接下来,我将给出修改后算法的python实现。图1显示了第三个变量的表示,该变量使用透明度将大值与低值可视化。图2显示了使用颜色的演化集群 您可以使用accept_thresh参数。特别要注意:
对于accept_thresh=0=>常规kmeans(立即达到约束)
对于accept_thresh=third_var.sum().sum()/(2*K),您可能会注意到,由于约束原因,靠近给定质心的一些点会影响到另一个质心 代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
import time
nb_samples = 1000
K = 3 # for demo purpose, used to generate cloud points
c_std = 1.2
# Generate test samples :
points, classes = datasets.make_blobs(n_features=2, n_samples=nb_samples, \
centers=K, cluster_std=c_std)
third_var_distribution = 'cubic_bycluster' # 'uniform'
if third_var_distribution == 'uniform':
third_var = np.random.random((nb_samples))
elif third_var_distribution == 'linear_bycluster':
third_var = np.random.random((nb_samples))
third_var = third_var * classes
elif third_var_distribution == 'cubic_bycluster':
third_var = np.random.random((nb_samples))
third_var = third_var * classes
# Threshold parameters :
# Try with K=3 and :
# T = K => one cluster reach cosntraint, two clusters won't converge
# T = 2K =>
accept_thresh = third_var.sum().sum() / (2*K)
def dist2centroids(points, centroids):
'''return arrays of ordered points to each centroids
first array is index of points
second array is distance to centroid
dim 0 : centroid
dim 1 : distance or point index
'''
dist = np.sqrt(((points - centroids[:, np.newaxis]) ** 2).sum(axis=2))
ord_dist_indices = np.argsort(dist, axis=1)
ord_dist_indices = ord_dist_indices.transpose()
dist = dist.transpose()
return ord_dist_indices, dist
def assign_points_with_constraints(inds, dists, tv, accept_thresh):
assigned = [False] * nb_samples
assignements = np.ones(nb_samples, dtype=int) * (-1)
cumul_third_var = np.zeros(K, dtype=float)
current_inds = np.zeros(K, dtype=int)
max_round = nb_samples * K
for round in range(0, max_round): # we'll break anyway
# worst advanced cluster in terms of cumulated third_var :
cluster = np.argmin(cumul_third_var)
if cumul_third_var[cluster] > accept_thresh:
continue # cluster had enough samples
while current_inds[cluster] < nb_samples:
# add points to increase cumulated third_var on this cluster
i_inds = current_inds[cluster]
closest_pt_index = inds[i_inds][cluster]
if assigned[closest_pt_index] == True:
current_inds[cluster] += 1
continue # pt already assigned to a cluster
assignements[closest_pt_index] = cluster
cumul_third_var[cluster] += tv[closest_pt_index]
assigned[closest_pt_index] = True
current_inds[cluster] += 1
new_cluster = np.argmin(cumul_third_var)
if new_cluster != cluster:
break
return assignements, cumul_third_var
def assign_points_with_kmeans(points, centroids, assignements):
new_assignements = np.array(assignements, copy=True)
count = -1
for asg in assignements:
count += 1
if asg > -1:
continue
pt = points[count, :]
distances = np.sqrt(((pt - centroids) ** 2).sum(axis=1))
centroid = np.argmin(distances)
new_assignements[count] = centroid
return new_assignements
def move_centroids(points, labels):
centroids = np.zeros((K, 2), dtype=float)
for k in range(0, K):
centroids[k] = points[assignements == k].mean(axis=0)
return centroids
rgba_colors = np.zeros((third_var.size, 4))
rgba_colors[:, 0] = 1.0
rgba_colors[:, 3] = 0.1 + (third_var / max(third_var))/1.12
plt.figure(1, figsize=(14, 14))
plt.title("Three blobs", fontsize='small')
plt.scatter(points[:, 0], points[:, 1], marker='o', c=rgba_colors)
# Initialize centroids
centroids = np.random.random((K, 2)) * 10
plt.scatter(centroids[:, 0], centroids[:, 1], marker='X', color='red')
# Step 1 : order points by distance to centroid :
inds, dists = dist2centroids(points, centroids)
# Check if clustering is theoriticaly possible :
tv_sum = third_var.sum()
tv_max = third_var.max()
if (tv_max > 1 / 3 * tv_sum):
print("No solution to the clustering problem !\n")
print("For one point : third variable is too high.")
sys.exit(0)
stop_criter_eps = 0.001
epsilon = 100000
prev_cumdist = 100000
plt.figure(2, figsize=(14, 14))
ln, = plt.plot([])
plt.ion()
plt.show()
while epsilon > stop_criter_eps:
# Modified kmeans assignment :
assignements, cumul_third_var = assign_points_with_constraints(inds, dists, third_var, accept_thresh)
# Kmeans on remaining points :
assignements = assign_points_with_kmeans(points, centroids, assignements)
centroids = move_centroids(points, assignements)
inds, dists = dist2centroids(points, centroids)
epsilon = np.abs(prev_cumdist - dists.sum().sum())
print("Delta on error :", epsilon)
prev_cumdist = dists.sum().sum()
plt.clf()
plt.title("Current Assignements", fontsize='small')
plt.scatter(points[:, 0], points[:, 1], marker='o', c=assignements)
plt.scatter(centroids[:, 0], centroids[:, 1], marker='o', color='red', linewidths=10)
plt.text(0,0,"THRESHOLD T = "+str(accept_thresh), va='top', ha='left', color="red", fontsize='x-large')
for k in range(0, K):
plt.text(centroids[k, 0], centroids[k, 1] + 0.7, "Ci = "+str(cumul_third_var[k]))
plt.show()
plt.pause(1)
将numpy导入为np
将matplotlib.pyplot作为plt导入
从sklearn导入数据集
导入时间
nb_样品=1000
K=3#用于演示,用于生成云点
c溳std=1.2
#生成测试样本:
点,类=数据集。生成块(n_特征=2,n_样本=nb_样本\
中心=K,集群=c)
第三个变量分布='cubic_bycluster'#'uniform'
如果第三个变量分布=‘统一’:
第三个变量=np.random.random((nb_样本))
elif第三个变量分布=='linear\u bycluster':
第三个变量=np.random.random((nb_样本))
第三个变量=第三个变量*类
elif third_var_distribution=='cubic_bycluster':
第三个变量=np.random.random((nb_样本))
第三个变量=第三个变量*类
#阈值参数:
#尝试使用K=3和:
#T=K=>一个集群达到共约束,两个集群不会收敛
#T=2K=>
接受阈值=第三个变量sum().sum()/(2*K)
def DIST2质心(点、质心):
''将有序点数组返回到每个质心
第一个数组是点的索引
第二个数组是到质心的距离
尺寸0:质心
尺寸1:距离或点索引
'''
dist=np.sqrt((点-质心[:,np.newaxis])**2.sum(轴=2))
ord_dist_index=np.argsort(dist,axis=1)
ord_dist_index=ord_dist_index.transpose()
距离=距离转置()
返回ord\U dist\U索引,dist
def分配带有限制的点(IND、DIST、tv、接受阈值):
赋值=[False]*nb_样本
赋值=np.ones(nb_样本,dtype=int)*(-1)
第三个变量=np.0(K,dtype=float)
当前索引=np.zero(K,dtype=int)
最大轮数=nb\U样本数*K
对于范围内的回合(0,最大回合):#我们无论如何都会打破
#累积第三方风险值方面最差的高级集群:
cluster=np.argmin(第三个变量)
如果cumul\u第三个变量[cluster]>接受阈值:
继续#群集有足够的样本
虽然