1

这是我的代码:

from sklearn.linear_model import SGDClassifier, LogisticRegression
from sklearn.metrics import classification_report, accuracy_score
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.preprocessing import LabelEncoder, MaxAbsScaler
from sklearn.metrics import precision_recall_fscore_support
from sklearn.decomposition import TruncatedSVD
from scipy.sparse import csr_matrix, hstack
import os


sgd_classifier = SGDClassifier(loss='log', penalty='elasticnet', max_iter=30, n_jobs=60, alpha=1e-6, l1_ratio=0.7, class_weight='balanced', random_state=0)


vectorizer = TfidfVectorizer(analyzer="char_wb", ngram_range=(4,4), min_df=10)
X_train = vectorizer.fit_transform(X_text_train.ravel())
X_test = vectorizer.transform(X_text_test.ravel())
print('TF-IDF number of features:', len(vectorizer.get_feature_names()))


scaler = MaxAbsScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)


print('Inputs shape:', X_train.shape)
sgd_classifier.fit(X_train, y_train)
y_predicted = sgd_classifier.predict(X_test)
y_predicted_prob = sgd_classifier.predict_proba(X_test)


results_report = classification_report(y_test, y_predicted, labels=classes_trained, digits=2, output_dict=True)


df_results_report = pd.DataFrame.from_dict(results_report)
pd.set_option('display.max_rows', 300)
print(df_results_report.transpose())

X_text_train & X_text_test 的形状分别为 (2M, 2) 和 (100k, 2)。

他们的第一栏是关于金融交易的描述,一般来说每个描述由5-15个单词组成;所以每行包含大约 5-15 个单词。第二列是一个分类变量,只有与该银行交易相关的银行名称。

我将这两列合并到一个描述中,所以现在 X_text_train 和 X_text_test 分别具有形状 (2M, ) 和 (100k, )。

然后我应用 TF-IDF,现在 X_text_train & X_text_test 的形状分别为 (2M, 50k) 和 (100k, 50k)。

我观察到的是,当第二列上有一个看不见的值(因此合并描述中的新银行名称)时,SGDClassifier 返回一些非常不同且非常随机的预测,而不是如果我完全删除第二列会返回的预测与银行名称。

如果我仅在描述上执行 TF-IDF 并将银行名称单独保留为分类变量,也会发生同样的情况。

为什么会发生这种情况SGDClassifier?是否因为 SGD 以这种随机方式收敛,所以一般来说 SGD 不能很好地处理所有看不见的值?

有趣的是,在 TF-IDF 上,词汇表是预先确定的,因此测试集中的看不见的值在特征中基本上根本不考虑(即所有各自的特征只有 0 作为值),但 SGD 仍然中断。

(我也在 skLearn 的 Github 上发布了这个https://github.com/scikit-learn/scikit-learn/issues/21906

4

1 回答 1

0

X_text_train & X_text_test 的形状分别为 (2M, 2) 和 (100k, 2),在 TF-IDF 之后它们的形状分别为 (2M, 50k) 和 (100k, 50k)。

我不明白:在 scikit-learn 中,文本矢量化器不应该接受 2D 输入。他们期望一个可迭代的str对象:

https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html#sklearn.feature_extraction.text.TfidfVectorizer.fit

所以不可能X_text_train有除 之外的形状(n_documents,)

X_train = vectorizer.fit_transform(X_text_train.ravel())
X_test = vectorizer.transform(X_text_test.ravel())

这对我来说没有任何意义:np.array([["a", "b"], ["c", "d"]], dtype=object).ravel()将返回array(['a', 'b', 'c', 'd'], dtype=object). 因此,这将在X_text_train.

也许您想做类似以下的事情?

X_concat_text_train = [x[0] + " " + x[1] for x in X_text_train]

为什么 SGDClassifier 会发生这种情况?

如果无法访问具有最少合成数据或公开可用数据的最小可重复示例,则实际上不可能准确地回答您的问题。

是否因为 SGD 以这种随机方式收敛,所以一般来说 SGD 不能很好地处理所有看不见的值?

SGDClassifier您可以通过LogisticRegression使用非随机的 LBFGS 求解器替换来自己回答问题。

于 2021-12-20T17:20:18.317 回答