main函数

typedef vector<vector<double>> VVec;
typedef vector<double> Vec;

int main() {
    Perceptron P; // 定义一个Perceptron类
    VVec train_csv, test_csv; // VVec表示vector<vector<double>>
    train_csv = P.csv_read("./Mnist/mnist_train.csv"); // 读取训练数据
    test_csv = P.csv_read("./Mnist/mnist_test.csv"); // 读取测试数据
    auto [train_set, label] = P.get_label(train_csv); // 分离训练集及其label
    auto [test_set, test_label] = P.get_label(test_csv); // 分离测试集及其label
    P.train(train_set, label, 30); // 开始训练
    double acc_rate = P.test(test_set, test_label, w, b); // 开始测试,返回正确率
    cout << "acc: " << acc_rate << endl;
}

main函数内代码遵循读取数据、准备数据、开始训练、开始测试、输出结果这一顺序,以下依次实现上述功能。

Perceptron类定义

class Perceptron {
public:
    Vec w; // 权重
    double b = 0; // 偏置
    VVec csv_read(string filename) {} // 读csv
    pair<VVec, Vec> get_label(VVec& data) {} // 获取读取数据中的label项,返回数据集与对应label
    void train(VVec& train_set, Vec& label, int itera) {} // 开始训练
    double test(VVec& test_set, Vec& test_label) {} // 开始测试,输出测试效果

private:
    double mul_vv(Vec& a, Vec& b) {} // 一维向量与一维向量的乘法运算,输出数字
    Vec mul_vd(Vec& a, double b) {} // 一维向量与常数的乘法运算,输出一维向量
    Vec add_vv(Vec& a, Vec& b) {} // 一维向量与一维向量的加法,输出一维向量
};

以上为Perceptron类的大致定义,只需要完成以上函数,就能实现感知机算法。这里使用pair<xx, xx>的写法,是为了输出不同的数据结构,并且接受输出时能使用auto方便拆解。

csv_read

VVec csv_read(string filename) {
    ifstream inFile(filename); // 定义输入数据流
    string lineStr;
    VVec numArray; // 存储所有数值
    while (getline(inFile, lineStr)) { // 开始遍历每一行,存成二维表结构
        stringstream ss(lineStr);
        string str;
        Vec lineArray; // 存储每一行的数值
        while (getline(ss, str, ',')) { // 按照逗号分隔
            lineArray.push_back(stoi(str));
        }
        numArray.push_back(lineArray);
    }
    return numArray;
}