从零开始搭建K-Means(含代码)

什么是K-Means?

K-Means是一种无监督机器学习模型,在数据没有给定labels的情况下,我们用K-Means来进行分类预测。

K-Means的工作原理:

  1. 随机选取K个点(数据点)作为中心点
  2. 对每个数据点,计算该数据点到各个中心点的距离,并找出距离最近的那个中心点,将该数据点分配给最近的中心点的类。
  3. 对所有的数据点做完分配后,重新计算中心点,计算方法是求该类中每个特征的平均值,新的中心点的特征是该类中所有数据的特征的平均值。
  4. 看看中心点是否收敛(新中心点与原中心点变化是否小于一个阈限,小于即收敛),如果没有收敛用新的中心点返回2重新分类每个数据点

关于步骤2的距离计算,算法中用的是L2距离,即欧氏距离。因为K-Means算法目的是最小化簇内方差,而方差的定义就是平方和的形式。当然用其他距离也是可行的,但是欧式距离应用最广。

K-Means的优缺点:

优点:

  1. 原理简单
  2. 聚类效果教优
  3. 可解释性强
  4. 参数调整简单

缺点:

  1. K的取值问题
  2. 对于异常点敏感、
  3. 对数据不平衡的数据集效果不是很好
  4. 初始化的中心点会影响最终结果

关于K的取值问题,如果在不知道K取值的时候可以使用Elbow Method。
从零开始搭建K-Means(含代码)_第1张图片
当K增大时,中心点更靠近数据点,所以数据点与对应中心点的方差越来越小。选择曲线上曲率最大的点对应的横坐标作为K的取值,如图K=3。
对于中心点初始化问题,不同的初始化会引起不同的结果,这一点多运行几遍代码就可以看到,同样的K值会导致不同的分类结果。这一点在Kmeans++算法中有所改善,Kmeans++优化了初始化方法,使初始化的中心点尽可能远。虽然在初始化中心点的时候比原始算法费时,但是在迭代过程中能快速收敛,所以实际上算法降低了计算时间。
另外,Kmeans只能对于数字型数据计算距离,无法对categorical特征进行距离计算。

代码:

# k -  cluster number
# epsilon - threshold which is the minimum error to be used in the stop condition
# distance - type of distance l1 or l2

# return:
# prototypes - final centroids
# centroids - all iterations centroids
# group - each sample in which group

def kmeans(dataset, k, epsilon=0, distance='l2'):
    # store the centroids for all iterations
    all_centroids = []
    num_samples, num_features = dataset.shape
    # step1 - initialize the centroids
    centroids = dataset[np.random.randint(0,num_samples-1, size=k)]
    
    all_centroids.append(centroids)
    centroids_prev = np.zeros(centroids.shape)
    # store the clusters
    group = np.zeros((num_samples,1))
    
    # we use l2 distance, and you can also use l1 distance(write by youself)
    if distance == 'l2':
        method = l2_dist
    else:
        pass
    
    norm = method(centroids,centroids_prev)
    iteration = 0
    
    # step 2-4:
    while norm > epsilon:
        iteration += 1
        centroids_prev = centroids
        
        # for each sample in the dataset
        for index, sample in enumerate(dataset):
            # dist_vec store the distances between current sample and k centroids
            dist_vec = np.zeros((k,1))
            for index_pro, centroid in enumerate(centroids):
                # calculate the distance between sample and j-th centroids
                dist_vec[index_pro] = method(centroid, sample)
            # find the group which nearest with the sample
            group[index,0] = np.argmin(dist_vec)
        # new centroids
        temp_centroids = np.zeros((k,num_features))
        # for each cluster calculate the new centroid
        for index in range(len(centroids)):
            sample_close = [i for i in range(len(group)) if group[i] == index]
            centroid = np.mean(dataset[sample_close], axis=0)
            temp_centroids[index,:] = centroid
            
        centroids = temp_centroids
        
        norm = method(centroids,centroids_prev)
        
        all_centroids.append(temp_centroids)
        
    distortion = 0
    for i in range(num_samples):
        distortion += l2_dist(dataset[i,:],centroids[int(group[i]),:])
        
    return centroids, all_centroids, group, distortion 

完整代码下载请到我的github主页,里面还有各种初学者适用的代码:https://github.com/Ylsh1992/Numpy-Kmeans

代码有用的话请三连……点赞关注收藏~~~

你可能感兴趣的:(无监督学习,K-Means,从零开始)