我在 scikit-learn 中使用 Pipeline 将特征缩放与分类器结合起来。这对于逻辑回归很有效,但我很好奇这种方法是否可以有效地推广到更复杂的模型,例如基于树的集成或神经网络。具体来说,这些模型是否需要不同的扩展策略,或者我可以在它们之间一致地应用 StandardScaler 吗?
import numpy as np
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
# Generate sample data
np.random.seed(42)
X = np.random.rand(200, 5) # 200 samples, 5 features
y = np.random.randint(0, 2, 200) # Binary target
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Define pipelines for different models
pipelines = {
'logistic_regression': Pipeline([
('scaler', StandardScaler()),
('classifier', LogisticRegression())
]),
'random_forest': Pipeline([
('scaler', StandardScaler()),
('classifier', RandomForestClassifier())
]),
'neural_network': Pipeline([
('scaler', StandardScaler()),
('classifier', MLPClassifier(max_iter=500))
])
}
# Evaluate each model
for model_name, pipeline in pipelines.items():
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(f"{model_name} Accuracy: {accuracy_score(y_test, y_pred)}")
嗯,决策树以及森林并不真正关心规模。无论如何,他们不对值执行任何计算(仅对它们的分布进行计算。我的意思是,条件中位数、分位数等。但他们从不将它们相加、相乘等。也许除了,当使用树/森林进行定量回归时,在树的叶子内部应用某种插值,但即使如此,它也只是一个插值,无论如何,您正在使用它进行二元分类)。
因此,缩放输入并不会真正伤害他们。只是,没用。由于决策树的质量之一(随机森林的质量较差)是它们是可解释的,因此您失去了这种质量,并且没有获得任何交换(如果决策树说,例如,要授予贷款,您可以使用
if age>70 ⇒ no else if salary > 30000 ⇒ yes else no
进行分类,这是有道理的(您现在甚至可能认为我的标准很奇怪。这可能是真的,但重点是,如果您之前缩放过数据,您可以对此发表意见),这棵树本来是相同的,但是对于缩放,但这将是if age>0.44 ⇒ no else if salary > -0.01 ⇒ else no
,信息量较少。
MLP 另一方面,急需某种缩放(不一定是这个。而是使值模糊地介于 -1 和 1 之间)
逻辑回归,理论上不应该关心,但在实践中,如果数字条件不好,迭代算法可能会失败,所以最好让所有数据大致处于相同的规模。
无论如何,一般来说,sklearn(或其他)不简单地将数据缩放包含在算法中是有原因的。这是因为关于如何扩展不存在通用规则。即使对于给定的算法也不是(除了决策树不关心,您可以将其视为一般规则)。
例如,没有任何内容表明数据的“逻辑”与数据集的分布相同。在我的最后一个示例中,您可能希望将 18 到 100 岁之间的年龄线性映射到 -1,1(0 为 59),即使您的训练数据集中的平均年龄为 35。您可能决定在 -1,1 之间进行非线性映射 - 1 和 1,但使用分布(因此 -1 是最小值,+1 是最大值,0 是中位数,0.5 75% 百分位数,-0.5 25% 百分位数等)。您可以再次使用数据集的分布或人口的分布来做到这一点。
更甚的是,你可能想要使用更多的全局缩放,不是逐一缩放每个特征,而是沿着某个轴(例如,使用PCA)、减少特征等。
因此,尝试使用预定义的缩放器为任何类型的数据和任何类型的算法创建通用管道并没有真正意义。如果是的话,sklearn 已经做到了。