【问题标题】:How to add another feature (length of text) to current bag of words classification? Scikit-learn如何在当前的词袋分类中添加另一个特征(文本长度)? Scikit-学习
【发布时间】:2016-12-31 11:00:38
【问题描述】:

我正在使用词袋对文本进行分类。它运行良好,但我想知道如何添加一个不是单词的功能。

这是我的示例代码。

import numpy as np
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.multiclass import OneVsRestClassifier

X_train = np.array(["new york is a hell of a town",
                    "new york was originally dutch",
                    "new york is also called the big apple",
                    "nyc is nice",
                    "the capital of great britain is london. london is a huge metropolis which has a great many number of people living in it. london is also a very old town with a rich and vibrant cultural history.",
                    "london is in the uk. they speak english there. london is a sprawling big city where it's super easy to get lost and i've got lost many times.",
                    "london is in england, which is a part of great britain. some cool things to check out in london are the museum and buckingham palace.",
                    "london is in great britain. it rains a lot in britain and london's fogs are a constant theme in books based in london, such as sherlock holmes. the weather is really bad there.",])
y_train = [[0],[0],[0],[0],[1],[1],[1],[1]]

X_test = np.array(["it's a nice day in nyc",
                   'i loved the time i spent in london, the weather was great, though there was a nip in the air and i had to wear a jacket.'
                   ])   
target_names = ['Class 1', 'Class 2']

classifier = Pipeline([
    ('vectorizer', CountVectorizer(min_df=1,max_df=2)),
    ('tfidf', TfidfTransformer()),
    ('clf', OneVsRestClassifier(LinearSVC()))])
classifier.fit(X_train, y_train)
predicted = classifier.predict(X_test)
for item, labels in zip(X_test, predicted):
    print '%s => %s' % (item, ', '.join(target_names[x] for x in labels))

现在很明显,关于伦敦的文字往往比关于纽约的文字长得多。如何将文本长度添加为特征? 我是否必须使用另一种分类方式,然后结合两个预测?有没有什么办法可以和词袋一起做呢? 一些示例代码会很棒——我对机器学习和 scikit 学习非常陌生。

【问题讨论】:

标签: python machine-learning scikit-learn classification text-classification


【解决方案1】:

如 cmets 所示,这是 FunctionTransformerFeaturePipelineFeatureUnion 的组合。

import numpy as np
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.svm import LinearSVC
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.multiclass import OneVsRestClassifier
from sklearn.preprocessing import FunctionTransformer

X_train = np.array(["new york is a hell of a town",
                    "new york was originally dutch",
                    "new york is also called the big apple",
                    "nyc is nice",
                    "the capital of great britain is london. london is a huge metropolis which has a great many number of people living in it. london is also a very old town with a rich and vibrant cultural history.",
                    "london is in the uk. they speak english there. london is a sprawling big city where it's super easy to get lost and i've got lost many times.",
                    "london is in england, which is a part of great britain. some cool things to check out in london are the museum and buckingham palace.",
                    "london is in great britain. it rains a lot in britain and london's fogs are a constant theme in books based in london, such as sherlock holmes. the weather is really bad there.",])
y_train = np.array([[0],[0],[0],[0],[1],[1],[1],[1]])

X_test = np.array(["it's a nice day in nyc",
                   'i loved the time i spent in london, the weather was great, though there was a nip in the air and i had to wear a jacket.'
                   ])   
target_names = ['Class 1', 'Class 2']


def get_text_length(x):
    return np.array([len(t) for t in x]).reshape(-1, 1)

classifier = Pipeline([
    ('features', FeatureUnion([
        ('text', Pipeline([
            ('vectorizer', CountVectorizer(min_df=1,max_df=2)),
            ('tfidf', TfidfTransformer()),
        ])),
        ('length', Pipeline([
            ('count', FunctionTransformer(get_text_length, validate=False)),
        ]))
    ])),
    ('clf', OneVsRestClassifier(LinearSVC()))])

classifier.fit(X_train, y_train)
predicted = classifier.predict(X_test)
predicted

这会将文本的长度添加到分类器使用的特征中。

【讨论】:

  • 我想做类似的事情,但是要添加的功能不是文本本身的功能,而是外部的,例如来自 pandas DataFrame 列。我怎么能把它添加到管道中? FunctionTransformer 似乎无法获取插入数据所需的 X_train 的索引。
  • @user1725306 我知道的三个选项。 1。确保新数据与文本的顺序相同(在训练之前拆分列),然后使用 FeatureUnion 将它们连接在一起。 2。使用整个数据框作为输入,但使用来自mlxtend 的 ColumnSelector 在 FeatureUnion 的两个分支中选择文本和附加信息。 3。看看sklearn-pandas,它使 sklearn 具有数据框感知能力。
【解决方案2】:

我假设您要添加的新功能是数字的。这是我的逻辑。首先使用TfidfTransformer 或类似的东西将文本转换为稀疏文本。然后将稀疏表示转换为pandas DataFrame 并添加我认为是数字的新列。最后,您可能希望使用scipy 或您觉得合适的任何其他模块将您的数据框转换回sparse 矩阵。我假设您的数据位于名为datasetpandas DataFrame 中,其中包含'Text Column''Numeric Column'。这是一些代码。

dataset = pd.DataFrame({'Text Column':['Sample Text1','Sample Text2'], 'Numeric Column': [2,1]})
dataset.head()

        Numeric Column   Text Column
0                   2    Sample Text1
1                   1    Sample Text2

from sklearn.feature_extraction.text import TfidfVectorizer, TfidfTransformer
from scipy import sparse

tv = TfidfVectorizer(min_df = 0.05, max_df = 0.5, stop_words = 'english')
X = tv.fit_transform(dataset['Text column'])
vocab = tv.get_feature_names()

X1 = pd.DataFrame(X.toarray(), columns = vocab)
X1['Numeric Column'] = dataset['Numeric Column']


X_sparse = sparse.csr_matrix(X1.values)

最后,你可能想要;

print(X_sparse.shape)
print(X.shape)

确保新列已成功添加。我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2018-10-14
    • 2019-07-13
    • 2017-01-19
    • 2018-02-06
    • 2021-01-01
    • 2016-05-17
    • 2017-06-12
    • 2016-01-24
    • 2012-06-24
    相关资源
    最近更新 更多