C++代码实现MATLAB中的removeoutliers函数功能 // removeoutliers.cpp// 对应 MATLAB rmoutliers(A) 的 C 实现 演示程序// 编译: g -stdc17 -O2 -o removeoutliers_demo#includeiostream#includeiomanip#includevector#includealgorithm#includecmath#includenumeric#includestdexcept#includestring/** * 对应 MATLAB rmoutliers(A) 的 C 实现 * 默认方法MAD中位数绝对偏差阈值因子 3 * 支持方法median(MAD)、mean(均值±标准差)、quartiles(四分位数) */classRemoveOutliers{public:// 检测方法enumclassMethod{Median,// 默认MADMean,// 均值 ± 3σQuartiles// 四分位数法};structOptions{Method methodMethod::Median;doublethresholdFactor3.0;// median/mean 默认 3quartiles 默认 1.5booluseScaledMADtrue;// 是否使用换算 MAD乘常数 cintdim1;// 1 按行移除2 按列移除矩阵};structResult{std::vectorstd::vectordoublecleanedData;// 清洗后数据std::vectorbooloutlierMask;// 离群值逻辑掩码展平std::vectorintremovedIndices;// 被移除的行/列索引};public:/** * 对向量或矩阵进行离群值检测与移除 * param data 输入数据二维行×列 * param opts 选项 * return 清洗后的数据及元信息 */staticResultprocess(conststd::vectorstd::vectordoubledata){returnprocess(data,Options{});}staticResultprocess(conststd::vectorstd::vectordoubledata,constOptionsopts){if(data.empty()||data[0].empty())throwstd::invalid_argument(Input data is empty.);constsize_t rowsdata.size();constsize_t colsdata[0].size();// 校验所有行长度一致for(constautorow:data){if(row.size()!cols)throwstd::invalid_argument(Rows have inconsistent lengths.);}Result result;if(opts.dim1){// 按列检测移除整行MATLAB 默认行为resultprocessByColumn(data,opts);}elseif(opts.dim2){// 按行检测移除整列resultprocessByRow(data,opts);}else{throwstd::invalid_argument(dim must be 1 or 2.);}returnresult;}// 核心统计函数 /** * 计算中位数自动排序副本不修改原数据 */staticdoublemedian(std::vectordoublev){if(v.empty())return0.0;size_t nv.size();std::sort(v.begin(),v.end());if(n%21){returnv[n/2];}else{return0.5*(v[n/2-1]v[n/2]);}}/** * 计算换算 MADMedian Absolute Deviation * scaledMAD c * median(|x - median(x)|) * c 1 / (sqrt(2) * erfcinv(3/2)) ≈ 1.482602218505602 */staticdoublescaledMAD(conststd::vectordoubledata){if(data.size()2)return0.0;doublemedmedian(data);std::vectordoubleabsDev;absDev.reserve(data.size());for(doublex:data){absDev.push_back(std::fabs(x-med));}doublerawMADmedian(absDev);// 换算常数 cconstdoublec1.482602218505602;returnc*rawMAD;}/** * 计算算术均值 */staticdoublemean(conststd::vectordoubledata){if(data.empty())return0.0;doublesumstd::accumulate(data.begin(),data.end(),0.0);returnsum/static_castdouble(data.size());}/** * 计算样本标准差无偏估计除以 n-1与 MATLAB std 默认一致 */staticdoublestddev(conststd::vectordoubledata){size_t ndata.size();if(n2)return0.0;doublemmean(data);doublesqSum0.0;for(doublex:data){doubledx-m;sqSumd*d;}returnstd::sqrt(sqSum/static_castdouble(n-1));}/** * 计算指定百分位数线性插值法与 MATLAB prctile 一致 */staticdoublepercentile(std::vectordoublev,doublep){if(v.empty())return0.0;if(p0.0)return*std::min_element(v.begin(),v.end());if(p100.0)return*std::max_element(v.begin(),v.end());std::sort(v.begin(),v.end());doublerank(p/100.0)*(static_castdouble(v.size())-1.0);size_t lostatic_castsize_t(std::floor(rank));size_t histatic_castsize_t(std::ceil(rank));doublefracrank-static_castdouble(lo);if(lohi)returnv[lo];returnv[lo]*(1.0-frac)v[hi]*frac;}private:// 按列处理移除行 staticResultprocessByColumn(conststd::vectorstd::vectordoubledata,constOptionsopts){constsize_t rowsdata.size();constsize_t colsdata[0].size();std::vectorboolrowOutlier(rows,false);// 对每一列独立检测for(size_t j0;jcols;j){std::vectordoublecolData;colData.reserve(rows);for(size_t i0;irows;i)colData.push_back(data[i][j]);std::vectorboolcolMaskdetectOutliers(colData,opts);for(size_t i0;irows;i){if(colMask[i])rowOutlier[i]true;// 任一列检出则移除整行}}// 构建结果Result res;res.outlierMaskrowOutlier;for(size_t i0;irows;i){if(rowOutlier[i]){res.removedIndices.push_back(static_castint(i));}else{res.cleanedData.push_back(data[i]);}}returnres;}// 按行处理移除列 staticResultprocessByRow(conststd::vectorstd::vectordoubledata,constOptionsopts){constsize_t rowsdata.size();constsize_t colsdata[0].size();std::vectorboolcolOutlier(cols,false);for(size_t i0;irows;i){std::vectorboolrowMaskdetectOutliers(data[i],opts);for(size_t j0;jcols;j){if(rowMask[j])colOutlier[j]true;}}Result res;for(size_t i0;irows;i){std::vectordoublenewRow;for(size_t j0;jcols;j){if(!colOutlier[j])newRow.push_back(data[i][j]);}res.cleanedData.push_back(std::move(newRow));}for(size_t j0;jcols;j){if(colOutlier[j])res.removedIndices.push_back(static_castint(j));}res.outlierMaskcolOutlier;returnres;}// 离群值检测核心 staticstd::vectorbooldetectOutliers(conststd::vectordoubledata,constOptionsopts){size_t ndata.size();std::vectorboolmask(n,false);if(n2)returnmask;switch(opts.method){caseMethod::Median:{doublemedmedian(data);doublemadValopts.useScaledMAD?scaledMAD(data):[](){std::vectordoubleabsDev;for(doublex:data)absDev.push_back(std::fabs(x-med));returnmedian(absDev);}();if(madVal0.0)returnmask;// 所有值相同无离群值doublethropts.thresholdFactor*madVal;for(size_t i0;in;i){if(std::fabs(data[i]-med)thr)mask[i]true;}break;}caseMethod::Mean:{doublemmean(data);doublesstddev(data);if(s0.0)returnmask;doublethropts.thresholdFactor*s;for(size_t i0;in;i){if(std::fabs(data[i]-m)thr)mask[i]true;}break;}caseMethod::Quartiles:{doubleq1percentile(data,25.0);doubleq3percentile(data,75.0);doubleiqrq3-q1;doublelowerq1-opts.thresholdFactor*iqr;doubleupperq3opts.thresholdFactor*iqr;for(size_t i0;in;i){if(data[i]lower||data[i]upper)mask[i]true;}break;}}returnmask;}};// 演示主程序 intmain(){// 示例数据含离群值std::vectorstd::vectordoubledata{{1.0,1.0},// 0{34.0,0.0},// 1{35.0,35.0},// 2{35.0,35.0},// 3{33.0,33.0},// 4{34.0,34.0},// 5{160.0,160.0},// 6 离群值{38.0,38.0},// 7{35.0,35.0},// 8{95.0,35.0},// 9 第1列离群{36.0,36.0},// 10{150.0,150.0},// 11 离群值{39.0,39.0},// 12{41.0,41.0},// 13{42.0,40.0},// 14{0.0,0.0},// 15 离群值{200.0,200.0}// 16 离群值};// 默认 MAD 方法autoresultRemoveOutliers::process(data);std::cout 默认 MAD 方法thresholdFactor3\n;std::cout被移除的行索引;for(intidx:result.removedIndices)std::coutidx ;std::cout\n\n清洗后数据\n;for(constautorow:result.cleanedData){for(doublev:row)std::coutstd::setw(6)v ;std::cout\n;}// 均值 ± 3σ 方法RemoveOutliers::Options meanOpt;meanOpt.methodRemoveOutliers::Method::Mean;autoresultMeanRemoveOutliers::process(data,meanOpt);std::cout\n Mean 方法 \n移除行数resultMean.removedIndices.size()\n;// 四分位数方法RemoveOutliers::Options quartOpt;quartOpt.methodRemoveOutliers::Method::Quartiles;quartOpt.thresholdFactor1.5;autoresultQuartRemoveOutliers::process(data,quartOpt);std::cout\n Quartiles 方法1.5×IQR\n移除行数resultQuart.removedIndices.size()\n;return0;}