distances = np.sqrt(((X - centroids[:, np.newaxis]) ** 2).sum(axis=2))
时间: 2024-06-07 17:10:16 浏览: 7
这段代码是计算每个样本点与聚类中心的欧式距离,其中X是样本数据矩阵,centroids是聚类中心矩阵。具体来说,np.newaxis用于扩展centroids的维度,使其可以与X进行广播运算,**2表示对差值平方,sum(axis=2)表示对差值平方后的矩阵沿着第2个维度(即特征维度)求和,最终得到每个样本点到每个聚类中心的欧式距离矩阵,存储在distances中。
相关问题
class KMeans: def __init__(self, k=2): self.k = k def fit(self, X): # 初始化聚类中心 self.centroids = X[np.random.choice(X.shape[0], self.k, replace=False)] while True: # 计算每个样本到聚类中心的距离 distances = np.sqrt(((X - self.centroids[:, np.newaxis]) ** 2).sum(axis=2)) # 将每个样本分配到距离最近的聚类中心 labels = np.argmin(distances, axis=0) # 计算新的聚类中心 new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(self.k)]) # 判断是否收敛 if np.allclose(new_centroids, self.centroids): break self.centroids = new_centroids def predict(self, X): distances = np.sqrt(((X - self.centroids[:, np.newaxis]) ** 2).sum(axis=2)) return np.argmin(distances, axis=0)
这是一个简单的 KMeans 聚类算法的实现。KMeans 算法是一种无监督学习算法,通过将样本分成 k 类,并将每个样本分配到距离最近的聚类中心,来实现聚类任务。
在这个实现中,初始化时指定了聚类的数目 k。在 fit 函数中,随机选择 k 个样本作为初始聚类中心,然后不断迭代,计算每个样本到聚类中心的距离,并将每个样本分配到距离最近的聚类中心。之后,计算新的聚类中心,并判断是否收敛。如果新的聚类中心与旧的聚类中心相同,说明已经收敛,算法结束。否则,将新的聚类中心作为当前的聚类中心,继续迭代。
在 predict 函数中,计算每个样本到聚类中心的距离,并将其分配到距离最近的聚类中心,返回每个样本所属的聚类编号。
import numpy as npfrom numpy.linalg import normdef fcm(X, c, m, error=0.0001, maxiter=1000): # 初始化隶属度矩阵 U U = np.random.rand(c, X.shape[0]) U /= np.sum(U, axis=0) # 迭代计算 for i in range(maxiter): # 计算聚类中心 centroids = U.dot(X) / U.sum(axis=1)[:, None] # 计算距离矩阵 distances = np.sqrt(((X[:, None, :] - centroids) ** 2).sum(axis=2)) # 更新隶属度矩阵 U U_new = 1 / (distances / np.expand_dims(np.min(distances, axis=2), axis=2)) ** (2 / (m - 1)) U_new /= np.sum(U_new, axis=0) # 判断收敛 if norm(U_new - U) < error: break U = U_new # 返回聚类结果 return centroids, U.argmax(axis=0)# 示例数据X = np.random.rand(100, 2)# 聚类数目c = 3# 模糊指数m = 2# 聚类centroids, labels = fcm(X, c, m)# 打印聚类中心和标签print('Centroids:', centroids)print('Labels:', labels)优化这段代码
这段代码本身已经比较简洁和高效了,但还是有一些可以优化的地方:
1. 在计算距离矩阵时,可以使用numpy的广播功能来避免使用np.expand_dims函数:
```
distances = np.sqrt(((X[:, None, :] - centroids) ** 2).sum(axis=2))
```
2. 在计算U_new时,可以将np.expand_dims函数替换为np.newaxis:
```
U_new = 1 / (distances / np.min(distances, axis=2)[:, np.newaxis]) ** (2 / (m - 1))
```
3. 可以使用numpy的einsum函数进一步优化计算距离矩阵的过程:
```
distances = np.sqrt(np.einsum('ijk->ij', (X[:, np.newaxis, :] - centroids) ** 2))
```
4. 可以将一些常数值(如2和1)提前计算并存储,避免重复计算:
```
c1 = 2 / (m - 1)
c2 = 1 / (m - 1)
U_new = 1 / (distances / np.min(distances, axis=2)[:, np.newaxis]) ** c1
```
综上,以下是优化后的代码:
```
import numpy as np
from numpy.linalg import norm
def fcm(X, c, m, error=0.0001, maxiter=1000):
# 初始化隶属度矩阵 U
U = np.random.rand(c, X.shape[0])
U /= np.sum(U, axis=0)
# 计算常数值
c1 = 2 / (m - 1)
c2 = 1 / (m - 1)
# 迭代计算
for i in range(maxiter):
# 计算聚类中心
centroids = U.dot(X) / U.sum(axis=1)[:, None]
# 计算距离矩阵
distances = np.sqrt(np.einsum('ijk->ij', (X[:, np.newaxis, :] - centroids) ** 2))
# 更新隶属度矩阵 U
U_new = 1 / (distances / np.min(distances, axis=2)[:, np.newaxis]) ** c1
U_new /= np.sum(U_new, axis=0)
# 判断收敛
if norm(U_new - U) < error:
break
U = U_new
# 返回聚类结果
return centroids, U.argmax(axis=0)
# 示例数据
X = np.random.rand(100, 2)
# 聚类数目
c = 3
# 模糊指数
m = 2
# 聚类
centroids, labels = fcm(X, c, m)
# 打印聚类中心和标签
print('Centroids:', centroids)
print('Labels:', labels)
```