持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
先讲一下等以下用于本次的预处理和半监督学习中的数据集,他是来自Scikit-Learn.datasets下的load_digits(),和我们之前使用的MNIST数据集类似,也是一些数字数据集。不过这个相对小一些,含有1797个8*8像素的数字。
聚类预处理
按照之前的做法,面对这些比较规律的,可以直接使用LogisticRegression(),输出的结果如下:
log_reg.score(X_test, y_test)->0.9688888888888889
但是其实看上面的结果,我们知道标签应该是在0-9之间,也就是主要有10类数字的手写。其实也可以在这个数字集输入LogisticRegression()之前,可以先使用K-Means处理一下,同时也是一个不错的降维算法。
但是我们要注意一点:按照10个分类还不够,因为我们的数据集可视化后如下图所示:
图1 部分数字图像
可以看到,及时是同样一个数字,光是这边就有两种不相同的写法。因此在聚类的同时要考虑到降维,也要考虑类别不能太少。比如我们可以将类别设置成60个,然后弄成Pipeline中:
pipeline = Pipeline([
("kmeans", KMeans(n_clusters=60, random_state=42)),
("log_reg", LogisticRegression(multi_class="ovr", solver="lbfgs", max_iter=5000, random_state=42))
])
pipeline.fit(X_train, y_train)
pipeline.score(X_test, y_test) #输出:0.9844444444444445
还不错,提升的效果还是很明显的。如果我们像继续往下找有没有更合适的n_clusters,也很简单,使用GridSearchCV(),对pipeline中的n_clusters进行搜索以下就行。
聚类进行半监督学习
在平时我们如果有不少的可训练数据,但只有少量的标签时(比如数据集还是上面的,但是就选取其中60个训练),我们看看使用的LogisticRegression()的效果如何:
# 截取一部分数据
log_reg.fit(X_train[:60], y_train[:60])
log_reg.score(X_test, y_test)# 输出:0.8844444444444445
嗯哼!结果很明显,预测的准确率降低到了83.4%左右。这样的结果还是挺不满意的,不过有了上面的例子,我们是不是可以做什么改变,增加一下预测效果:
- 可以使用聚类预处理,提高预测效果
- 同时聚类之后,我们还可以选择一些有点代表性的数据,比如选择离中心点最近的图像
kmeans = KMeans(n_clusters=60, random_state=42)
X_digits_dist = kmeans.fit_transform(X_train)
representative_digit_idx = np.argmin(X_digits_dist, axis=0)
X_representative_digits = X_train[representative_digit_idx]
log_reg.fit(X_representative_digits, y_representative_digits)
log_reg.score(X_test, y_test)#输出:0.9222222222222223
这效果提升的还是很不错的,但我们可以继续提升他的准确率。比如说我们把现有的标签传播到其他的同一集群中的实例(称为标签传播):处理起来很简单,就是循环我们的n_clusters数-for i in range(60),每次选出KMeans分割成同一类,将预测值设置成一样:
y_train_propagated[kmeans.labels_==i] = y_representative_digits[i]
然后训练一下log_reg,得出的分数是:0.9333333333333333
这个结果有一点点提升,但是好像不想我们的想的那么美好。这个是什么原因呢?我们得从KMeans深入思考一下,在KMeans得分类边界处的值,其实有时候分的不像离中心的那么准确,也就是你在AB边界处,可能是A,也可能是B,因此对于这些的数据,最好能够剔除掉。
比如我可以使用np.percentile选出每类前75%的数据,在重新训练:
X_cluster_dist = X_digits_dist[np.arange(len(X_train)), kmeans.labels_]
for i in range(k):
in_cluster = (kmeans.labels_ == i)
cluster_dist = X_cluster_dist[in_cluster]
cutoff_distance = np.percentile(cluster_dist, percentile_closest)
above_cutoff = (X_cluster_dist > cutoff_distance)
X_cluster_dist[in_cluster & above_cutoff] = -1
partially_propagated = (X_cluster_dist != -1)
X_train_partially_propagated = X_train[partially_propagated]
y_train_partially_propagated = y_train_propagated[partially_propagated]
log_reg.fit(X_train_partially_propagated, y_train_partially_propagated)
log_reg.score(X_test, y_test)#输出:0.9355555555555556
效果还满不错了,只用了50个实例,我们能够达到接近直接使用LogisticRegression()训练全部训练集的准确率。