del*_*onX 9 python classification scikit-learn text-classification multilabel-classification
我正在做多标签分类,我尝试为每个文档预测正确的标签,这是我的代码:
mlb = MultiLabelBinarizer()
X = dataframe['body'].values
y = mlb.fit_transform(dataframe['tag'].values)
classifier = Pipeline([
('vectorizer', CountVectorizer(lowercase=True,
stop_words='english',
max_df = 0.8,
min_df = 10)),
('tfidf', TfidfTransformer()),
('clf', OneVsRestClassifier(LinearSVC()))])
predicted = cross_val_predict(classifier, X, y)
Run Code Online (Sandbox Code Playgroud)
运行我的代码时,我收到多个警告:
UserWarning: Label not :NUMBER: is present in all training examples.
Run Code Online (Sandbox Code Playgroud)
当我打印出预测标签和真实标签时,cca一半的所有文件都有标签为空的预测.
为什么会发生这种情况,是否与在训练运行时打印出的警告有关?我怎样才能避免那些空洞的预测呢?
LinearSVC().
我试过了RandomForestClassifier(),它也给出了空洞的预测.奇怪的是,当我cross_val_predict(classifier, X, y, method='predict_proba')用于预测每个标签的概率而不是二元决策0/1时,每个预测集总是至少有一个标签,给定文档的概率> 0.所以我不知道为什么这个标签没有选择二元决策?或者是以不同于概率的方式评估二元决策?
EDIT02: 我找到了一个老职位,其中OP处理类似的问题.这是同样的情况吗?
为什么会发生这种情况,是否与在训练运行时打印出的警告有关?
问题可能是某些标签仅出现在几个文档中(有关详细信息,请查看此主题).将数据集拆分为train并进行测试以验证模型时,可能会发生训练数据中缺少某些标记的情况.让我们train_indices与训练样本的索引.如果k训练样本中没有出现(索引的)特定标记k,则指标矩阵的第-列中的所有元素y[train_indices]都为零.
我怎样才能避免那些空洞的预测呢?
在上面描述的场景中,分类器将无法可靠地预测k测试文档中的-th标记(在下一段中将详细介绍).因此,您无法信任所做的预测,clf.predict并且您需要自己实现预测功能,例如通过使用此答案中clf.decision_function建议的返回的决策值.
所以我不知道为什么这个标签没有选择二元决策?或者是以不同于概率的方式评估二元决策?
在包含许多标签的数据集中,大多数标签的出现频率相当低.如果将这些低值馈送到二元分类器(即,进行0-1预测的分类器),则分类器极有可能为所有文档上的所有标签选择0.
我找到了一个老职位,其中OP处理类似的问题.这是同样的情况吗?
是的,一点没错.那家伙面临着与你完全相同的问题,他的代码与你的代码非常相似.
演示
为了进一步解释这个问题,我使用模拟数据详细阐述了一个简单的玩具示例.
Q = {'What does the "yield" keyword do in Python?': ['python'],
'What is a metaclass in Python?': ['oop'],
'How do I check whether a file exists using Python?': ['python'],
'How to make a chain of function decorators?': ['python', 'decorator'],
'Using i and j as variables in Matlab': ['matlab', 'naming-conventions'],
'MATLAB: get variable type': ['matlab'],
'Why is MATLAB so fast in matrix multiplication?': ['performance'],
'Is MATLAB OOP slow or am I doing something wrong?': ['matlab-oop'],
}
dataframe = pd.DataFrame({'body': Q.keys(), 'tag': Q.values()})
mlb = MultiLabelBinarizer()
X = dataframe['body'].values
y = mlb.fit_transform(dataframe['tag'].values)
classifier = Pipeline([
('vectorizer', CountVectorizer(lowercase=True,
stop_words='english',
max_df=0.8,
min_df=1)),
('tfidf', TfidfTransformer()),
('clf', OneVsRestClassifier(LinearSVC()))])
Run Code Online (Sandbox Code Playgroud)
请注意我已经设置,min_df=1因为我的数据集比你的小很多.当我运行以下句子时:
predicted = cross_val_predict(classifier, X, y)
Run Code Online (Sandbox Code Playgroud)
我收到一堆警告
C:\...\multiclass.py:76: UserWarning: Label not 4 is present in all training examples.
str(classes[c]))
C:\\multiclass.py:76: UserWarning: Label not 0 is present in all training examples.
str(classes[c]))
C:\...\multiclass.py:76: UserWarning: Label not 3 is present in all training examples.
str(classes[c]))
C:\...\multiclass.py:76: UserWarning: Label not 5 is present in all training examples.
str(classes[c]))
C:\...\multiclass.py:76: UserWarning: Label not 2 is present in all training examples.
str(classes[c]))
Run Code Online (Sandbox Code Playgroud)
以及以下预测:
In [5]: np.set_printoptions(precision=2, threshold=1000)
In [6]: predicted
Out[6]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
Run Code Online (Sandbox Code Playgroud)
条目全部的那些行0表示没有为相应文档预测标签.
解决方法
为了便于分析,让我们手动验证模型,而不是通过cross_val_predict.
import warnings
from sklearn.model_selection import ShuffleSplit
rs = ShuffleSplit(n_splits=1, test_size=.5, random_state=0)
train_indices, test_indices = rs.split(X).next()
with warnings.catch_warnings(record=True) as received_warnings:
warnings.simplefilter("always")
X_train, y_train = X[train_indices], y[train_indices]
X_test, y_test = X[test_indices], y[test_indices]
classifier.fit(X_train, y_train)
predicted_test = classifier.predict(X_test)
for w in received_warnings:
print w.message
Run Code Online (Sandbox Code Playgroud)
当执行上面的代码片段时,会发出两个警告(我使用上下文管理器来确保捕获警告):
Label not 2 is present in all training examples.
Label not 4 is present in all training examples.
Run Code Online (Sandbox Code Playgroud)
这与索引标签的事实一致2,并4从训练样本丢失:
In [40]: y_train
Out[40]:
array([[0, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 1]])
Run Code Online (Sandbox Code Playgroud)
对于某些文档,预测为空(对应于全零的行的文档predicted_test):
In [42]: predicted_test
Out[42]:
array([[0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0]])
Run Code Online (Sandbox Code Playgroud)
要克服这个问题,您可以实现自己的预测函数,如下所示:
def get_best_tags(clf, X, lb, n_tags=3):
decfun = clf.decision_function(X)
best_tags = np.argsort(decfun)[:, :-(n_tags+1): -1]
return lb.classes_[best_tags]
Run Code Online (Sandbox Code Playgroud)
通过这样做,始终为每个文档分配n_tag具有最高置信度分数的标记:
In [59]: mlb.inverse_transform(predicted_test)
Out[59]: [('matlab',), (), (), ('matlab', 'naming-conventions')]
In [60]: get_best_tags(classifier, X_test, mlb)
Out[60]:
array([['matlab', 'oop', 'matlab-oop'],
['oop', 'matlab-oop', 'matlab'],
['oop', 'matlab-oop', 'matlab'],
['matlab', 'naming-conventions', 'oop']], dtype=object)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2425 次 |
| 最近记录: |