#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;
}