StandardScaler()执行fit_transform输出全零如何解决
StandardScaler转换单条特征数据结果全为0问题修复
问题复现
使用StandardScaler()对字典格式的单条特征数据做标准化转换时,输出结果全部为0,复现代码如下:
from sklearn.preprocessing import StandardScaler import pandas as pd param ={ "user_id": 22058, "signup_day": 24, "signup_month": 2, "signup_year": 2015, "purchase_day": 18, "purchase_month": 4, "purchase_year": 2015, "purchase_value": 34, "age": 39, "source_Ads": 0, "source_Direct": 0, "source_SEO": 1, "browser_Chrome": 1, "browser_FireFox": 0, "browser_IE": 0, "browser_Opera": 0, "browser_Safari": 0, "sex_F": 0, "sex_M": 1 } new = (pd.Series(param, index=['user_id', 'signup_day', 'signup_month', 'signup_year', 'purchase_day', 'purchase_month', 'purchase_year', 'purchase_value', 'age', 'source_Ads', 'source_Direct', 'source_SEO', 'browser_Chrome', 'browser_FireFox','browser_IE', 'browser_Opera', 'browser_Safari', 'sex_F', 'sex_M'])).values.reshape(1,-1) print(new) scaler = StandardScaler() X_new = scaler.fit_transform(new) print(X_new)
运行输出:
new = [[22058 24 2 2015 18 4 2015 34 39 0 0 1 1 0 0 0 0 0 1]] X_new =[[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
问题原因
- 对仅包含1个样本的输入直接调用
fit_transform()是结果全0的核心原因:StandardScaler的标准化计算逻辑为(特征值 - 特征列均值) / 特征列标准差,当输入只有1条样本时,每个特征列的均值就是当前样本的对应特征值,分子计算结果恒为0,因此所有输出值都是0。 - 缩放器的统计参数(各特征的均值、标准差)必须从完整训练集上拟合得到,在单条待预测样本上重新拟合缩放器,完全违背标准化的逻辑,得到的结果没有实际业务意义。
修复方案
- 训练阶段:在全部训练数据上调用
fit()方法拟合StandardScaler,习得所有特征的均值、标准差参数,拟合完成后可持久化保存缩放器实例,供后续预测阶段复用。 - 预测阶段:处理单条待预测样本时,直接调用已拟合完成的缩放器的
transform()方法完成转换即可,禁止在单条样本上调用fit()或fit_transform()重新拟合参数。
修复后的参考代码:
from sklearn.preprocessing import StandardScaler import pandas as pd import numpy as np # 训练阶段:在全量训练集上拟合缩放器,示例训练集可替换为实际业务训练数据 train_data = np.array([ [22058,24,2,2015,18,4,2015,34,39,0,0,1,1,0,0,0,0,0,1], [12345,12,3,2014,22,5,2015,52,28,1,0,0,0,1,0,0,0,1,0], [34567,5,11,2016,3,1,2016,120,45,0,1,0,0,0,1,0,0,0,1] ]) scaler = StandardScaler() scaler.fit(train_data) # 预测阶段:转换单条待处理样本 param ={ "user_id": 22058, "signup_day": 24, "signup_month": 2, "signup_year": 2015, "purchase_day": 18, "purchase_month": 4, "purchase_year": 2015, "purchase_value": 34, "age": 39, "source_Ads": 0, "source_Direct": 0, "source_SEO": 1, "browser_Chrome": 1, "browser_FireFox": 0, "browser_IE": 0, "browser_Opera": 0, "browser_Safari": 0, "sex_F": 0, "sex_M": 1 } new = (pd.Series(param, index=['user_id', 'signup_day', 'signup_month', 'signup_year', 'purchase_day', 'purchase_month', 'purchase_year', 'purchase_value', 'age', 'source_Ads', 'source_Direct', 'source_SEO', 'browser_Chrome', 'browser_FireFox','browser_IE', 'browser_Opera', 'browser_Safari', 'sex_F', 'sex_M'])).values.reshape(1,-1) # 仅调用transform做转换,不重新拟合 X_new = scaler.transform(new) print(X_new)
额外提示:
user_id这类唯一标识类特征没有数值大小的统计意义,不建议参与标准化计算,这类特征放入缩放逻辑反而会引入无效噪声。
内容的提问来源于stack exchange,提问作者Anastasia_data
相关产品推荐
相关产品推荐

