K-Means聚类最重要的应用之一是非结构数据(声音,图像)上的矢量量化(VQ),非结构化数据往往占据较多的储存空间,文件本身比较大,运算非常缓慢,我们希望能够在保证数据质量的前提下,尽量的缩小非结构化的数据大小,或者简化非结构化数据的结构。矢量量化就可以帮助我们实现这个目的。K-Means的本质是一种降维应用,它与一些其它的降维算法的思路不太相同。例如,特征选择的降维是直接选取对模型贡献最大的特征,PCA的降维是聚合信息,而矢量量化的降维是在同等样本量上压缩信息的大小,既不改变特征数目,也不改变样本数目,只改变在这些特征下的样本上的信息量。emmmm.....细细品
举个例子来说,有一组40个样本的数据,分别含有40组不同的信息(x1,x2)。我们把这组数据聚成4类,找出4个质心,我们认为每一簇的样本点和它们所属质心非常相似,因此它们所承载的信息就约等于它们所在的簇的质心所承载的信息。那我,我们就可以用每个簇的质心来覆盖原有样本。这样,40个样本带有的40种取值,就被我们压缩了4组取值,虽然样本量还是40个,但是这40个样本所带的取值其实只有4个,就是4个质心。
#导包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin#对两个序列中的点进行距离匹配的函数
from sklearn.datasets import load_sample_image#导入图片数据所用的类
from sklearn.utils import shuffle#洗牌
#实例化导入颐和园图片
china=load_sample_image('china.jpg')
print(china)
print(china.dtype)#查看图片数据类型
print(china.shape)
#包含多少种不同的颜色?
newimage=china.reshape((427*640,3))
print(newimage.shape)
result=pd.DataFrame(newimage).drop_duplicates().shape#去重复颜色
print(result)
#图像可视化
plt.figure(figsize=(15,15))
plt.imshow(china)#导入三维数组形成的图片
plt.show()
图片探索完毕,我们可以了解到图片还有9w种颜色,我们希望使用K-Means将颜色压缩到64种,也就是说将9w种颜色聚成64类,用64个质心来代替全部的9w种颜色。
为了比较,我们还要画出随机压缩到64种颜色的矢量量化图像。我们需要随机选择64个样本点作为随机质心。对比上面使用K-Means,观察图像可视化的状况,查看图片信息的损失度。
K-Means矢量量化:
#导包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin#对两个序列中的点进行距离匹配的函数
from sklearn.datasets import load_sample_image#导入图片数据所用的类
from sklearn.utils import shuffle#洗牌
#实例化导入颐和园图片
china=load_sample_image('china.jpg')
# 数据预处理
n_clusters=64
china=np.array(china,dtype=np.float64)/china.max()#归一化,压缩[0,1]之间
w,h,d=original_shape=tuple(china.shape)#把chian从图片模式转换为矩阵格式
assert d==3#确保d一定为3,不然报错
image_array=np.reshape(china,(w*h,d))#改变矩阵结构
#对数据进行KMeans矢量量化
image_array_sample=shuffle(image_array,random_state=0)[:1000]#数据量大先使用1000个数找到质心
kmeans=KMeans(n_clusters=n_clusters,random_state=0).fit(image_array_sample)
print(kmeans.cluster_centers_.shape)#返回64个质心
#根据质心对所有数据进行分类
labels=kmeans.predict(image_array)
print(labels.shape)
#使用质心替换所有样本
image_kmeans=image_array.copy()
for i in range(w*h):
image_kmeans[i]=kmeans.cluster_centers_[labels[i]]
#恢复图片结构
image_kmeans=image_kmeans.reshape(w,h,d)
print(image_kmeans.shape)
#最后绘制图像
#原图
plt.figure(figsize=(10,10))
plt.axis('off')
plt.title('Original image (96,615 colors)')
plt.imshow(china)
plt.show()
#kmeans降维后的
plt.figure(figsize=(10,10))
plt.axis('off')
plt.title('Quantized image (64 colors,k-means)')
plt.imshow(image_kmeans)
plt.show()
效果:
随机矢量量化:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import pairwise_distances_argmin
from sklearn.datasets import load_sample_image#导入图片数据所用的类
from sklearn.utils import shuffle#洗牌
#实例化导入颐和园图片
china=load_sample_image('china.jpg')
#3 数据预处理
n_clusters=64
china=np.array(china,dtype=np.float64)/china.max()
#把chian从图片模式转换为矩阵格式
w,h,d=original_shape=tuple(china.shape)
assert d==3#确保d一定为3,不然报错
image_array=np.reshape(china,(w*h,d))
#对数据进行随机矢量量化
centroid_random=shuffle(image_array,random_state=0)[:n_clusters]#随机找到质心
print(centroid_random.shape)
labels_random=pairwise_distances_argmin(centroid_random,image_array,axis=0)#27w个数据分别对应的随机质心的索引
#使用随机质心替换所有样本
image_random=image_array.copy()
for i in range(w*h):
image_random[i]=centroid_random[labels_random[i]]
#恢复图片结构
image_random=image_random.reshape(w,h,d)
print(image_random.shape)
#显示图片
plt.figure(figsize=(10,10))
plt.axis('off')
plt.title('Quantized image (64 colors,random)')
plt.imshow(image_random)
plt.show()
效果:
对比K-Means和随机矢量量化后的图片,可见K-Means比随机矢量量化的好太多。