我想将我的数据分为训练集和测试集,是在拆分之前还是之后对数据进行归一化?对于构建预测模型是否有任何影响?
我想将我的数据分为训练集和测试集,是在拆分之前还是之后对数据进行归一化?对于构建预测模型是否有任何影响?
首先,您需要将数据分为训练集和测试集(验证集也可能有用)。
不要忘记,测试数据点代表真实世界的数据。 对解释变量(或预测变量)进行特征归一化(或数据标准化)是一种技术,通过减去均值并除以方差来居中和规范化数据。如果您使用整个数据集的平均值和方差,将向训练解释变量(即平均值和方差)引入未来信息。
因此,您应该在训练数据上执行特征归一化。然后再次对测试实例进行归一化,但这次使用训练解释变量的均值和方差。通过这种方式,我们可以测试和评估模型是否能够很好地推广到新的、未知的数据点。
如需更全面的阅读,请阅读我的文章"Feature Scaling and Normalisation in a nutshell"
例如,假设我们有以下数据:
>>> import numpy as np
>>>
>>> X, y = np.arange(10).reshape((5, 2)), range(5)
其中X
代表我们的特征:
>>> X
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
并且Y
包含对应的标签
>>> list(y)
>>> [0, 1, 2, 3, 4]
步骤1:创建训练/测试集
>>> X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
>>> X_train
[[4 5]
[0 1]
[6 7]]
>>>
>>> X_test
[[2 3]
[8 9]]
>>>
>>> y_train
[2, 0, 3]
>>>
>>> y_test
[1, 4]
步骤 2:规范化训练数据
>>> from sklearn import preprocessing
>>>
>>> normalizer = preprocessing.Normalizer()
>>> normalized_train_X = normalizer.fit_transform(X_train)
>>> normalized_train_X
array([[0.62469505, 0.78086881],
[0. , 1. ],
[0.65079137, 0.7592566 ]])
第三步:规范化测试数据
>>> normalized_test_X = normalizer.transform(X_test)
>>> normalized_test_X
array([[0.5547002 , 0.83205029],
[0.66436384, 0.74740932]])
torchvision.transforms.Normalize
和torch.nn.functional.normalize
。其中之一可用于创建具有平均值为0和标准差为1的输出张量,而另一个则创建具有范数为1的输出。
Normalizer
类的作用Normalizer
类是(2)的一个示例,因为它会对每个观测值(行)进行重新缩放,使得每行的平方和为1。如果一行的平方和等于0,则不进行重新缩放。在Normalizer文档的第一句话中说:
将样本单独归一化为单位范数。
这个简单的测试代码可以验证这个理解:
X = np.arange(10).reshape((5, 2))
normalizer = preprocessing.Normalizer()
normalized_all_X = normalizer.transform(X)
sum_of_squares = np.square(normalized_all_X).sum(1)
print(np.allclose(sum_of_squares,np.ones_like(sum_of_squares)))
这将打印True
,因为结果是一组1,正如文档中所述。
即使其中一些方法只是“传递”方法,标准化程序实现了fit
、transform
和fit_transform
方法。这是为了在预处理方法之间有一致的接口,而不是因为方法的行为需要区分不同的数据分区。
Normalizer
类不会减去列平均值
另一个答案写道:
不要忘记测试数据点代表真实世界的数据。特征归一化(或数据标准化)是一种通过减去平均值并除以方差来居中和规范化数据的技术。
好的,让我们试试这个。使用答案中的代码片段,我们有
X = np.arange(10).reshape((5, 2))
X_train = X[:3]
X_test = X[3:]
normalizer = preprocessing.Normalizer()
normalized_train_X = normalizer.fit_transform(X_train)
column_means_train_X = normalized_train_X.mean(0)
[0.42516214 0.84670847]
n
数字的和 x=[x1,x2,x3,...,xn]
是 S
,这些数字的平均值是 S / n
。然后我们有 sum(x - S/n) = S - n * (S / n) = 0
)。Normalizer
类应用于整个数据集不会改变结果。Normalizer
类完全无关。事实上,Giorgos Myrianthous选择的例子实际上对他们所描述的效果是免疫的。Normalizer
类确实涉及特征的均值,那么我们预期归一化结果将根据包括在训练集中的哪些数据而发生变化。Normalizer
不会减去列平均值。Normalizer
应用于所有数据或仅应用于一些数据对结果没有影响。[[0. 1. ]
[0.5547002 0.83205029]
[0.62469505 0.78086881]]
[[0.65079137 0.7592566 ]
[0.66436384 0.74740932]]
如果我们结合应用,就会得到
[[0. 1. ]
[0.5547002 0.83205029]
[0.62469505 0.78086881]
[0.65079137 0.7592566 ]
[0.66436384 0.74740932]]
唯一的区别是,在第一个情况下,我们有2个数组,这是由于分区造成的。让我们再次确认合并后的数组相同:
normalized_train_X = normalizer.fit_transform(X_train)
normalized_test_X = normalizer.transform(X_test)
normalized_all_X = normalizer.transform(X)
assert np.allclose(np.vstack((normalized_train_X, normalized_test_X)),normalized_all_X )
没有引发任何异常; 它们在数值上是相同的。
但是sklearn的转换器有时是有状态的,因此让我们创建一个新对象,只是为了确保这不是与状态相关的行为。
new_normalizer = preprocessing.Normalizer()
new_normalized_all_X = new_normalizer.fit_transform(X)
assert np.allclose(np.vstack((normalized_train_X, normalized_test_X)),new_normalized_all_X )
Normalizer.fit()
方法是为了在Scikit-Learn中提供这些预处理器的统一API而提供的语法糖 - 如果你查看源代码,它只是一个传递方法。 - Greensticknormalizer = preprocessing.Normalizer().fit(xtrain)
变换
xtrainnorm = normalizer.transform(xtrain)
xtestnorm = normalizer.transform(Xtest)
fit
或 transform
的问题?这个问题没有提到 Python、sklearn 或 Normalizer
。为什么这个答案假定它是关于这个特定类的呢? - Sycorax问自己,如果在分割数据之前或之后进行转换,你的数据是否会有不同。如果正在进行log2
转换,则顺序无关紧要,因为每个值都是独立转换的。如果正在对数据进行缩放和居中处理,则顺序很重要,因为异常值可能会极大地改变最终的分布。这将导致测试集"溢出"并影响训练集,从而可能导致过于乐观的性能指标。
对于R
用户,caret
包可很好处理测试/训练拆分。您可以向train
函数添加参数preProcess = c("scale", "center")
,它将自动将任何转换从训练数据应用到测试数据。
Tl;dr - 如果数据在归一化之前或之后产生了差异,请在拆分之前进行处理。
preprocessing.Normalizer()
时,不使用任何有关训练数据的信息进行transform
。它只需要提供给transform
的数据。 - Sycorax