我们将K均值、DBSCAN、和凝聚聚类算法应用于Wild数据集中的Labeled Faces,并查看他们是否找到了有趣的结构,我们将使用数据的特征表示它由包含100个主成分的PCA(whiten=true)生成。
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
from sklearn.metrics.cluster import adjusted_rand_score
from sklearn.metrics.cluster import silhouette_score
#从lfw数据中提取特征脸,并对数据进行变换
from sklearn.decomposition import PCA
people = fetch_lfw_people()
x_people= image_shape = people.images[0].shape
mask = np.zeros(people.target.shape, dtype=np.bool)
for target in np.unique(people.target):
mask[np.where(people.target == target)[0][:50]] = 1
x_people = people.data[mask]
y_people = people.target[mask]
x_people = x_people/255
pca = PCA(n_components=100, whiten=True, random_state=0)
pca.fit_transform(x_people)
x_pca = pca.transform(x_people)
#我们之前见到,与原始像素相比,这是对人脸图像的一种语义更强的表示,其计算速度也更快
#这是一个很好的练习,就是在原始数据上运行下列实验,不用PCA,我们来看是不是能找到
#类似的簇
#应用默认参数的DBSCAN
dbscan = DBSCAN()
labels = dbscan.fit_predict(x_pca)
print("unique labels: {}".format(np.unique(x_pca)))
print("Number of points per cluster:{}".format(np.bincount(labels+1)))
运行上述代码的结果为:
unique labels: [-5.3817143 -5.025449 -4.996254 ... 6.376457 6.4434543 6.5006413]
Number of points per cluster:[3005]
我们看到,这里的3005个数据全部被标记为噪声,下面我们通过修改eps和n_samples数值来进行调整(增大eps或减小min_samples都可以减少噪声)。
前面代码不变,只是修改样本最小数和eps值。
dbscan = DBSCAN(min_samples=2)
labels = dbscan.fit_predict(x_pca)
print("unique labels: {}".format(np.unique(x_pca)))
print("Number of points per cluster:{}".format(np.bincount(labels+1)))
运行结果如下:
unique labels: [-5.3816504 -5.294047 -5.0465255 ... 6.633741 6.635052 6.962216 ]
Number of points per cluster:[3005]
这里我们把min_samples的值都减小到2了,但是还是所有点都是噪声。看来min_samples值对问题的影响不大,下面我们来调整eps(距离)值来看看。
#调整DBSCAN参数
dbscan = DBSCAN(min_samples=3, eps=14)
labels = dbscan.fit_predict(x_pca)
print("unique labels: {}".format(np.unique(x_pca)))
print("Number of points per cluster:{}".format(np.bincount(labels+1)))
运行结果如下:
Number of points per cluster:[1631 1374]
然后在运行,这里min_samples值为3,eps值为14时,发现又1631个噪声,只有1374个点为核心样本。
我们增大eps的值为18,看看结果。
#调整DBSCAN参数
dbscan = DBSCAN(min_samples=3, eps=18)
labels = dbscan.fit_predict(x_pca)
print("unique labels: {}".format(np.unique(x_pca)))
print("Number of points per cluster:{}".format(np.bincount(labels+1)))
此时的运行结果如下:
Number of points per cluster:[ 296 2709]
此时噪声点相对比较少了,只有296个噪声点,2709个核心样本。下面我们来看看所有的噪声点。在上述代码后面添加下面的代码:
noise = x_people[labels==-1]
fig, axes = plt.subplots(3, 9, subplot_kw={'xticks': (), 'yticks': ()}, figsize=(12, 4))
for image, ax in zip(noise, axes.ravel()):
ax.imshow(image.reshape(image_shape), vmin=0, vmax=1)
运行后结果如下图所示:

人脸数据集中被DBSCAN标记为噪声的样本
通过比较上面图中的噪声点,我们发现有个共同的特征,那就是这些图像的脸部显示都是不清晰或不完整的,有的用手挡住了脸,有的大笑或者表情夸张,还有的是曝光度不适中。这种尝试找出不正常图形的方法被称作”异常值检测“。通过该方法我们可能会尝试更好的剪切图像,以得到更加适合的数据,将那些噪声点图像筛选掉。
下节我们将接着分析该部分内容。