我有一组自定义功能和一组使用矢量器创建的功能,在本例中为TfidfVectorizer。
我所有的自定义特性都是简单的np.array(例如[0,5,4,22,1])。我正在使用StandardScaler来缩放我的所有特性,正如你在我的管道中看到的那样,在我的"自定义管道"之后调用StandardScaler。问题是,是否有方法或需要缩放我在"vectorized_pipeline"中使用的矢量器。在矢量器上应用StandardScaler似乎不起作用(我得到以下错误:"ValueError:无法将稀疏矩阵居中")。
另一个问题是,在我将所有特征加入FeatureUnion后缩放它们是否明智,或者我是否单独缩放它们中的每一个(在我的示例中,通过分别调用"pos_cluster"one_answers"styleic_features"中的缩放器,而不是在它们都加入后调用它),这样做的更好做法是什么?
from sklearn.pipeline import FeatureUnion, Pipeline
from sklearn import feature_selection
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
X = ['I am a sentence', 'an example']
Y = [1, 2]
X_dev = ['another sentence']
inner_scaler = StandardScaler()
# classifier
LinearSVC1 = LinearSVC(tol=1e-4, C = 0.10000000000000001)
# vectorizers
countVecWord = TfidfVectorizer(ngram_range=(1, 3), max_features=2000, analyzer=u'word', sublinear_tf=True, use_idf = True, min_df=2, max_df=0.85, lowercase = True)
countVecWord_tags = TfidfVectorizer(ngram_range=(1, 4), max_features= 1000, analyzer=u'word', min_df=2, max_df=0.85, sublinear_tf=True, use_idf = True, lowercase = False)
pipeline = Pipeline([
('union', FeatureUnion(
transformer_list=[
('vectorized_pipeline', Pipeline([
('union_vectorizer', FeatureUnion([
('stem_text', Pipeline([
('selector', ItemSelector(key='stem_text')),
('stem_tfidf', countVecWord)
])),
('pos_text', Pipeline([
('selector', ItemSelector(key='pos_text')),
('pos_tfidf', countVecWord_tags)
])),
])),
])),
('custom_pipeline', Pipeline([
('custom_features', FeatureUnion([
('pos_cluster', Pipeline([
('selector', ItemSelector(key='pos_text')),
('pos_cluster_inner', pos_cluster)
])),
('stylistic_features', Pipeline([
('selector', ItemSelector(key='raw_text')),
('stylistic_features_inner', stylistic_features)
]))
])),
('inner_scale', inner_scaler)
])),
],
# weight components in FeatureUnion
# n_jobs=6,
transformer_weights={
'vectorized_pipeline': 0.8, # 0.8,
'custom_pipeline': 1.0 # 1.0
},
)),
('clf', classifier),
])
pipeline.fit(X, Y)
y_pred = pipeline.predict(X_dev)
第一件事:
错误"无法将稀疏矩阵居中"
原因很简单——StandardScaler有效地应用了特征转换:
f_i = (f_i - mean(f_i)) / std(f_i)
对于稀疏矩阵,这将导致密集矩阵,因为均值(f_i)将不为零(通常)。在实践中,只有与他们的收入相等的特征最终会为零。Scikit learn不想这样做,因为这是对您的数据的巨大修改,可能会导致代码的其他部分出现故障,占用大量内存等。如何处理?如果你真的想这样做,有两种选择:
- 通过.toarray()加密矩阵,这将需要大量内存,但会给你带来你所期望的结果
- 创建没有均值的StandardScaler,因此安装的
StandardScaler(with_mean = False)
将应用f_i = f_i / std(f_i)
,但会留下稀疏的数据格式
需要鳞片吗
这是另一个问题——通常,缩放(任何形式)只是一种启发式。这不是你必须应用的东西,也不能保证它会有帮助,当你不知道你的数据是什么样子时,这只是一件合理的事情。像tfidf这样的"智能"矢量器实际上已经在做了。idf转换应该创建一种合理的数据缩放。不能保证哪一个会更好,但总的来说,tfidf应该足够了。特别是考虑到它仍然支持稀疏计算,而StandardScaler则不支持。