Building Models with Distance Metrics

这里将会讨论聚类,聚类是指给定一组没有标签的样本集 D D D ,将 D D D 划分为互不相交的k个子集,即k个样本簇。

KMeans

k-平均聚类的目的是:把n个点(可以是样本的一次观察或一个实例)划分到k个聚类中,使得每个点都属于离他最近的均值(此即聚类中心)对应的聚类,以之作为聚类的标准。这个问题将归结为一个把数据空间划分为Voronoi cells的问题。

已知观测集 { x 1 , x 2 , ⋯   , x n } \left \{ x_{1},x_{2},\cdots,x_{n}\right \} {x1,x2,,xn},其中每个观测都是一个 d d d-维实向量, k k k-平均聚类要把这 n n n个观测划分到 k k k个集合中(k≤n),使得组内平方和(WCSS within-cluster sum of squares)最小。换句话说,它的目标是找到使得下式满足的聚类 S i S_{i} Si
a r g m i n ∑ i = 1 k ∑ x ∈ S i ∥ x − μ i ∥ 2 argmin\sum_{i=1}^{k}\sum_{x\in S_{i}}\left \| x-\mu_{i} \right \|^{2} argmini=1kxSixμi2
其中 μ i \mu _{i} μi S i S_{i} Si中所有点的均值。

我们来测试一下Kmeans算法

%pylab inline
import matplotlib.pyplot as plt
import numpy as np

#加载数据
from sklearn.datasets import make_blobs
blobs, classes = make_blobs(500, centers=3)#样本数据和类别

#绘制数据
f, ax = plt.subplots()
rgb = np.array(['r', 'g', 'b'])
ax.scatter(blobs[:, 0], blobs[:, 1], color=rgb[classes])
ax.set_title("Blobs")

这里写图片描述
这里我们是知道每个样本类别的,实际情况是我们并不知道每个样本的类别。
这里写图片描述
我们使用KMeans算法来进行聚类。

from sklearn.cluster import KMeans
kmean = KMeans(n_clusters=3)#为了测试方便,假设为3
kmean.fit(blobs)
kmean.cluster_centers_

kmean.cluster_centers_就是聚类后每个类别的中心,我们画出来

f, ax = plt.subplots()
ax.scatter(blobs[:, 0], blobs[:, 1], color=rgb[classes])
ax.scatter(kmean.cluster_centers_[:, 0],kmean.cluster_centers_[:, 1], marker='*', s=250,color='black', label='Centers')
ax.set_title("Blobs")
ax.legend()

这里写图片描述
可以看到还是很符合我们的观测的。
我们也可以打印真实的类别classes和聚类后的类别kmean.labels_ 有多少相同

np.sum(kmean.labels_ == classes)

我测试的是0 。当时我就傻了,后来打印出来发现其实都是对应的,只不过聚类后的类别标号改了,

kmean.labels_[:10]
Out:array([0, 0, 1, 2, 1, 1, 1, 0, 1, 2])

classes[:10]
Out:array([2, 2, 0, 1, 0, 0, 0, 2, 0, 1])

比如原始数据的类别0对应的类别1,类别1对应类别2,类别2对应类别0,如此对应之后会发现非常的一致。

tr = np.array([2,0,1])
new_labels = tr[kmean.labels_]
np.sum(new_labels == classes)

Out:497

可以看到真的是非常准确。
还有一个很有用的函数是transform

kmean.transform(blobs)

这个函数会计算出每个样本与各个簇中心的距离

Out:array(
[[ 6.47297373, 1.39043536, 6.4936008 ],
[ 6.78947843, 1.51914705, 3.67659072],
[ 7.24414567, 5.42840092, 0.76940367],
[ 8.56306214, 5.78156881, 0.89062961],
[ 7.32149254, 0.89737788, 5.12246797]])

Silhouette distance

Silhouette距离是一种数据簇相似性(相同簇越密集越好,不同簇越分散越好)的度量方式。
假设数据已经根据某些聚类算法分为k类 C = { C 1 , C 2 ⋯   , C k } C= \{ C_{1},C_{2}\cdots ,C_{k} \} C={C1,C2,Ck},对每一个样本 x ( i ) x^{(i)} x(i),计算 x ( i ) x^{(i)} x(i)与同一类中其他所有的数据距离的均值 a ( i , x i ∈ c ) = 1 N c Σ j = 1 N c d i s t ( x c ( i ) , x c ( j ) ) a(i,x_{i} \in c) = \frac{1}{N_{c}}\Sigma_{j=1}^{N_{c}} dist(x_{c}^{(i)},x_{c}^{(j)}) a(i,xic)=Nc1Σj=1Ncdist(xc(i),xc(j))
其中假设 x i x_{i} xi属于第c类, N c N_{c} Nc为第c类样本的总个数.
在计算样本 x i x_{i} xi到所有其他簇的所有样本平均距离的最小值
b ( i ) = m i n { a ( i , x i ∉ c ) } b(i) = min\{ a(i,x_{i} \notin c)\} b(i)=min{a(i,xi/c)}
现在定义
s ( i ) = b ( i ) − a ( i ) m a x { a ( i ) , b ( i ) } s(i) = \frac{b(i)-a(i)}{max\{a(i),b(i)\}} s(i)=max{a(i),b(i)}b(i)a(i)

可以看到 − 1 ⩽ s ( i ) ⩽ 1 -1\leqslant s(i) \leqslant 1 1s(i)1 。我自己认为,可以将 b ( i ) − a ( i ) b(i)-a(i) b(i)a(i)看作是类内间距, { m a x { a ( i ) , b ( i ) } \{max\{a(i),b(i)\} {max{a(i),b(i)}看作类间距离,他们的比值 s ( i ) s(i) s(i)越接近1,说明类内间距小,同类样本密集,类间距离大,不同类的样本分开的更散。
我们可以计算出所有样本的Silhouette距离。

from sklearn import metrics
silhouette_samples = metrics.silhouette_samples(blobs,kmean.labels_)
f, ax = plt.subplots()
ax.set_title("Hist of Silhouette Samples")
ax.hist(silhouette_samples,bins=100);

可以看到silhouette_samples 都非常接近1.打印一下均值silhouette_samples.mean()。到这里就都结束了,那么我们如何知道我们的模型到底好不好呢?这个测试中我们比较了kmean.labels_classes。但是实际上我们是不知道真实的类别的,所以我们可以用metrics.silhouette_score 来指示模型的好坏,这个函数得到的其实就是所有样本silhouette距离的均值,值越大说明有越多的样本分的越准确。这里我们试着改变类别的个数k,来观测k值为多少的时候模型最好。

sillhouette_avgs = []
# this could take a while
for k in range(2, 60):
    kmean = KMeans(n_clusters=k).fit(blobs)
    sillhouette_avgs.append(metrics.silhouette_score(blobs,kmean.labels_))
f, ax = plt.subplots()
ax.plot(sillhouette_avgs)
sillhouette_avgs.index(max(sillhouette_avgs))+2 #+2是从2开始的

这里写图片描述

MiniBatch KMeans

由于KMeans算法的实现原理,当数据很多的时候常规的计算会非常的耗时,我们使用MiniBatch KMeans来进行加速计算。

from sklearn.datasets import make_blobs
blobs, labels = make_blobs(int(1e6), 3)
from sklearn.cluster import KMeans, MiniBatchKMeans
kmeans = KMeans(n_clusters=3)
minibatch = MiniBatchKMeans(n_clusters=3)

我们用两种方式来测试一下,看看到底有没有计算变快

%time kmeans.fit(blobs)
Out : Wall time: 5.55 s

%time minibatch.fit(blobs)
Out : Wall time: 1.21 s

可以看到明显加速了,但是光有计算速度是不行的,看看结果都如何

minibatch.cluster_centers_
kmeans.cluster_centers_

我们也可以直接看看中心距离差了多少

np.diag(pairwise.pairwise_distances(kmeans.cluster_centers_, minibatch.cluster_centers_))

可以看到两种方式计算的中心结果相差不多。(应该和 批梯度下降法,随机梯度下降法类似)

利用聚类模糊图片

这里讲一个有趣的应用,利用聚类模糊图像。一个图片由高Height,宽Width,RGB构成,例如一个图片大小为100200像素,每个像素为(r,g,b)那么总共就有1002003个数据需要存储,如果我们将图片img.reshape(wh,3),那么就相当于有w*h个样本,每个样本3个属性,我们通过聚类将这些样本聚成k类,求出每个类的中心值,然后所有这个类的样本都用中心值代替,再将这些数据reshape(w,h,3)还原成图片,那么我们只需要记录k个中心值就可以了,这样就是图片模糊化了。

from scipy import ndimage
img = ndimage.imread("e:\\girl.jpg")
plt.imshow(img)

这里写图片描述

 x, y, z = img.shape
long_img = img.reshape(x*y, z) #将图片格式转换有3个属性的大小为x*y个样本集

使用聚类算法

from sklearn import cluster
k_means = cluster.KMeans(n_clusters=5)
k_means.fit(long_img)

将计算后的每个类的中心代替每个类中每个样本的值,绘制出来(不忍直视)

centers = k_means.cluster_centers_
labels = k_means.labels_
plt.imshow(centers[labels].reshape(x, y, z))

这里写图片描述

绘制近邻点

我们可以计算出给定的点与其他点的距离,绘制出近邻的点。计算距离的函数用pairwise_distances

from sklearn.metrics import pairwise
from sklearn.datasets import make_blobs
points, labels = make_blobs()
distances = pairwise.pairwise_distances(points)

得到的distances 就是任意两个点距离的矩阵,例如distances[0] 就是第0个点与其他所有点的距离,假如我们想要得到与第一个样本点的最近的5个点,我们可以

ranks = np.argsort(distances[0])
near = points[ranks][:5]

argsort 函数返回的是数组值从小到大的索引值,我们可以得到前五个最近的值。

f, ax = plt.subplots()
ax.scatter(points[:,0],points[:,1],c='r')
ax.scatter(near[:,0],near[:,1],c='b')
ax.scatter(points[0,0],points[0,1], marker='*', s=250,color='black', label='Centers')
ax.legend()

这里写图片描述
这里的距离默认是欧氏距离,即 L 2 L_{2} L2。当然我们也可以使用其他距离,

  • cityblock
  • cosine
  • euclidean
  • L1
  • L2
  • manhattan

使用KMeans进行异常检测

有时候我们的样本会有一些异常点,这些点的存在是我们的模型变得非常糟糕,我们使用KMeans进行检测。异常值检测是通过找出簇的质心,然后通过距离质心的距离识别潜在离群值的点,也就是把距离最远的中心最远的几个点去掉。为了测试方便,我们生成一个中心的的簇。

from sklearn.datasets import make_blobs
import numpy as np
from sklearn.cluster import KMeans

X, labels = make_blobs(100, centers=1)
kmeans = KMeans(n_clusters=1)
kmeans.fit(X)

然后绘制出来

f, ax = plt.subplots()
ax.set_title("Blob")
ax.scatter(X[:, 0], X[:, 1], label='Points')
ax.scatter(kmeans.cluster_centers_[:, 0],kmeans.cluster_centers_[:, 1], label='Centroid',color='r')
ax.legend()

这里写图片描述
接着计算出所有点与中心的距离,我们得到最大的5个

distances = kmeans.transform(X)
sorted_idx = np.argsort(distances.ravel())[::-1][:5]

将其标注出来

f, ax = plt.subplots(figsize=(7, 5))
ax.set_title("Single Cluster")
ax.scatter(X[:, 0], X[:, 1], label='Points')
ax.scatter(kmeans.cluster_centers_[:, 0],kmeans.cluster_centers_[:, 1],label='Centroid', color='r')
ax.scatter(X[sorted_idx][:, 0], X[sorted_idx][:, 1],label='Extreme Value', edgecolors='r',facecolors='none', s=100)
ax.legend(loc='best')

这里写图片描述
然后将其删除

new_X = np.delete(X, sorted_idx, axis=0)

我们将新旧中心都画出来看看

new_kmeans = KMeans(n_clusters=1)
new_kmeans.fit(new_X)
f, ax = plt.subplots()
ax.set_title("Extreme Values Removed")
ax.scatter(new_X[:, 0], new_X[:, 1], label='Pruned Points')
ax.scatter(kmeans.cluster_centers_[:, 0],kmeans.cluster_centers_[:, 1], label='Old Centroid',color='r', s=80, alpha=.5)
ax.scatter(new_kmeans.cluster_centers_[:, 0],new_kmeans.cluster_centers_[:, 1], label='New Centroid',color='m', s=80, alpha=.5)
ax.legend(loc='best')

这里写图片描述

不得不说,新旧的中心这个真的是分不开啊。不过你可以已知删除,知道你满意。

使用KNN进行回归

KNN(k-Nearest Neighbors)其实非常的简单,就是物以类聚,人以群分。你想知道某个人的薪资,你看看他身边的人的薪资,平均一下差不多就是他的薪资了。回归时,你想知道某个样本的输出值,你可以看看这个样本周围最近的k个点的输出值时多少,这个样本点的输出值也不会偏离太多。

我们使用iris数据集进行测试

from sklearn import datasets
iris = datasets.load_iris()
iris.feature_names
Out:['sepal length (cm)','sepal width (cm)','petal length (cm)','petal width (cm)']

我们使用sepal length 和sepal width来预测petal length,

X,y=iris.data[:,[0,1]],iris.data[:,2]
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X, y)
print("The MSE is: {:.2}".format(np.power(y - lr.predict(X),2).mean()))

Out:The MSE is: 0.41

然后使用KNN进行测试,

from sklearn.neighbors import KNeighborsRegressor
knnr = KNeighborsRegressor(n_neighbors=10)
knnr.fit(X, y)
print("The MSE is: {:.2}".format(np.power(y - knnr.predict(X),2).mean()))

Out:The MSE is: 0.17

高斯混合模型聚类

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Keras中,metrics_updates是一个字典,用于指定每个指标(metrics)的更新方式。指标是用于评估模型性能的函数,例如准确率(accuracy)、损失(loss)、精度(precision)等。在训练过程中,每个指标都需要进行更新,以反映当前模型的性能。 metrics_updates的键是指标名称,值是一个函数,用于计算指标的更新值。函数的参数包括当前的指标值(metric_value)、当前的批次大小(batch_size)和总样本数(count)。例如,下面的代码定义了一个metrics_updates字典,用于更新训练过程中的准确率和损失: ``` from keras import backend as K from keras.models import Sequential from keras.layers import Dense model = Sequential() model.add(Dense(10, input_shape=(5,), activation='relu')) model.add(Dense(1, activation='sigmoid')) metrics_updates = { 'accuracy': lambda metric_value, batch_size, count: metric_value * (count-batch_size) / count + \ K.mean(K.equal(model.output > 0.5, model.targets)), 'loss': lambda metric_value, batch_size, count: metric_value * (count-batch_size) / count + \ K.mean(K.binary_crossentropy(model.targets, model.output)) } model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'], metrics_updates=metrics_updates) ``` 在上面的例子中,metrics_updates字典包含两个键:accuracy和loss。对于accuracy指标,更新函数使用了加权平均的方法,以平滑地更新指标值。对于loss指标,更新函数使用了平均损失的方法。这些更新函数都使用了Keras的后端(backend)函数,以确保能够在不同的计算图(graph)中运行。 在训练模型时,Keras将自动调用每个指标的更新函数,并在每个批次结束后更新指标值。这些指标值可以通过model.history属性获得,例如: ``` history = model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=10, batch_size=32) print(history.history['accuracy']) print(history.history['loss']) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值