【问题标题】:Turning on multi-label classification with NLTK, scikit-learn and OneVsRestClassifier使用 NLTK、scikit-learn 和 OneVsRestClassifier 开启多标签分类
【发布时间】:2016-07-12 04:21:10
【问题描述】:

免责声明:我对 AI、Python、NLTK 和 scikit-learn 还很陌生。

我正在尝试训练分类器将一组文档分类为一组标签。

我正在使用 NLTK 包装器与 scikit-learn 的 OneVsRestClassifier 对话。

training_set = [
    [{"car": True, ...}, "Label 1"],
    [{"car": False, ...}, "Label 2"],
    ...
    [{"car": False, ...}, "Label 1"],
]

ovr = SklearnClassifier(OneVsRestClassifier(MultinomialNB()))
ovr.train(training_set)

这适用于多类分类,分类器尝试仅将文档分类到标签。准确度很好,但我希望分类器为文档分配 0、1 或更多标签。我怎样才能做到这一点?

遗憾的是,documentation 说:

这个策略也可以用于多标签学习,其中一个分类器 用于预测多个标签,例如,通过拟合二维矩阵 如果样本 i 有标签 j,则单元格 [i, j] 为 1,否则为 0。

这对我来说不是很清楚,因为我不熟悉这种语言。我有一种感觉,我必须以这样一种方式来塑造我的训练集,以便分类器能够理解我希望它对我的数据进行多标签分类?如果是,如何?

我尝试在数组中提供标签,如下所示:

training_set = [
    [{"car": True, ...}, ["Label 1"]],
    [{"car": False, ...}, ["Label 2"]],
    ...
    [{"car": False, ...}, ["Label 1"]],
]

这没有按预期工作并引发:

DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().
  y = column_or_1d(y, warn=True)
One-vs-rest accuracy percent: 0.0

【问题讨论】:

    标签: python machine-learning scikit-learn nltk multilabel-classification


    【解决方案1】:

    我通过摆脱 NLTK 到 scikit-learn 适配器并导入 NLTK 模块来帮助我将数据结构转换为可用于 scikit-learn OneVsRestClassifier 的东西来解决这个问题。

    from nltk import compat
    from sklearn.feature_extraction import DictVectorizer
    from sklearn.naive_bayes import MultinomialNB
    from sklearn.multiclass import OneVsRestClassifier
    
    _vectorizer = DictVectorizer(dtype=float, sparse=True)
    
    def prepare_scikit_x_and_y(labeled_featuresets):
        X, y = list(compat.izip(*labeled_featuresets))
        X = _vectorizer.fit_transform(X)
    
        set_of_labels = []
        for label in y:
            set_of_labels.append(set(label))
    
        y = self.mlb.fit_transform(set_of_labels)
    
        return X, y
    
    def train_classifier(labeled_featuresets):
        X, y = prepare_scikit_x_and_y(labeled_featuresets)
        classifier.fit(X, y)
    
    training_set = [
        [{"car": True, ...}, ["Label 1"]],
        [{"car": False, ...}, ["Label 2"]],
        ...
        [{"car": False, ...}, ["Label 1"]],
    ]
    
    
    ovr = OneVsRestClassifier(MultinomialNB())
    ovr.train(training_set)
    

    快乐豆

    【讨论】:

    • 所以我只需要传递矩阵,即training_set?...但这只是一个参数..我们需要clf.fit(X,y)的X,y参数...我需要重塑还是什么?
    【解决方案2】:

    文档想说的是,使用二维矩阵作为目标。所以基本上,你的训练集可以是,

    training_set = [
        [{"car": True, ...}, [is_label_1, is_label_2, is_label_3]],
        [{"car": False, ...}, [is_label_1, is_label_2, is_label_3]],
        ...
        [{"car": False, ...}, [is_label_1, is_label_2, is_label_3]],
    ]
    

    对于特定样本,使用多个标签对其进行训练, 例如对于第一个样本,如果存在标签 1 和标签 3,则将其作为 [1, 0, 1] 传递。

    希望,你的答案很清楚。

    【讨论】:

    • 清除!可悲的是,在我自己知道如何做之后,我看到了你的答案,并不太可悲。还是谢谢你。
    • 所以我只需要传递矩阵,即training_set?...但这只是一个参数..我们需要clf.fit(X,y)的X,y参数...我需要重塑还是什么?
    • 您需要将训练数据矩阵与训练标签一起传递,唯一不同的是,每个条目的训练标签是列表,即 [is_label_1, is_label_2, is_label_3]。
    猜你喜欢
    • 2016-10-17
    • 2017-03-14
    • 2012-11-11
    • 2016-10-16
    • 2014-11-19
    • 2018-04-10
    • 2016-01-24
    • 2013-04-30
    • 2018-06-19
    相关资源
    最近更新 更多