我想在分类器中包含多个特征,以更好地提升模型性能。我有一个类似于下面的数据集
文本 | 是否为大写? | 是否全大写? | 是否包含数字? | 标签 |
---|---|---|---|---|
an example of text | 0 | 0 | 0 | 0 |
ANOTHER example of text | 1 | 1 | 0 | 1 |
What’s happening?Let’s talk at 5 | 1 | 0 | 1 | 1 |
我对文本应用了不同的预处理算法(词袋模型、TF-IDF等)。只使用文本列在分类器中是“容易”的,只需选择X= df['Text']
并应用预处理算法。然而,我现在也想包括是否为大写?
和其他变量(除了标签)作为特征,因为我发现它们可能对我的分类器有用。我尝试了以下方法:
X=df[['Text','是否为大写?', '是否全大写?', '是否包含数字?']]y=df['标签']from sklearn.base import TransformerMixinclass DenseTransformer(TransformerMixin): def fit(self, X, y=None, **fit_params): return self def transform(self, X, y=None, **fit_params): return X.todense()from sklearn.pipeline import Pipelinepipeline = Pipeline([ ('vectorizer', CountVectorizer()), ('to_dense', DenseTransformer()), ])transformer = ColumnTransformer([('text', pipeline, '文本')], remainder='passthrough')X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=40)X_train = transformer.fit_transform(X_train)X_test = transformer.transform(X_test)df_train = pd.concat([X_train, y_train], axis=1)df_test = pd.concat([X_test, y_test], axis=1)#逻辑回归logR_pipeline = Pipeline([ ('LogRCV',countV), ('LogR_clf',LogisticRegression()) ])logR_pipeline.fit(df_train['文本'], df_train['标签'])predicted_LogR = logR_pipeline.predict(df_test['文本'])np.mean(predicted_LogR == df_test['标签'])
然而,我得到了以下错误:
TypeError: cannot concatenate object of type ‘<class’scipy.sparse.csr.csr_matrix’>’; only Series and DataFrame objs arevalid
有没有人处理过类似的问题?我该如何修复它?我的目标是将所有特征包含在我的分类器中。
更新:
我也尝试了这个:
from sklearn.base import BaseEstimator,TransformerMixinclass custom_count_v(BaseEstimator,TransformerMixin): def __init__(self,tfidf): self.tfidf = tfidf def fit(self, X, y=None): joined_X = X.apply(lambda x: ' '.join(x), axis=1) self.tfidf.fit(joined_X) return self def transform(self, X): joined_X = X.apply(lambda x: ' '.join(x), axis=1) return self.tfidf.transform(joined_X) count_v = CountVectorizer() clmn = ColumnTransformer([("count", custom_count_v(count_v), ['文本'])],remainder="passthrough")clmn.fit_transform(df)
它没有返回任何错误,但不清楚我是否正确地包含了所有特征,以及我是否需要在训练/测试分割之前或之后这样做。如果您能展示直到应用分类器的步骤,将会非常有帮助:
#逻辑回归logR_pipeline = Pipeline([ ('LogRCV',....), ('LogR_clf',LogisticRegression()) ])logR_pipeline.fit(....)predicted_LogR = logR_pipeline.predict(...)np.mean(predicted_LogR == ...)
其中省略号处应该填入数据框或列(我想这取决于转换和连接的方式),以便更好地了解我所做的步骤和错误。
回答:
您的错误似乎是试图连接数组和序列。
我不熟悉pipeline和columntransformer,所以我可能错了;不过看起来它没有从CountVectorizer中捕获特征名称,因此拥有未标记的数据框没有任何好处:也许您可以坚持使用numpy数组。如果我错了,从np.array到数据框的转换应该足够简单…
所以,您可以这样做:
df_train = np.append( X_train, #这是一个数组 np.array(y_train).reshape(len(y_train),1), #将序列转换为正确形状的numpy数组 axis=1)print(df_train)[[1 0 1 0 0 1 0 1 0 1 1 0 1] [0 1 0 1 1 0 1 0 1 1 0 1 1]]
希望这有帮助(不过正如我所说,我对这些sklearn库不太熟悉…)
编辑
更完整且不使用那些pipeline(我也不确定是否需要这些pipeline);在我的电脑上由于输入数据集的原因失败了,但您可能会在完整数据集上取得更好的效果。
df = pd.DataFrame( [["an example of text", 0, 0, 0, 0], ["ANOTHER example of text", 1, 1, 0, 1], ["What's happening?Let's talk at 5", 1, 0, 1, 1] ], columns=["文本", "是否为大写?", "是否全大写?", "是否包含数字?", "标签"] )X=df[['文本','是否为大写?', '是否全大写?', '是否包含数字?']]y=df['标签']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=40)cv = CountVectorizer()X_train = ( pd.DataFrame( cv.fit_transform(X_train['文本']).toarray(), columns=cv.get_feature_names(), index=X_train.index ) #通过这种方式,您可以将标签/索引保持在数据框格式中 .join(X_train.drop('文本', axis=1)) #添加您之前的'get_dummies'列 )X_test = ( pd.DataFrame( cv.transform(X_test['文本']).toarray(), columns=cv.get_feature_names(), index=X_test.index ) .join(X_test.drop('文本', axis=1)) )#然后直接计算您的回归:lr = LogisticRegression()lr = lr.fit(X_train, y_train)y_pred = lr.predict(X_test)