我有一段Python代码实现了k-means算法。我很难理解这段代码在做什么。比如C = X[numpy.random.choice(X.shape[0], k, replace=False), :]
这样的代码行对我来说非常 confusing。
有人能解释一下这段代码到底在做什么吗?谢谢
def k_means(data, k, num_of_features): # 将数据转换为矩阵
X = data.as_matrix() # 从数据中随机选择k个点
C = X[numpy.random.choice(X.shape[0], k, replace=False), :] # 移除最后一列
C = [C[j][:-1] for j in range(len(C))] # 转换为numpy数组
C = numpy.asarray(C) # 存储质心更新时的值
C_old = numpy.zeros(C.shape) # 创建一个数组,用于将每个点分配到簇
clusters = numpy.zeros(len(X)) # 误差函数 - 新旧质心之间的距离
error = dist(C, C_old, None) # 循环将持续到误差变为零或尝试5次
tries = 0
while error != 0 and tries < 1: # 将每个值分配到最近的簇
for i in range(len(X)): # 按距离获取最近的簇
clusters[i] = dist1(X[i][:-1], C) # 存储旧的质心值
C_old = deepcopy(C) # 通过取平均值找到新的质心
for i in range(k): # 获取与当前簇匹配的所有点
points = [X[j][:-1] for j in range(len(X)) if clusters[j] == i] # 如果没有点被分配到簇,则置于原点
if not points: C[i][:] = numpy.zeros(C[i].shape) else: # 获取所有点的平均值,并将质心置于该位置
C[i] = numpy.mean(points, axis=0) # 误差是质心旧位置与新位置之间的距离
error = dist(C, C_old, None) # 增加尝试次数
tries += 1
return sil_coefficient(X,clusters,k)
回答:
(扩展回答,将来会格式化)X 是作为矩阵的数据。使用 [] 符号,我们是从矩阵中获取切片或选择单个元素。你可能需要复习 numpy 数组索引。 https://docs.scipy.org/doc/numpy/reference/arrays.indexing.htmlnumpy.random.choice 从数据矩阵的第一个维度大小中随机选择 k 个元素,不替换。注意,在索引中使用 [] 语法,我们看到有两个条目。numpy.random.choice 和 “:”。”:” 表示我们沿该轴取所有元素。
因此,X[numpy.random.choice(X.shape[0], k, replace=False), :] 表示我们沿第一个轴选择一个元素,并取与该第一个索引共享的所有元素沿第二个轴。实际上,我们是在选择矩阵的一行随机行。
(注释很好地解释了这段代码,我建议你进一步了解 numpy 索引和列表解析)。
C[C[j][:-1] for j in range(len(c))] 部分中的 “C[” 使用列表解析来选择矩阵 C 的一部分。
C[j] 代表矩阵 C 的行。我们使用 [:-1] 来获取行中除最后一个元素之外的所有元素。我们对矩阵 C 中的每一行都这样做。这移除了矩阵的最后一列。
C = numpy.asarray(C)。这将矩阵转换为 numpy 数组,以便我们可以对其进行特殊的 numpy 操作。
C_old = numpy.zeros(C.shape)。这创建了一个零矩阵,以后会被填充,其大小与 C 相同。我们正在初始化这个数组以便以后填充。
clusters = numpy.zeros(len(x))。这创建了一个零向量,其维度与矩阵 X 的行数相同。这个向量稍后会被填充。我们正在初始化这个数组以便以后填充。
error = dist(C, C_old, None)。计算两个矩阵之间的距离。我相信这个函数是在你的脚本中的其他地方定义的。
tries = 0。将尝试计数器设置为 0。
while…在该条件为真时执行该代码块。
for i in [0…(X 行数 – 1)]:
clusters[i] = dist1(X[i][:-1], C); 将 X 的第 i 行最接近的簇放在 clusters 的第 i 个位置。
C_old = deepcopy(C) – 创建 C 的一个新的副本。不要只是移动指针。
对于每个 (0..簇的数量 – 1):
points = [X[j][:-1] for j in range(len(X)) if clusters[j] == i]。这是列表解析。创建一个列表,包含 X 的行,去掉最后一个条目,但仅当该行属于第 j 个簇时才包含该行。
if not points。如果没有点属于某个簇。
C[i][:] = numpy.zeros(C[i].shape)。创建一个零向量,以后会被填充,并使用这个向量作为簇矩阵 C 的第 i 行。
else:
C[i] = np.mean(points, axis=0)。将簇矩阵 C 的第 i 行赋值为簇中点的平均值。我们沿行求和(axis=0)。这是我们在更新我们的簇。