这是我的代码:
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)