C++代码实现MATLAB中的normalize函数功能

cpp 复制代码
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <algorithm>
#include <stdexcept>
#include <string>
#include <cassert>

// ============================================================
// 辅助函数
// ============================================================

// 计算算术平均值
double computeMean(const std::vector<double>& v) {
    if (v.empty()) return 0.0;
    double sum = std::accumulate(v.begin(), v.end(), 0.0);
    return sum / static_cast<double>(v.size());
}

// 计算样本标准差(除以 N-1,与 MATLAB normalize 默认行为一致)
double computeStd(const std::vector<double>& v, double mean) {
    if (v.size() < 2) return 0.0;
    double sqSum = 0.0;
    for (double x : v) {
        double diff = x - mean;
        sqSum += diff * diff;
    }
    return std::sqrt(sqSum / static_cast<double>(v.size() - 1));
}

// 计算中位数
double computeMedian(std::vector<double> v) {
    if (v.empty()) return 0.0;
    std::sort(v.begin(), v.end());
    size_t n = v.size();
    if (n % 2 == 0) {
        return (v[n / 2 - 1] + v[n / 2]) / 2.0;
    } else {
        return v[n / 2];
    }
}

// 计算 MAD(中位数绝对偏差)
double computeMAD(const std::vector<double>& v, double median) {
    if (v.empty()) return 0.0;
    std::vector<double> absDev;
    absDev.reserve(v.size());
    for (double x : v) {
        absDev.push_back(std::abs(x - median));
    }
    return computeMedian(absDev);
}

// 计算 L2 范数(欧几里得范数)
double computeNormL2(const std::vector<double>& v) {
    double sqSum = 0.0;
    for (double x : v) {
        sqSum += x * x;
    }
    return std::sqrt(sqSum);
}

// 计算 IQR(四分位距)
double computeIQR(std::vector<double> v) {
    if (v.size() < 2) return 0.0;
    std::sort(v.begin(), v.end());
    size_t n = v.size();
    auto percentile = [&](double p) -> double {
        double idx = p * (static_cast<double>(n) - 1.0);
        size_t lo = static_cast<size_t>(std::floor(idx));
        size_t hi = static_cast<size_t>(std::ceil(idx));
        if (lo == hi) return v[lo];
        double frac = idx - static_cast<double>(lo);
        return v[lo] * (1.0 - frac) + v[hi] * frac;
    };
    return percentile(0.75) - percentile(0.25);
}

// ============================================================
// 核心归一化函数(对一维向量)
// ============================================================

// zscore:中心化为均值 0,缩放为标准差 1
std::vector<double> normalizeZscore(const std::vector<double>& v) {
    double mean = computeMean(v);
    double sd = computeStd(v, mean);
    std::vector<double> result(v.size());
    for (size_t i = 0; i < v.size(); ++i) {
        result[i] = (sd != 0.0) ? (v[i] - mean) / sd : 0.0;
    }
    return result;
}

// norm:按 L2 范数归一化
std::vector<double> normalizeNorm(const std::vector<double>& v) {
    double normVal = computeNormL2(v);
    std::vector<double> result(v.size());
    for (size_t i = 0; i < v.size(); ++i) {
        result[i] = (normVal != 0.0) ? v[i] / normVal : 0.0;
    }
    return result;
}

// range:重缩放到 [0, 1]
std::vector<double> normalizeRange(const std::vector<double>& v) {
    if (v.empty()) return {};
    auto [minIt, maxIt] = std::minmax_element(v.begin(), v.end());
    double minVal = *minIt, maxVal = *maxIt;
    double range = maxVal - minVal;
    std::vector<double> result(v.size());
    for (size_t i = 0; i < v.size(); ++i) {
        result[i] = (range != 0.0) ? (v[i] - minVal) / range : 0.0;
    }
    return result;
}

// medianiqr:中心化为中位数,缩放为 IQR
std::vector<double> normalizeMedianIQR(const std::vector<double>& v) {
    double med = computeMedian(v);
    double iqr = computeIQR(v);
    std::vector<double> result(v.size());
    for (size_t i = 0; i < v.size(); ++i) {
        result[i] = (iqr != 0.0) ? (v[i] - med) / iqr : 0.0;
    }
    return result;
}

// center+scale 通用形式(可自定义中心化值和缩放值)
std::vector<double> normalizeCenterScale(const std::vector<double>& v,
                                          double center, double scale) {
    std::vector<double> result(v.size());
    for (size_t i = 0; i < v.size(); ++i) {
        result[i] = (scale != 0.0) ? (v[i] - center) / scale : 0.0;
    }
    return result;
}

// ============================================================
// 矩阵归一化(按列处理,与 MATLAB normalize(A) 默认行为一致)
// ============================================================

class Matrix {
public:
    size_t rows, cols;
    std::vector<double> data; // 列优先存储

    Matrix(size_t r, size_t c) : rows(r), cols(c), data(r * c, 0.0) {}

    double& operator()(size_t i, size_t j) { return data[i + j * rows]; }
    double operator()(size_t i, size_t j) const { return data[i + j * rows]; }

    // 提取第 j 列
    std::vector<double> getColumn(size_t j) const {
        std::vector<double> col(rows);
        for (size_t i = 0; i < rows; ++i) {
            col[i] = (*this)(i, j);
        }
        return col;
    }

    // 设置第 j 列
    void setColumn(size_t j, const std::vector<double>& col) {
        for (size_t i = 0; i < rows; ++i) {
            (*this)(i, j) = col[i];
        }
    }

    // 提取第 i 行
    std::vector<double> getRow(size_t i) const {
        std::vector<double> row(cols);
        for (size_t j = 0; j < cols; ++j) {
            row[j] = (*this)(i, j);
        }
        return row;
    }

    // 设置第 i 行
    void setRow(size_t i, const std::vector<double>& row) {
        for (size_t j = 0; j < cols; ++j) {
            (*this)(i, j) = row[j];
        }
    }
};

// 按指定维度归一化矩阵
// dim=1: 按列归一化(默认),dim=2: 按行归一化
Matrix normalizeMatrix(const Matrix& A, int dim = 1,
                        const std::string& method = "zscore") {
    Matrix result(A.rows, A.cols);

    if (dim == 1) {
        // 按列处理
        for (size_t j = 0; j < A.cols; ++j) {
            std::vector<double> col = A.getColumn(j);
            std::vector<double> normCol;

            if (method == "zscore") {
                normCol = normalizeZscore(col);
            } else if (method == "norm") {
                normCol = normalizeNorm(col);
            } else if (method == "range") {
                normCol = normalizeRange(col);
            } else if (method == "medianiqr") {
                normCol = normalizeMedianIQR(col);
            } else {
                throw std::invalid_argument("Unknown method: " + method);
            }
            result.setColumn(j, normCol);
        }
    } else if (dim == 2) {
        // 按行处理
        for (size_t i = 0; i < A.rows; ++i) {
            std::vector<double> row = A.getRow(i);
            std::vector<double> normRow;

            if (method == "zscore") {
                normRow = normalizeZscore(row);
            } else if (method == "norm") {
                normRow = normalizeNorm(row);
            } else if (method == "range") {
                normRow = normalizeRange(row);
            } else if (method == "medianiqr") {
                normRow = normalizeMedianIQR(row);
            } else {
                throw std::invalid_argument("Unknown method: " + method);
            }
            result.setRow(i, normRow);
        }
    } else {
        throw std::invalid_argument("dim must be 1 or 2");
    }

    return result;
}

// ============================================================
// 使用示例
// ============================================================

int main() {
    // 示例 1:向量 zscore 归一化(对应 MATLAB: normalize(1:5))
    std::vector<double> v = {1, 2, 3, 4, 5};
    auto n1 = normalizeZscore(v);
    std::cout << "zscore: ";
    for (double x : n1) std::cout << x << " ";
    std::cout << "\n";

    // 示例 2:向量 L2 范数归一化
    auto n2 = normalizeNorm(v);
    std::cout << "norm:   ";
    for (double x : n2) std::cout << x << " ";
    std::cout << "\n";

    // 示例 3:range 归一化到 [0,1]
    auto n3 = normalizeRange(v);
    std::cout << "range:  ";
    for (double x : n3) std::cout << x << " ";
    std::cout << "\n";

    // 示例 4:矩阵按列 zscore 归一化
    Matrix A(3, 3);
    // [8 1 6]
    // [3 5 7]
    // [4 9 2]
    A(0,0)=8; A(0,1)=1; A(0,2)=6;
    A(1,0)=3; A(1,1)=5; A(1,2)=7;
    A(2,0)=4; A(2,1)=9; A(2,2)=2;

    Matrix N = normalizeMatrix(A, 1, "zscore");
    std::cout << "\nMatrix zscore (by column):\n";
    for (size_t i = 0; i < N.rows; ++i) {
        for (size_t j = 0; j < N.cols; ++j) {
            std::cout << N(i, j) << "\t";
        }
        std::cout << "\n";
    }

    // 示例 5:矩阵按行 zscore 归一化
    Matrix N2 = normalizeMatrix(A, 2, "zscore");
    std::cout << "\nMatrix zscore (by row):\n";
    for (size_t i = 0; i < N2.rows; ++i) {
        for (size_t j = 0; j < N2.cols; ++j) {
            std::cout << N2(i, j) << "\t";
        }
        std::cout << "\n";
    }

    return 0;
}
相关推荐
Rain的Java大神之路4 分钟前
LeetCode 21 合并两个有序链表:一道 Easy 题,凭什么刷掉一半候选人?
java·后端·算法
小蒋观天下11 分钟前
太阳能低功耗AI相机专项:AOV值守、唤醒时序、ISP启停时序BUG
深度学习·数码相机·算法·机器学习
Leinwin16 分钟前
Copilot Studio 实战:多模型选择、GitHub Copilot harness 计费与 Copilot Credits 额度管理
开发语言·c#
wenyq719 分钟前
LeetCode 152. Maximum Product Subarray
java·算法·leetcode
余额瞒着我当琳20 分钟前
C++异常,异常的概念,异常抛出与捕获,RAII 和智能指针的设计思路,C++标准库一些指针的使用
java·开发语言·c++·算法
東隅已逝,桑榆非晚22 分钟前
map和set的使用
数据结构·c++·笔记·学习
2601_9707038326 分钟前
除湿机原理研究报告:一台机器在物理上能走多远
大数据·数据结构·算法·数据库架构·推荐算法
信奥卷王27 分钟前
[GESP202312 六级] 工作沟通(含视频)
算法
♡すぎ♡36 分钟前
SWE 的原理解析
算法·计算机图形学·swe