这是我的代码:
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(。
我观察到的是,当第二列上有一个看不见的值(因此合并描述中有一个新的银行名称(时,SGD分类器返回的预测与我完全删除第二列银行名称时返回的预测非常不同,而且非常随机。
如果我只对描述进行TF-IDF,并将银行名称作为分类变量单独保存,也会发生同样的情况。
为什么SGDClassifier
会出现这种情况?是不是SGD通常不能很好地处理所有看不见的值,因为它以这种随机方式收敛?
有趣的是,在TF-IDF上,词汇表是预先确定的,因此在特征中基本上根本不考虑测试集中看不见的值(即所有相应的特征都只有0作为值(,但SGD仍然会中断。
(我也在skLearn的Github上发布了这篇文章https://github.com/scikit-learn/scikit-learn/issues/21906)
X_text_train&X_text_test的形状分别为(2M,2(和(100k,2。
我不明白:在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
中为每个原始行生成2行。
也许你想做以下事情?
X_concat_text_train = [x[0] + " " + x[1] for x in X_text_train]
SGDClassifier为什么会出现这种情况?
如果不能使用最少的合成数据或公开可用的数据访问最少的可复制示例,就不可能准确地回答您的问题。
是不是SGD通常不能很好地处理所有看不见的值,因为它以这种随机方式收敛?
您可以通过将SGDClassifier
替换为使用非随机LBFGS解算器的LogisticRegression
来自行回答此问题。