OnVsRestClassifier 给出 0 精度

Posted

技术标签:

【中文标题】OnVsRestClassifier 给出 0 精度【英文标题】:OnVsRestClassifier gives 0 accuracy 【发布时间】:2016-03-21 09:58:32 【问题描述】:

我正在尝试解决多标签分类问题

        from sklearn.preprocessing import MultiLabelBinarizer 

        traindf = pickle.load("traindata.pkl","rb"))
        X = traindf['Col1']
        X=MultiLabelBinarizer().fit_transform(X)

        y = traindf['Col2']
        y= MultiLabelBinarizer().fit_transform(y)

        Xtrain, Xvalidate, ytrain, yvalidate = train_test_split(X, y, test_size=.5)
        from sklearn.linear_model import LogisticRegression

        clf = OneVsRestClassifier(LogisticRegression(penalty='l2', C=0.01)).fit(Xtrain,ytrain)

        print "One vs rest accuracy: %.3f"  % clf.score(Xvalidate,yvalidate)

这样,我总是得到 0 准确度。请指出我做错了什么。我是多标签分类的新手。这是我的数据的样子

Col1                  Col2
asd dfgfg             [1,2,3]
poioi oiopiop         [4]

编辑

感谢您的帮助@lejlot。我想我已经掌握了窍门。这是我尝试过的

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import SGDClassifier 
from sklearn.multiclass import OneVsRestClassifier
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

tdf = pd.read_csv("mul.csv", index_col="DocID",error_bad_lines=False)

print tdf

所以我的输入数据看起来像

DocID   Content           Tags    
1       abc abc abc       [1]
2       asd asd asd       [2]
3       abc abc asd     [1,2]
4       asd asd abc     [1,2]
5       asd abc qwe   [1,2,3]
6       qwe qwe qwe       [3]
7       qwe qwe abc     [1,3]
8       qwe qwe asd     [2,3]

所以这只是我创建的一些测试数据。然后我做

text_clf = Pipeline([
                     ('vect', TfidfVectorizer()),
                     ('clf', SGDClassifier(loss='hinge', penalty='l2',
                                            alpha=1e-3, n_iter=5, random_state=42)),
 ])

t=TfidfVectorizer()
X=t.fit_transform(tdf["Content"]).toarray()
print X

这给了我

[[ 1.          0.          0.        ]
 [ 0.          1.          0.        ]
 [ 0.89442719  0.4472136   0.        ]
 [ 0.4472136   0.89442719  0.        ]
 [ 0.55247146  0.55247146  0.62413987]
 [ 0.          0.          1.        ]
 [ 0.40471905  0.          0.91444108]
 [ 0.          0.40471905  0.91444108]]

然后

y=tdf['Tags']
y=MultiLabelBinarizer().fit_transform(y)

print y

给我

[[0 1 0 0 1 1]
 [0 0 1 0 1 1]
 [1 1 1 0 1 1]
 [1 1 1 0 1 1]
 [1 1 1 1 1 1]
 [0 0 0 1 1 1]
 [1 1 0 1 1 1]
 [1 0 1 1 1 1]]

我想知道为什么有 6 列? 不应该只有 3 个吗? 无论如何,然后我还创建了一个测试数据文件

sdf=pd.read_csv("multest.csv", index_col="DocID",error_bad_lines=False)
print sdf

所以看起来像

DocID  Content        PredTags             
34     abc abc qwe    [1,3]
35     asd abc asd    [1,2]
36     abc abc abc      [1]

我有PredTags 列来检查准确性。所以最后我适合并预测为

clf = OneVsRestClassifier(LogisticRegression(penalty='l2', C=0.01)).fit(X,y)
predicted = clf.predict(t.fit_transform(sdf["Content"]).toarray())
print predicted

这给了我

[[1 1 1 1 1 1]
 [1 1 1 0 1 1]
 [1 1 1 0 1 1]]

现在,我如何知道正在预测哪些标签?如何检查我的 PredTags 列的准确性?

更新

非常感谢@lejlot :) 我也设法获得如下准确性

sdf=pd.read_csv("multest.csv", index_col="DocID",error_bad_lines=False)
print sdf

predicted = clf.predict(t.fit_transform(sdf["Content"]).toarray())
print predicted


ty=sdf["PredTags"]
ty = [map(int, list(_y.replace(',','').replace('[','').replace(']',''))) for _y in ty]

yt=MultiLabelBinarizer().fit_transform(ty)
Xt=t.fit_transform(sdf["Content"]).toarray()

print Xt
print yt
print "One vs rest accuracy: %.3f"  % clf.score(Xt,yt)

我也只需要对测试集预测列进行二值化 :)

【问题讨论】:

这不是您在分类中使用 text 的方式。在继续构建任何模型之前,请阅读有关处理文本的 scikitlearn 手册。 你是说scikit-learn.org/stable/tutorial/text_analytics/… 谢谢,我去看看。但是乍一看,它似乎没有多标签分类的用例。 多标签分类不是问题,您错误地处理了文本。多标签分类(基本形式)只是一组独立的二元分类器,仅此而已。 谢谢大佬,我会努力学习的。 【参考方案1】:

实际的问题是你处理文本的方式,你应该extract some kind of features 并将其用作文本表示。例如,您可以使用 词袋 表示、tfidf 或任何更复杂的方法。

那么现在发生了什么?您在 list of strings 上调用 multilabelbinarizer,因此 scikit-learn 会在列表中创建一组所有可迭代项...导致 set of letters 表示。比如

from sklearn.preprocessing import MultiLabelBinarizer 
X = ['abc cde', 'cde', 'fff']
print MultiLabelBinarizer().fit_transform(X)

给你

array([[1, 1, 1, 1, 1, 1, 0],
       [0, 0, 0, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 0, 1]])

        |  |  |  |  |  |  |
        v  v  v  v  v  v  v

        a  b  _  c  d  e  f

因此分类几乎是不可能的,因为这并没有捕捉到您的文本的任何含义。

例如,您可以进行计数向量化(词袋)

from sklearn.feature_extraction.text import CountVectorizer
print CountVectorizer().fit_transform(X).toarray()

给你

      [[1  1  0]
       [0  1  0]
       [0  0  1]]

        |  |  |
        v  |  v
       abc | fff
           v
          cde

更新

最后,要使用标签而不是二值化进行预测,您需要存储二值化器

labels = MultiLabelBinarizer()
y = labels.fit_transform(y)

以后

clf = OneVsRestClassifier(LogisticRegression(penalty='l2', C=0.01)).fit(X,y)
predicted = clf.predict(t.fit_transform(sdf["Content"]).toarray())
print labels.inverse_transform(predicted)

更新 2

如果你只有三个类,那么向量应该有 3 个元素,你的有 6 个,所以检查你传递的“y”,你的数据可能有一些错误

from sklearn.preprocessing import MultiLabelBinarizer
MultiLabelBinarizer().fit_transform([[1,2], [1], [3], [2]])

给予

array([[1, 1, 0],
       [1, 0, 0],
       [0, 0, 1],
       [0, 1, 0]])

正如预期的那样。

我最好的猜测是您的“标签”也是字符串,因此您实际上调用了

MultiLabelBinarizer().fit_transform(["[1,2]", "[1]", "[3]", "[2]"])

导致

array([[1, 1, 1, 0, 1, 1],
       [0, 1, 0, 0, 1, 1],
       [0, 0, 0, 1, 1, 1],
       [0, 0, 1, 0, 1, 1]])

        |  |  |  |  |  | 
        v  v  v  v  v  v  

        ,  1  2  3  [  ] 

这些是你的 6 节课。三个真实的,2 个“平凡”类“[”和“]”,它们总是存在,还有几乎平凡的类“”,它出现在属于多个类的每个对象。

您应该首先将标签转换为实际列表,例如通过

y = [map(int, list(_y.replace(',','').replace('[','').replace(']',''))) for _y in y]

【讨论】:

所以如果我使用 CountVectorizer().fit_transform(X).toarray() 作为我的 classifier.fit() 的参数,它会起作用吗? 分类不是算法任务,没有“如果我做 X,它会起作用”之类的东西 - 这只是一个,可能需要数千个步骤才能正确完成。这只是可能做某事的最基本的方法。 非常感谢您的帮助。请参阅编辑。我觉得我已经接近解决方案了。如果我错了,请纠正我。真的很感激 完美男人 :) 非常感谢。你真是个好老师!

以上是关于OnVsRestClassifier 给出 0 精度的主要内容,如果未能解决你的问题,请参考以下文章

精LintCode领扣算法问题答案:1891 · 旅行计划

精彻底熟悉Hadoop RPC框架

BZOJ1925: [Sdoi2010]地精部落

算法精解---计数排序

黑苹果_OpenCore_0.8.4各项功能精解

地精排序Gnome Sort