1. 引言
在机器学习和数据挖掘中,数据的归一化是非常重要和常见的操作。在数据预处理中,我们通常要将不同属性的特征值统一到同一尺度之下,否则那些取值范围比较大的属性将会对模型训练产生更大的影响,而取值范围较小的属性则可能会被忽略掉。但是在进行C++开发时,由于数据规模很大,并不是所有的数据都能顺利进行归一化。
2. 怎样归一化数据
归一化数据的实现方式主要有两种:离差标准化和标准差标准化。
2.1 离差标准化
离差标准化是将原始数据映射到[0, 1]区间上,这种方法对于数据的分布没有明显的要求,适用于数据的最大值和最小值较为稳定的情况,其公式为:
x_new = (x - x_min) / (x_max - x_min)
x_new:归一化后的数据值
x:原始数据值
x_min:所有样本数据中最小值
x_max:所有样本数据中最大值
离差标准化的代码实现:
double min_val = ...;
double max_val = ...;
double new_min = 0.0;
double new_max = 1.0;
double normalize(double x) {
return (x - min_val) / (max_val - min_val) * (new_max - new_min) + new_min;
}
2.2 标准差标准化
标准差标准化是将原始数据映射到均值为0,标准差为1的正态分布上,这种方法要求原始数据的分布可以近似为高斯分布,公式为:
x_new = (x - mean) / stddev
x_new:归一化后的数据值
x:原始数据值
mean:所有样本数据的平均值
stddev:所有样本数据的标准差
标准差标准化的代码实现:
double mean = ...;
double stddev = ...;
double standardize(double x) {
return (x - mean) / stddev;
}
3. 数据归一化异常问题
这里介绍一下在C++开发中数据归一化可能会遇到的问题以及解决方案:
3.1 内存开销过大
对于大规模的数据,离差标准化和标准差标准化都需要依据数据的全局最值,全局均值和标准差进行归一化操作,会占用大量的内存,导致程序崩溃。
对于这个问题,我们可以采用采样或分批加载的方法来进行数据归一化。例如,可以随机选取一小部分数据进行归一化得到最大值最小值和均值标准差等统计量,然后根据所选的这一小部分数据的统计量,来对所有数据进行归一化操作。以离差标准化为例,代码实现如下:
double min_val = ...;
double max_val = ...;
double new_min = 0.0;
double new_max = 1.0;
double normalize(double x) {
return (x - min_val) / (max_val - min_val) * (new_max - new_min) + new_min;
}
double get_max_val(vector data) {
double max_val = -HUGE_VAL;
for (int i = 0; i < data.size(); i++) {
if (data[i] > max_val) max_val = data[i];
}
return max_val;
}
double get_min_val(vector data) {
double min_val = HUGE_VAL;
for (int i = 0; i < data.size(); i++) {
if (data[i] < min_val) min_val = data[i];
}
return min_val;
}
void normalize_data(vector &data) {
int sample_size = 100; // 采样数据量
int stride = data.size() / sample_size; // 步长
vector<double> sample_data;
for (int i = 0; i < sample_size; i++) {
sample_data.push_back(data[i * stride]);
}
double max_val = get_max_val(sample_data);
double min_val = get_min_val(sample_data);
for (int i = 0; i < data.size(); i++) {
data[i] = normalize(data[i], min_val, max_val);
}
}
3.2 离群值的处理
离群值是指与正常数据分布有较大差异的那些数据,这些数据可能会对模型训练和预测产生负面影响。因此,我们需要对这类数据进行处理。
离差标准化对离群值比较敏感,如果进来一个极端的值,会造成原本在一定范围内的数值归一化之后都分布在一个范围外,这会导致归一化的结果不准确。而标准差标准化则相对较好地解决了这个问题。
在标准差标准化中,数据不再依据全局最值进行映射,而是通过均值和标准差来进行映射的,它是基于样本数据能够反映出总体趋势和特点这一原理,所以对于离群值相较于离差标准化处理得更好。
在C++中,标准差的计算比较困难,我们通常使用Boost.C++提供的math库来求解标准差。
标准差标准化的代码实现如下:
double mean = ...;
double stddev = ...;
double standardize(double x) {
return (x - mean) / stddev;
}
double get_mean(vector<double> data) {
double sum = accumulate(data.begin(), data.end(), 0.0);
return sum / data.size();
}
double get_stddev(vector<double> data) {
double mean = get_mean(data);
double accum = 0.0;
for (int i = 0; i < data.size(); i++) {
accum += (data[i] - mean) * (data[i] - mean);
}
double stdev = sqrt(accum / (data.size() - 1));
return stdev;
}
void standardize_data(vector<double> &data) {
double mean = get_mean(data);
double stddev = get_stddev(data);
for (int i = 0; i < data.size(); i++) {
data[i] = standardize(data[i], mean, stddev);
}
}
4. 结论
数据归一化是机器学习和数据挖掘中非常重要的预处理操作之一。在进行C++开发时,由于数据规模较大,可能会遇到内存开销过大或离群值的处理等问题,我们需要采用采样或分批加载的方法来解决内存开销过大的问题,而对于离群值的处理,则可以使用标准差标准化来实现。