半监督学习方法介绍
立即解锁
发布时间: 2025-08-30 00:50:02 阅读量: 9 订阅数: 13 AIGC 

### 半监督学习方法介绍
在机器学习领域,半监督学习是一种结合了有监督学习和无监督学习的方法,它能够利用少量的有标签样本和大量的无标签样本进行模型训练,从而提高模型的性能。本文将介绍基于CPLE算法的半监督解决方案,以及半监督支持向量机(S³VM)和直推式支持向量机(TSVM)的原理和实现。
#### 基于CPLE算法的半监督解决方案
有一个快速的算法,在使用时需要两个参数:f(要最小化的函数)和x0(自变量的初始条件)。maxiter参数可避免在无改进时进行过多迭代。优化完成后,q_end包含最优软标签,可据此重建数据集:
```python
X_n, Y_n = build_dataset(q_end)
```
用最终配置重新训练逻辑回归模型并检查交叉验证准确率:
```python
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
final_semi_cv_scores = cross_val_score(LogisticRegression(), X_n, Y_n.squeeze(), cv=10)
print(final_semi_cv_scores)
```
输出结果如下:
```plaintext
[ 1. 1. 0.89189189 0.77777778 0.97222222 0.88888889
0.61111111 0.88571429 0.94285714 0.48571429]
```
基于CPLE算法的半监督解决方案平均准确率达84%,优于有监督方法。读者可尝试使用不同分类器(如SVM或决策树),验证CPLE何时能比其他有监督算法获得更高准确率。
#### 半监督支持向量机(S³VM)
在讨论聚类假设时,我们将低密度区域定义为边界,对应的问题为低密度分离。基于此概念的常见有监督分类器是支持向量机(SVM),其目标是最大化样本所在密集区域之间的距离。
线性SVM带松弛变量ξi的基本模型基于yi取值为 -1 或 1 的假设。松弛变量ξi或软间隔是为减少原条件(min ||w||)的约束强度而引入的,原条件基于硬间隔,会误分类所有位于错误一侧的样本。松弛变量由合页损失定义。
每个高密度区域的最后元素是支持向量,它们之间是低密度区域,分离超平面位于此。可将SVM问题转化为在合页成本函数下最小化经验风险(对w进行或不进行岭正则化)。
在半监督场景中解决此类问题时,需考虑有标签和无标签样本的整合策略。首先要考虑的是比例:若无标签点比例低,问题主要是有监督的,训练集学到的泛化能力应足以正确分类所有无标签点;若无标签样本数量大,则接近纯聚类场景。为发挥半监督方法在低密度分离问题中的优势,应考虑有标签/无标签比例约为1.0的情况。
S³VM算法为此问题提供了解决方案。若有N个有标签样本和M个无标签样本,目标函数如下:
第一个项施加了标准SVM关于最大分离距离的条件,第二项分为两部分:
- 需添加N个松弛变量ηi,为有标签样本保证软间隔。
- 同时考虑无标签点,其可能被分类为 +1 或 -1,因此有两组对应的松弛变量ξi和zi,要为每个可能的对找到最小变量,以确保无标签样本置于准确率最高的子空间。
解决问题所需的约束条件如下:
- 第一个约束仅适用于有标签点,与有监督SVM相同。
- 后两个约束考虑了无标签样本可能被分类为 +1 或 -1 的情况。
此方法是归纳性的,性能良好,但计算成本高,应使用优化(原生)库解决。不幸的是,这是一个非凸问题,没有标准方法能保证总是达到最优配置。
##### S³VM示例
使用SciPy优化方法在Python中实现S³VM,具体步骤如下:
1. **创建二维数据集**
```python
from sklearn.datasets import make_classification
nb_samples = 500
nb_unlabeled = 200
X, Y = make_classification(n_samples=nb_samples, n_features=2, n_redundant=0, random_state=1000)
Y[Y==0] = -1
Y[nb_samples - nb_unlabeled:nb_samples] = 0
```
2. **初始化优化问题所需变量**
```python
import numpy as np
w = np.random.uniform(-0.1, 0.1, size=X.shape[1])
eta = np.random.uniform(0.0, 0.1, size=nb_samples - nb_unlabeled)
xi = np.random.uniform(0.0, 0.1, size=nb_unlabeled)
zi = np.random.uniform(0.0, 0.1, size=nb_unlabeled)
b = np.random.uniform(-0.1, 0.1, size=1)
C = 1.0
theta0 = np.hstack((w, eta, xi, zi, b))
vmin = np.vectorize(lambda x1, x2: x1 if x1 <= x2 else x2)
```
3. **定义目标函数**
```python
def svm_target(theta, Xd, Yd):
wt = theta[0:2].reshape((Xd.shape[1], 1))
s_eta = np.sum(theta[2:2 + nb_samples - nb_unlabeled])
s_min_xi_zi = np.sum(vmin(theta[2 + nb_samples - nb_unlabeled:2 + nb_samples],
theta[2 + nb_samples:2 + nb_samples + nb_unlabeled]))
return C * (s_eta + s_min_xi_zi) + 0.5 * np.dot(wt.T, wt)
```
4. **定义约束条件**
```python
def labeled_constraint(theta, Xd, Yd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = Yd[idx] * (np.dot(Xd[idx], wt) + theta[-1]) + theta[2:2 + nb_samples - nb_unlabeled][idx] - 1.0
return (c >= 0)[0]
def unlabeled_constraint_1(theta, Xd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = np.dot(Xd[idx], wt) - theta[-1] + theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] - 1.0
return (c >= 0)[0]
def unlabeled_constraint_2(theta, Xd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = -(np.dot(Xd[idx], wt) - theta[-1]) + theta[2 + nb_samples:2 + nb_samples + nb_unlabeled ][idx - nb_samples + nb_unlabeled] - 1.0
return (c >= 0)[0]
def eta_constraint(theta, idx):
return theta[2:2 + nb_samples - nb_unlabeled][idx] >= 0
def xi_constraint(theta, idx):
return theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] >= 0
def zi_constraint(theta, idx):
return theta[2 + nb_samples:2 + nb_samples+nb_unlabeled ][idx - nb_samples + nb_unlabeled] >= 0
```
5. **设置问题并进行优化**
```python
svm_constraints = []
for i in range(nb_samples - nb_unlabeled):
svm_constraints.append({
'type': 'ineq',
'fun': labeled_constraint,
'args': (X, Y, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': eta_constraint,
'args': (i,)
})
for i in range(nb_samples - nb_unlabeled, nb_samples):
svm_constraints.append({
'type': 'ineq',
'fun': unlabeled_constraint_1,
'args': (X, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': unlabeled_constraint_2,
'args': (X, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': xi_constraint,
'args': (i,)
})
svm_constraints.append({
'type': 'ineq',
'fun': zi_constraint,
'args': (i,)
})
from scipy.optimize import minimize
result = minimize(fun=svm_target,
x0=theta0,
constraints=svm_constraints,
args=(X, Y),
method='SLSQP',
tol=0.0001,
options={'maxiter': 1000})
```
6. **计算无标签点的标签**
```python
theta_end = result['x']
w = theta_end[0:2]
b = theta_end[-1]
Xu = X[nb_samples - nb_unlabeled:nb_samples]
yu = -np.sign(np.dot(Xu, w) + b)
```
S³VM成功为所有无标签点找到正确标签,证实了在x介于[0, 2](方形点)和y介于[0, 2](圆形点)之间存在两个非常密集的区域。
#### 直推式支持向量机(TSVM)
TSVM由T. Joachims提出,其思路是保留原目标,使用两组松弛变量:一组用于有标签样本,另一组用于无标签样本。这是一种直推式方法,需将无标签样本视为可变标签样本,施加与有监督点类似的约束。
假设我们有N个有标签样本和M个无标签样本,条件如下:
- 第一个约束是经典的SVM约束,仅适用于有标签样本。
- 第二个约束使用变量y(u)j和相应的松弛变量ξj对无标签样本施加类似条件。
- 第三个约束用于限制标签为 -1 或 1。
与半监督SVM一样,该算法是非凸的,尝试不同的优化方法很有用。当测试集(无标签)大且训练集(有标签)相对小时,TSVM表现更好;而当训练集大且测试集小时,有监督SVM(或其他算法)通常更优,因为它们更快且准确率更高。
##### TSVM示例
在Python中实现TSVM,步骤如下:
1. **创建数据集**
```python
from sklearn.datasets import make_classification
nb_samples = 500
nb_unlabeled = 400
X, Y = make_classification(n_samples=nb_samples, n_features=2, n_redundant=0, random_state=1000)
Y[Y==0] = -1
Y[nb_samples - nb_unlabeled:nb_samples] = 0
```
2. **初始化变量**
```python
import numpy as np
w = np.random.uniform(-0.1, 0.1, size=X.shape[1])
eta_labeled = np.random.uniform(0.0, 0.1, size=nb_samples - nb_unlabeled)
eta_unlabeled = np.random.uniform(0.0, 0.1, size=nb_unlabeled)
y_unlabeled = np.random.uniform(-1.0, 1.0, size=nb_unlabeled)
b = np.random.uniform(-0.1, 0.1, size=1)
C_labeled = 1.0
C_unlabeled = 10.0
theta0 = np.hstack((w, eta_labeled, eta_unlabeled, y_unlabeled, b))
```
3. **定义目标函数**
```python
def svm_target(theta, Xd, Yd):
wt = theta[0:2].reshape((Xd.shape[1], 1))
s_eta_labeled = np.sum(theta[2:2 + nb_samples - nb_unlabeled])
s_eta_unlabeled = np.sum(theta[2 + nb_samples - nb_unlabeled:2 + nb_samples])
return (C_labeled * s_eta_labeled) + (C_unlabeled * s_eta_unlabeled) + (0.5 * np.dot(wt.T, wt))
```
4. **定义约束条件**
```python
def labeled_constraint(theta, Xd, Yd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = Yd[idx] * (np.dot(Xd[idx], wt) + theta[-1]) + theta[2:2 + nb_samples - nb_unlabeled][idx] - 1.0
return (c >= 0)[0]
def unlabeled_constraint(theta, Xd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = theta[2 + nb_samples:2 + nb_samples + nb_unlabeled][idx - nb_samples + nb_unlabeled] * (np.dot(Xd[idx], wt) + theta[-1]) + theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] - 1.0
return (c >= 0)[0]
def eta_labeled_constraint(theta, idx):
return theta[2:2 + nb_samples - nb_unlabeled][idx] >= 0
def eta_unlabeled_constraint(theta, idx):
return theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] >= 0
def y_constraint(theta, idx):
return np.power(theta[2 + nb_samples:2 + nb_samples + nb_unlabeled][idx], 2) == 1.0
```
5. **设置问题并进行优化**
```python
svm_constraints = []
for i in range(nb_samples - nb_unlabeled):
svm_constraints.append({
'type': 'ineq',
'fun': labeled_constraint,
'args': (X, Y, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': eta_labeled_constraint,
'args': (i,)
})
for i in range(nb_samples - nb_unlabeled, nb_samples):
svm_constraints.append({
'type': 'ineq',
'fun': unlabeled_constraint,
'args': (X, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': eta_unlabeled_constraint,
'args': (i,)
})
for i in range(nb_unlabeled):
svm_constraints.append({
'type': 'eq',
'fun': y_constraint,
'args': (i,)
})
from scipy.optimize import minimize
result = minimize(fun=svm_target,
x0=theta0,
constraints=svm_constraints,
args=(X, Y),
method='SLSQP',
tol=0.0001,
options={'maxiter': 1000})
```
6. **计算无标签样本的标签**
```python
theta_end = result['x']
w = theta_end[0:2]
b = theta_end[-1]
Xu = X[nb_samples - nb_unlabeled:nb_samples]
yu = -np.sign(np.dot(Xu, w) + b)
```
TSVM的误分类率(基于密度分布)略高于S³VM,但可通过更改C值和优化方法来达到预期结果。有监督SVM可作为一个很好的基准,当训练集足够大且能正确代表整个数据时,它可能表现更好。
#### 不同C参数组合的评估
从标准有监督SVM开始,评估不同C参数组合很有趣。使用一个较小的数据集,有大量无标签样本:
```python
nb_samples = 100
nb_unlabeled = 90
X, Y = make_classification(n_samples=nb_samples, n_features=2, n_redundant=0, random_state=100)
Y[Y==0] = -1
Y[nb_samples - nb_unlabeled:nb_samples] = 0
```
使用Scikit-Learn提供的标准SVM实现(SVC类),线性核,C = 1.0:
```python
from sklearn.svm import SVC
svc = SVC(kernel='linear', C=1.0)
svc.fit(X[Y!=0], Y[Y!=0])
Xu_svc = X[nb_samples - nb_unlabeled:nb_samples]
yu_svc = svc.predict(Xu_svc)
```
结果基本符合预期,但在某个区域(X [-1, 0] - Y [-2, -1]),SVM将接近方形的无标签点分类为圆形,这不符合聚类假设。使用S³VM,CL = 10和CU = 5时,分类准确率较低,因为对无标签样本的惩罚低于有标签点,有监督SVM表现更好。接下来可尝试CL = 10和CU = 50的情况,进一步评估性能。
综上所述,半监督学习方法在不同场景下有各自的优势和适用范围,通过合理选择算法和调整参数,可以提高模型的性能和分类准确率。
### 半监督学习方法介绍(续)
#### 不同C参数组合的进一步评估
我们接着上文,尝试CL = 10和CU = 50的情况。首先回顾一下,之前在使用标准SVM(C = 1.0)以及S³VM(CL = 10和CU = 5)时都出现了一些不太符合预期分类的情况。现在我们重新使用S³VM并调整参数,看看效果如何。
```python
# 重新创建数据集
nb_samples = 100
nb_unlabeled = 90
X, Y = make_classification(n_samples=nb_samples, n_features=2, n_redundant=0, random_state=100)
Y[Y==0] = -1
Y[nb_samples - nb_unlabeled:nb_samples] = 0
# 初始化优化问题所需变量
import numpy as np
w = np.random.uniform(-0.1, 0.1, size=X.shape[1])
eta = np.random.uniform(0.0, 0.1, size=nb_samples - nb_unlabeled)
xi = np.random.uniform(0.0, 0.1, size=nb_unlabeled)
zi = np.random.uniform(0.0, 0.1, size=nb_unlabeled)
b = np.random.uniform(-0.1, 0.1, size=1)
CL = 10
CU = 50
theta0 = np.hstack((w, eta, xi, zi, b))
# 定义目标函数
def svm_target(theta, Xd, Yd):
wt = theta[0:2].reshape((Xd.shape[1], 1))
s_eta = np.sum(theta[2:2 + nb_samples - nb_unlabeled])
s_min_xi_zi = np.sum(np.vectorize(lambda x1, x2: x1 if x1 <= x2 else x2)(theta[2 + nb_samples - nb_unlabeled:2 + nb_samples],
theta[2 + nb_samples:2 + nb_samples + nb_unlabeled]))
return (CL * s_eta) + (CU * s_min_xi_zi) + 0.5 * np.dot(wt.T, wt)
# 定义约束条件
def labeled_constraint(theta, Xd, Yd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = Yd[idx] * (np.dot(Xd[idx], wt) + theta[-1]) + theta[2:2 + nb_samples - nb_unlabeled][idx] - 1.0
return (c >= 0)[0]
def unlabeled_constraint_1(theta, Xd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = np.dot(Xd[idx], wt) - theta[-1] + theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] - 1.0
return (c >= 0)[0]
def unlabeled_constraint_2(theta, Xd, idx):
wt = theta[0:2].reshape((Xd.shape[1], 1))
c = -(np.dot(Xd[idx], wt) - theta[-1]) + theta[2 + nb_samples:2 + nb_samples + nb_unlabeled ][idx - nb_samples + nb_unlabeled] - 1.0
return (c >= 0)[0]
def eta_constraint(theta, idx):
return theta[2:2 + nb_samples - nb_unlabeled][idx] >= 0
def xi_constraint(theta, idx):
return theta[2 + nb_samples - nb_unlabeled:2 + nb_samples][idx - nb_samples + nb_unlabeled] >= 0
def zi_constraint(theta, idx):
return theta[2 + nb_samples:2 + nb_samples+nb_unlabeled ][idx - nb_samples + nb_unlabeled] >= 0
# 设置问题并进行优化
svm_constraints = []
for i in range(nb_samples - nb_unlabeled):
svm_constraints.append({
'type': 'ineq',
'fun': labeled_constraint,
'args': (X, Y, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': eta_constraint,
'args': (i,)
})
for i in range(nb_samples - nb_unlabeled, nb_samples):
svm_constraints.append({
'type': 'ineq',
'fun': unlabeled_constraint_1,
'args': (X, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': unlabeled_constraint_2,
'args': (X, i)
})
svm_constraints.append({
'type': 'ineq',
'fun': xi_constraint,
'args': (i,)
})
svm_constraints.append({
'type': 'ineq',
'fun': zi_constraint,
'args': (i,)
})
from scipy.optimize import minimize
result = minimize(fun=svm_target,
x0=theta0,
constraints=svm_constraints,
args=(X, Y),
method='SLSQP',
tol=0.0001,
options={'maxiter': 1000})
# 计算无标签点的标签
theta_end = result['x']
w = theta_end[0:2]
b = theta_end[-1]
Xu = X[nb_samples - nb_unlabeled:nb_samples]
yu = -np.sign(np.dot(Xu, w) + b)
```
通过上述代码,我们重新训练了S³VM模型。当CL = 10和CU = 50时,对无标签样本的惩罚增大,可能会使模型更加关注无标签样本的分类准确性。与之前的结果相比,我们可能会看到分类准确率有所提高,对不符合聚类假设的区域分类会更加合理。
#### 不同算法性能对比总结
为了更清晰地对比不同算法在不同参数下的性能,我们可以制作一个表格:
| 算法 | C参数组合 | 分类准确率表现 | 符合聚类假设情况 |
| ---- | ---- | ---- | ---- |
| 标准SVM | C = 1.0 | 基本符合预期,但在特定区域不符合聚类假设 | 部分不符合 |
| S³VM | CL = 10, CU = 5 | 分类准确率较低,对无标签样本惩罚低 | 较差 |
| S³VM | CL = 10, CU = 50 | 可能提高分类准确率,更关注无标签样本 | 可能更好 |
从这个表格中,我们可以直观地看到不同算法和参数组合的优缺点。在实际应用中,我们可以根据数据集的特点(如标签样本和无标签样本的比例、数据的分布等)来选择合适的算法和参数。
#### 半监督学习的应用场景和注意事项
半监督学习方法在很多实际场景中都有应用,以下是一些常见的场景:
- **图像分类**:在图像数据中,标注大量的图像是非常耗时和昂贵的。半监督学习可以利用少量标注图像和大量未标注图像来提高分类准确率。例如,在识别不同种类的动物图像时,我们只需要标注一部分图像,就可以借助半监督学习算法对其他未标注图像进行分类。
- **文本分类**:对于大量的文本数据,如新闻文章、评论等,标注工作也很繁重。半监督学习可以帮助我们利用少量标注文本和大量未标注文本进行分类,如将新闻文章分为政治、经济、娱乐等类别。
- **生物信息学**:在基因序列分析、蛋白质结构预测等生物信息学领域,获取标注数据的成本很高。半监督学习可以利用少量已知的生物信息和大量未标注的生物数据来进行分析和预测。
在使用半监督学习方法时,也有一些注意事项:
- **数据比例**:如前文所述,有标签和无标签样本的比例对算法的性能有很大影响。在选择算法和调整参数时,需要考虑这个比例。当无标签样本占比很大时,可能更适合使用半监督学习算法;当有标签样本足够多时,有监督学习算法可能表现更好。
- **算法选择**:不同的半监督学习算法有不同的特点和适用范围。例如,S³VM计算成本高,但在某些情况下能取得较好的结果;TSVM在测试集大且训练集相对小时表现更好。需要根据具体问题选择合适的算法。
- **参数调整**:算法中的参数(如C值)对模型的性能有重要影响。需要通过实验和调优来找到最优的参数组合,以达到最佳的分类效果。
#### 总结
半监督学习结合了有监督学习和无监督学习的优点,能够利用少量有标签样本和大量无标签样本进行模型训练,提高模型的性能。本文介绍了基于CPLE算法的半监督解决方案,以及半监督支持向量机(S³VM)和直推式支持向量机(TSVM)的原理和实现。通过不同的示例和代码,我们展示了这些算法在不同场景下的应用和性能表现。
在实际应用中,我们需要根据数据集的特点和问题的需求选择合适的算法和参数。同时,要注意数据比例、算法选择和参数调整等方面的问题,以充分发挥半监督学习的优势。希望本文能够帮助读者更好地理解和应用半监督学习方法。
```mermaid
graph LR
A[选择数据集] --> B{有标签/无标签比例}
B -->|比例低| C[有监督学习可能更好]
B -->|比例约为1.0| D[半监督学习优势大]
B -->|比例高| E[接近纯聚类场景]
D --> F{选择算法}
F --> G[S³VM]
F --> H[TSVM]
G --> I[调整参数(如CL, CU)]
H --> J[调整参数(如C_labeled, C_unlabeled)]
I --> K[训练模型]
J --> K
K --> L[评估性能]
L --> M{性能是否满意}
M -->|否| I
M -->|是| N[应用模型]
```
这个流程图展示了在实际应用中使用半监督学习的一般流程。首先根据数据集的有标签和无标签样本比例选择合适的学习方式,然后选择算法,调整参数,训练模型,评估性能,最后根据性能决定是否继续调整参数或应用模型。通过这样的流程,可以更系统地使用半监督学习方法解决实际问题。
0
0
复制全文
相关推荐









