用c语言写精简版的 smo算法
时间: 2024-02-12 10:09:35 浏览: 134
SMO算法源代码 c语言实现
5星 · 资源好评率100%
好的,以下是一个简单的C语言实现的SVM(支持向量机)分类器,使用的是SMO(Sequential Minimal Optimization)算法:
```c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 100 // 样本数
#define DIMENSION 2 // 样本维度
double alpha[N]; // 拉格朗日乘子
double b; // 偏置项
double w[DIMENSION]; // 分类超平面的法向量
double data[N][DIMENSION]; // 样本数据
double label[N]; // 标签
double dot_product(double a[], double b[]) {
double result = 0;
for (int i = 0; i < DIMENSION; i++) {
result += a[i] * b[i];
}
return result;
}
double kernel(double a[], double b[]) {
double dot = dot_product(a, b);
return dot * dot;
}
double error(int i) {
double sum = 0;
for (int j = 0; j < N; j++) {
sum += alpha[j] * label[j] * kernel(data[i], data[j]);
}
return sum + b - label[i];
}
double clip(double alpha, double L, double H) {
if (alpha < L) return L;
if (alpha > H) return H;
return alpha;
}
void train(double C, double tol, int max_iter) {
// 初始化 alpha 和 b
for (int i = 0; i < N; i++) {
alpha[i] = 0;
}
b = 0;
int iter = 0;
while (iter < max_iter) {
int num_changed_alphas = 0;
for (int i = 0; i < N; i++) {
double Ei = error(i);
if ((label[i] * Ei < -tol && alpha[i] < C) || (label[i] * Ei > tol && alpha[i] > 0)) {
// 随机选择一个 j
int j = rand() % N;
while (j == i) {
j = rand() % N;
}
double Ej = error(j);
// 保存旧的 alpha 值
double alpha_i_old = alpha[i];
double alpha_j_old = alpha[j];
// 计算新的 L 和 H
double L, H;
if (label[i] != label[j]) {
L = fmax(0, alpha[j] - alpha[i]);
H = fmin(C, C + alpha[j] - alpha[i]);
} else {
L = fmax(0, alpha[i] + alpha[j] - C);
H = fmin(C, alpha[i] + alpha[j]);
}
if (L == H) continue;
// 计算 eta
double eta = 2 * kernel(data[i], data[j]) - kernel(data[i], data[i]) - kernel(data[j], data[j]);
if (eta >= 0) continue;
// 更新 alpha[j]
alpha[j] -= label[j] * (Ei - Ej) / eta;
alpha[j] = clip(alpha[j], L, H);
if (fabs(alpha[j] - alpha_j_old) < tol) continue;
// 更新 alpha[i]
alpha[i] += label[i] * label[j] * (alpha_j_old - alpha[j]);
// 更新 b
double b1 = b - Ei - label[i] * (alpha[i] - alpha_i_old) * kernel(data[i], data[i]) -
label[j] * (alpha[j] - alpha_j_old) * kernel(data[i], data[j]);
double b2 = b - Ej - label[i] * (alpha[i] - alpha_i_old) * kernel(data[i], data[j]) -
label[j] * (alpha[j] - alpha_j_old) * kernel(data[j], data[j]);
if (alpha[i] > 0 && alpha[i] < C) {
b = b1;
} else if (alpha[j] > 0 && alpha[j] < C) {
b = b2;
} else {
b = (b1 + b2) / 2;
}
num_changed_alphas++;
}
}
iter = (num_changed_alphas == 0) ? iter + 1 : 0;
}
// 计算 w
for (int i = 0; i < DIMENSION; i++) {
w[i] = 0;
for (int j = 0; j < N; j++) {
w[i] += alpha[j] * label[j] * data[j][i];
}
}
}
int predict(double x[]) {
double result = dot_product(w, x) + b;
return (result > 0) ? 1 : -1;
}
int main() {
// 生成样本数据
for (int i = 0; i < N; i++) {
data[i][0] = rand() / (double)RAND_MAX * 2 - 1;
data[i][1] = rand() / (double)RAND_MAX * 2 - 1;
label[i] = (data[i][0] * data[i][0] + data[i][1] * data[i][1] < 0.5) ? 1 : -1;
}
// 训练 SVM
double C = 1.0; // 惩罚参数
double tol = 1e-4; // 精度
int max_iter = 100; // 最大迭代次数
train(C, tol, max_iter);
// 测试 SVM
int correct = 0;
for (int i = 0; i < N; i++) {
if (predict(data[i]) == label[i]) {
correct++;
}
}
printf("Accuracy: %.2f%%\n", (double)correct / N * 100);
return 0;
}
```
这个实现中采用了简单的二维数据进行测试,如果需要使用其他数据集,可以替换掉样本数据的生成部分。同时,为了简化实现,代码中使用了线性核函数,如果需要使用其他核函数,可以替换掉 `kernel` 函数的实现。
阅读全文