改进flow Python分类器并结合功能

改进flow Python分类器并结合功能,python,scikit-learn,text-classification,supervised-learning,multinomial,Python,Scikit Learn,Text Classification,Supervised Learning,Multinomial,我试图创建一个分类器来分类网站。我是第一次这样做,所以这对我来说是全新的。目前,我正在尝试在网页的几个部分(例如标题、文本、标题)上添加一些单词。看起来是这样的: from sklearn.feature_extraction.text import CountVectorizer countvect_text = CountVectorizer(encoding="cp1252", stop_words="english") countvect_title = CountVectorizer(

我试图创建一个分类器来分类网站。我是第一次这样做,所以这对我来说是全新的。目前,我正在尝试在网页的几个部分(例如标题、文本、标题)上添加一些单词。看起来是这样的:

from sklearn.feature_extraction.text import CountVectorizer
countvect_text = CountVectorizer(encoding="cp1252", stop_words="english")
countvect_title = CountVectorizer(encoding="cp1252", stop_words="english")
countvect_headings = CountVectorizer(encoding="cp1252", stop_words="english")

X_tr_text_counts = countvect_text.fit_transform(tr_data['text'])
X_tr_title_counts = countvect_title.fit_transform(tr_data['title'])
X_tr_headings_counts = countvect_headings.fit_transform(tr_data['headings'])

from sklearn.feature_extraction.text import TfidfTransformer

transformer_text = TfidfTransformer(use_idf=True)
transformer_title = TfidfTransformer(use_idf=True)
transformer_headings = TfidfTransformer(use_idf=True)

X_tr_text_tfidf = transformer_text.fit_transform(X_tr_text_counts)
X_tr_title_tfidf = transformer_title.fit_transform(X_tr_title_counts)
X_tr_headings_tfidf = transformer_headings.fit_transform(X_tr_headings_counts)

from sklearn.naive_bayes import MultinomialNB
text_nb = MultinomialNB().fit(X_tr_text_tfidf, tr_data['class'])
title_nb = MultinomialNB().fit(X_tr_title_tfidf, tr_data['class'])
headings_nb = MultinomialNB().fit(X_tr_headings_tfidf, tr_data['class'])

X_te_text_counts = countvect_text.transform(te_data['text'])
X_te_title_counts = countvect_title.transform(te_data['title'])
X_te_headings_counts = countvect_headings.transform(te_data['headings'])

X_te_text_tfidf = transformer_text.transform(X_te_text_counts)
X_te_title_tfidf = transformer_title.transform(X_te_title_counts)
X_te_headings_tfidf = transformer_headings.transform(X_te_headings_counts)

accuracy_text = text_nb.score(X_te_text_tfidf, te_data['class'])
accuracy_title = title_nb.score(X_te_title_tfidf, te_data['class'])
accuracy_headings = headings_nb.score(X_te_headings_tfidf, te_data['class'])
这很好,我得到了预期的准确度。然而,正如您可能已经猜到的,这看起来杂乱无章,而且充满了重复。那么,我的问题是,有没有办法写得更简洁一些?

此外,我不确定如何将这三个特征组合成一个多项式分类器。我尝试将tfidf值列表传递给
多项式nb().fit()
,但显然这是不允许的

或者,也可以向特征添加权重,以便在最终分类器中某些向量的重要性高于其他向量


我想我需要
管道
,但我完全不确定在这种情况下应该如何使用它。

下面的代码片段是简化代码的一种可能方式:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB

cv = CountVectorizer(encoding="cp1252", stop_words="english")
tt = TfidfTransformer(use_idf=True)
mnb = MultinomialNB()

accuracy = {}
for item in ['text', 'title', 'headings']:
    X_tr_counts = cv.fit_transform(tr_data[item])
    X_tr_tfidf = tt.fit_transform(X_tr_counts)
    mnb.fit(X_tr_tfidf, tr_data['class'])
    X_te_counts = cv.transform(te_data[item])
    X_te_tfidf = tt.transform(X_te_counts)
    accuracy[item] = mnb.score(X_te_tfidf, te_data['class'])
分类成功率存储在字典
准确性
中,其中包含键
'text
'title'
'headings'

编辑 正如@Vivek Kumar所指出的,一个更优雅的解决方案——不一定更简单——在于使用管道和功能联盟。这种方法还允许您将所有特征组合到一个模型中,并对从数据集的不同项中提取的特征应用权重因子

首先,我们导入必要的模块

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import FeatureUnion, Pipeline
然后,我们定义一个transformer类(如中所建议)来选择数据集的不同项:

class ItemSelector(BaseEstimator, TransformerMixin):
    def __init__(self, key):
        self.key = key

    def fit(self, foo, bar=None):
        return self

    def transform(self, data_dict):
        return data_dict[self.key]
我们现在准备好定义管道:

pipeline = Pipeline([
  ('features', FeatureUnion(
    transformer_list=[
      ('text_feats', Pipeline([
        ('text_selector', ItemSelector(key='text')),
        ('text_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                            stop_words="english", 
                                            use_idf=True))
        ])),
      ('title_feats', Pipeline([
        ('title_selector', ItemSelector(key='text')),
        ('title_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                             stop_words="english", 
                                             use_idf=True))
        ])),
      ('headings_feats', Pipeline([
        ('headings_selector', ItemSelector(key='text')),
        ('headings_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                                stop_words="english", 
                                                use_idf=True))
        ])),
    ],
    transformer_weights={'text': 0.5,  #change weights as appropriate
                         'title': 0.3,
                         'headings': 0.2}
    )),
  ('classifier', MultinomialNB())
])
最后,我们可以直接对数据进行分类:

pipeline.fit(tr_data, tr_data['class'])
pipeline.score(te_data, te_data['class'])

下面的代码段是简化代码的一种可能方法:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB

cv = CountVectorizer(encoding="cp1252", stop_words="english")
tt = TfidfTransformer(use_idf=True)
mnb = MultinomialNB()

accuracy = {}
for item in ['text', 'title', 'headings']:
    X_tr_counts = cv.fit_transform(tr_data[item])
    X_tr_tfidf = tt.fit_transform(X_tr_counts)
    mnb.fit(X_tr_tfidf, tr_data['class'])
    X_te_counts = cv.transform(te_data[item])
    X_te_tfidf = tt.transform(X_te_counts)
    accuracy[item] = mnb.score(X_te_tfidf, te_data['class'])
分类成功率存储在字典
准确性
中,其中包含键
'text
'title'
'headings'

编辑 正如@Vivek Kumar所指出的,一个更优雅的解决方案——不一定更简单——在于使用管道和功能联盟。这种方法还允许您将所有特征组合到一个模型中,并对从数据集的不同项中提取的特征应用权重因子

首先,我们导入必要的模块

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import FeatureUnion, Pipeline
然后,我们定义一个transformer类(如中所建议)来选择数据集的不同项:

class ItemSelector(BaseEstimator, TransformerMixin):
    def __init__(self, key):
        self.key = key

    def fit(self, foo, bar=None):
        return self

    def transform(self, data_dict):
        return data_dict[self.key]
我们现在准备好定义管道:

pipeline = Pipeline([
  ('features', FeatureUnion(
    transformer_list=[
      ('text_feats', Pipeline([
        ('text_selector', ItemSelector(key='text')),
        ('text_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                            stop_words="english", 
                                            use_idf=True))
        ])),
      ('title_feats', Pipeline([
        ('title_selector', ItemSelector(key='text')),
        ('title_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                             stop_words="english", 
                                             use_idf=True))
        ])),
      ('headings_feats', Pipeline([
        ('headings_selector', ItemSelector(key='text')),
        ('headings_vectorizer', TfidfVectorizer(encoding="cp1252", 
                                                stop_words="english", 
                                                use_idf=True))
        ])),
    ],
    transformer_weights={'text': 0.5,  #change weights as appropriate
                         'title': 0.3,
                         'headings': 0.2}
    )),
  ('classifier', MultinomialNB())
])
最后,我们可以直接对数据进行分类:

pipeline.fit(tr_data, tr_data['class'])
pipeline.score(te_data, te_data['class'])

首先,countvectorier和TfidfTransformer可以通过使用(本质上是两者的组合)删除

第二,TFIDF矢量化器和多项式NB可以组合在一起。 管道依次应用变换列表和最终估计器。在
管道上调用
fit()
时,它会逐个拟合所有变换并变换数据,然后使用最终估计器拟合变换后的数据。当调用
score()
predict()
时,它只在所有转换器上调用
transform()
,在最后一个转换器上调用
score()
predict()

因此,代码如下所示:

from sklearn.pipeline import Pipeline
pipeline = Pipeline([('vectorizer', TfidfVectorizer(encoding="cp1252",
                                                    stop_words="english",
                                                    use_idf=True)), 
                     ('nb', MultinomialNB())])

accuracy={}
for item in ['text', 'title', 'headings']:

    # No need to save the return of fit(), it returns self
    pipeline.fit(tr_data[item], tr_data['class'])

    # Apply transforms, and score with the final estimator
    accuracy[item] = pipeline.score(te_data[item], te_data['class'])
编辑: 编辑以包含所有特征的组合以获得单一精度:

为了综合这些结果,我们可以采用多种方法。一个很容易理解(但又有点混乱)的例子如下:

# Using scipy to concatenate, because tfidfvectorizer returns sparse matrices
from scipy.sparse import hstack

def get_tfidf(tr_data, te_data, columns):

    train = None
    test = None

    tfidfVectorizer = TfidfVectorizer(encoding="cp1252",
                                      stop_words="english",
                                      use_idf=True)
    for item in columns:
        temp_train = tfidfVectorizer.fit_transform(tr_data[item])
        train = hstack((train, temp_train)) if train is not None else temp_train

        temp_test = tfidfVectorizer.transform(te_data[item])
        test = hstack((test , temp_test)) if test is not None else temp_test

    return train, test

train_tfidf, test_tfidf = get_tfidf(tr_data, te_data, ['text', 'title', 'headings']) 

nb = MultinomialNB()
nb.fit(train_tfidf, tr_data['class'])
nb.score(test_tfidf, te_data['class'])
第二种方法(更可取的方法)是将所有这些纳入管道。但由于选择了不同的列(“文本”、“标题”、“标题”)并将结果连接在一起,这并不是那么简单。我们需要为他们使用FeatureUnion。特别是以下示例:

第三,如果您愿意使用其他库,那么从
sklearn
可以简化前面示例中使用的功能联合的使用

如果你想走第二条或第三条路,如果有任何困难,请随时联系


注意:我没有检查代码,但它应该可以工作(少一些语法错误,如果有的话)。将尽快在我的电脑上进行检查。

首先,可以使用(本质上是两者的组合)删除CountVectorier和TfidfTransformer

第二,TFIDF矢量化器和多项式NB可以组合在一起。 管道依次应用变换列表和最终估计器。在
管道上调用
fit()
时,它会逐个拟合所有变换并变换数据,然后使用最终估计器拟合变换后的数据。当调用
score()
predict()
时,它只在所有转换器上调用
transform()
,在最后一个转换器上调用
score()
predict()

因此,代码如下所示:

from sklearn.pipeline import Pipeline
pipeline = Pipeline([('vectorizer', TfidfVectorizer(encoding="cp1252",
                                                    stop_words="english",
                                                    use_idf=True)), 
                     ('nb', MultinomialNB())])

accuracy={}
for item in ['text', 'title', 'headings']:

    # No need to save the return of fit(), it returns self
    pipeline.fit(tr_data[item], tr_data['class'])

    # Apply transforms, and score with the final estimator
    accuracy[item] = pipeline.score(te_data[item], te_data['class'])
编辑: 编辑以包含所有特征的组合以获得单一精度:

为了综合这些结果,我们可以采用多种方法。一个很容易理解(但又有点混乱)的例子如下:

# Using scipy to concatenate, because tfidfvectorizer returns sparse matrices
from scipy.sparse import hstack

def get_tfidf(tr_data, te_data, columns):

    train = None
    test = None

    tfidfVectorizer = TfidfVectorizer(encoding="cp1252",
                                      stop_words="english",
                                      use_idf=True)
    for item in columns:
        temp_train = tfidfVectorizer.fit_transform(tr_data[item])
        train = hstack((train, temp_train)) if train is not None else temp_train

        temp_test = tfidfVectorizer.transform(te_data[item])
        test = hstack((test , temp_test)) if test is not None else temp_test

    return train, test

train_tfidf, test_tfidf = get_tfidf(tr_data, te_data, ['text', 'title', 'headings']) 

nb = MultinomialNB()
nb.fit(train_tfidf, tr_data['class'])
nb.score(test_tfidf, te_data['class'])
第二种方法(更可取的方法)是将所有这些纳入管道。但由于选择了不同的列(“文本”、“标题”、“标题”)并将结果连接在一起,这并不是那么简单。我们需要为他们使用FeatureUnion。特别是以下示例:

第三,如果您愿意使用其他库,那么从
sklearn
可以简化前面示例中使用的功能联合的使用

如果你想走第二条或第三条路,如果有任何疑问,请随时联系