Skip to main content
 首页 » 编程设计

python之Scikit-learn 脚本给出与教程截然不同的结果,并且在我更改数据帧时给出错误

2025年05月04日13lautakyan007

我正在完成包含此部分的教程:

>>> import numpy as np 
>>> import pandas as pd 
>>> from sklearn.feature_extraction.text import TfidfVectorizer 
>>> from sklearn.linear_model.logistic import LogisticRegression 
>>> from sklearn.cross_validation import train_test_split, cross_val_score 
>>> df = pd.read_csv('data/sms.csv') 
>>> X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['message'], df['label']) 
>>> vectorizer = TfidfVectorizer() 
>>> X_train = vectorizer.fit_transform(X_train_raw) 
>>> X_test = vectorizer.transform(X_test_raw) 
>>> classifier = LogisticRegression() 
>>> classifier.fit(X_train, y_train) 
>>> precisions = cross_val_score(classifier, X_train, y_train, cv=5, scoring='precision') 
>>> print 'Precision', np.mean(precisions), precisions 
>>> recalls = cross_val_score(classifier, X_train, y_train, cv=5, scoring='recall') 
>>> print 'Recalls', np.mean(recalls), recalls 

然后我复制了几处修改:

ddir = (sys.argv[1]) 
df = pd.read_csv(ddir + '/SMSSpamCollection', sep='\t', quoting=csv.QUOTE_NONE, names=["label", "message"]) 
X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['label'], df['message']) 
 
 
vectorizer = TfidfVectorizer() 
X_train = vectorizer.fit_transform(X_train_raw) 
X_test = vectorizer.transform(X_test_raw) 
classifier = LogisticRegression() 
classifier.fit(X_train, y_train) 
 
 
precisions = cross_val_score(classifier, X_train, y_train, cv=5, scoring='precision') 
recalls = cross_val_score(classifier, X_train, y_train, cv=5, scoring='recall') 
 
 
print 'Precision', np.mean(precisions), precisions 
print 'Recalls', np.mean(recalls), recalls 

然而,尽管代码几乎没有差异,但书中的结果比我的要好得多:

书籍:精度 0.992137651822 [ 0.98717949 0.98666667 1. 0.98684211 1. ] 召回 0.677114261885 [0.7 0.67272727 0.6 0.68807339 0.72477064]

我的:精度 0.108435683974 [ 2.33542342e-06 1.22271611e-03 1.68918919e-02 1.97530864e-01 3.26530612e-01] 召回 0.2352210 [20.3530] 370787 0.125 0.44444444 0.57142857]

回过头来看看脚本出了什么问题,我认为是第 18 行:

X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['label'], df['message']) 

是罪魁祸首,并将 (df['label'], df['message']) 更改为 (df['message'], df['label']) 。但这给了我一个错误:

Traceback (most recent call last): 
  File "Chapter4[B-FLGTLG]C[Y-BCPM][G-PAR--[00].py", line 30, in <module> 
    precisions = cross_val_score(classifier, X_train, y_train, cv=5, scoring='precision') 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/cross_validation.py", line 1433, in cross_val_score 
    for train, test in cv) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py", line 800, in __call__ 
    while self.dispatch_one_batch(iterator): 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py", line 658, in dispatch_one_batch 
    self._dispatch(tasks) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py", line 566, in _dispatch 
    job = ImmediateComputeBatch(batch) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py", line 180, in __init__ 
    self.results = batch() 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/externals/joblib/parallel.py", line 72, in __call__ 
    return [func(*args, **kwargs) for func, args, kwargs in self.items] 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/cross_validation.py", line 1550, in _fit_and_score 
    test_score = _score(estimator, X_test, y_test, scorer) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/cross_validation.py", line 1606, in _score 
    score = scorer(estimator, X_test, y_test) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/metrics/scorer.py", line 90, in __call__ 
    **self._kwargs) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/metrics/classification.py", line 1203, in precision_score 
    sample_weight=sample_weight) 
  File "/usr/local/lib/python2.7/dist-packages/sklearn/metrics/classification.py", line 984, in precision_recall_fscore_support 
    (pos_label, present_labels)) 
ValueError: pos_label=1 is not a valid label: array(['ham', 'spam'],  
      dtype='|S4') 

这可能是什么问题?数据在这里:http://archive.ics.uci.edu/ml/datasets/SMS+Spam+Collection以防有人想尝试。

请您参考如下方法:

堆栈跟踪末尾的错误是理解这里发生的事情的关键。

ValueError: pos_label=1 is not a valid label: array(['ham', 'spam'], dtype='|S4')

您正在尝试通过精确度和召回率对您的模型进行评分。回想一下,这些评分方法是根据真阳性、假阳性和假阴性制定的。但是如何sklearn知道什么是积极的,什么是消极的吗?是“火腿”还是“垃圾邮件”?我们需要一种方法来告诉 sklearn我们认为“垃圾邮件”是正面标签,“火腿”是负面标签。根据sklearn文档中,默认情况下精度和召回评分器期望正标签为 1 ,因此 pos_label=1错误信息的一部分。

至少有 3 种方法可以解决此问题。

1。直接从数据源将“ham”和“spam”值编码为 0 和 1,以适应精确度/召回率评分器:

# Map dataframe to encode values and put values into a numpy array 
encoded_labels = df['label'].map(lambda x: 1 if x == 'spam' else 0).values # ham will be 0 and spam will be 1 
 
# Continue as normal 
X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['message'], encoded_labels) 

2。使用 sklearn的内置函数 ( label_binarize ) 将分类数据转换为编码整数,以适应精度/召回评分器:

这会将您的分类数据转换为整数。

# Encode labels 
from sklearn.preprocessing import label_binarize 
encoded_column_vector = label_binarize(df['label'], classes=['ham','spam']) # ham will be 0 and spam will be 1 
encoded_labels = np.ravel(encoded_column_vector) # Reshape array 
 
# Continue as normal 
X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['message'], encoded_labels) 

3. 使用 pos_label 的自定义参数创建记分器对象:

如文档所述,默认情况下精确率和召回率得分为 pos_label 1 的参数,但这可以更改为通知评分员哪个字符串代表正标签。您可以使用 make_scorer 构造具有不同参数的记分器对象。 .

# Start out as you did originally with string labels 
X_train_raw, X_test_raw, y_train, y_test = train_test_split(df['message'], df['label']) 
# Fit classifier as normal ... 
 
 
# Get precision and recall 
from sklearn.metrics import precision_score, recall_score, make_scorer 
# Precision 
precision_scorer = make_scorer(precision_score, pos_label='spam') 
precisions = cross_val_score(classifier, X_train, y_train, cv=5, scoring=precision_scorer) 
print 'Precision', np.mean(precisions), precisions 
 
# Recall 
recall_scorer = make_scorer(recall_score, pos_label='spam') 
recalls = cross_val_score(classifier, X_train, y_train, cv=5, scoring=recall_scorer) 
print 'Recalls', np.mean(recalls), recalls 

在对您的代码进行任何这些更改后,我得到的平均准确率和召回率分数约为 0.990。和 0.704 , 与书上的编号一致。

在所有 3 个选项中,我最推荐 #3,因为它更难出错。