sklearn中带有词袋和附加情感特征的文本分类器

Posted

技术标签:

【中文标题】sklearn中带有词袋和附加情感特征的文本分类器【英文标题】:text classifier with bag of words and additional sentiment feature in sklearn 【发布时间】:2016-05-17 05:21:30 【问题描述】:

我正在尝试构建一个分类器,除了词袋外,它还使用情绪或主题(LDA 结果)等特征。我有一个带有文本和标签的 pandas DataFrame,并且想添加一个情感值(介于 -5 和 5 之间的数字)和 LDA 分析的结果(带有句子主题的字符串)。

我有一个工作包的单词分类器,它使用 sklearn 中的 CountVectorizer 并使用 MultinomialNaiveeBayes 执行分类。

df = pd.DataFrame.from_records(data=data, columns=names)
train, test = train_test_split(
    df,
    train_size=train_ratio,
    random_state=1337
)
train_df = pd.DataFrame(train, columns=names)
test_df = pd.DataFrame(test, columns=names)
vectorizer = CountVectorizer()
train_matrix = vectorizer.fit_transform(train_df['text'])
test_matrix = vectorizer.transform(test_df['text'])
positive_cases_train = (train_df['label'] == 'decision')
positive_cases_test = (test_df['label'] == 'decision')
classifier = MultinomialNB()
classifier.fit(train_matrix, positive_cases_train)

现在的问题是。我怎样才能在词袋技术的基础上将其他特征引入我的分类器?

提前致谢,如果您需要更多信息,我很乐意提供。

编辑:在添加@Guiem 建议的行后,关于新功能的权重的新问题。此编辑添加到该新问题:

我的火车矩阵的形状是(2554, 5286)。奇怪的是,它是这个形状,有没有添加情感列(可能没有正确添加行?)

如果我打印矩阵,我会得到以下输出:

  (0, 322)  0.0917594575712
  (0, 544)  0.196910480455
  (0, 556)  0.235630958238
  (0, 706)  0.137241420774
  (0, 1080) 0.211125349374
  (0, 1404) 0.216326271935
  (0, 1412) 0.191757369869
  (0, 2175) 0.128800602511
  (0, 2176) 0.271268708356
  (0, 2371) 0.123979845513
  (0, 2523) 0.406583720526
  (0, 3328) 0.278476810585
  (0, 3752) 0.203741786877
  (0, 3847) 0.301505063552
  (0, 4098) 0.213653538407
  (0, 4664) 0.0753937554096
  (0, 4676) 0.164498844366
  (0, 4738) 0.0844966331512
  (0, 4814) 0.251572721805
  (0, 5013) 0.201686066537
  (0, 5128) 0.21174469759
  (0, 5135) 0.187485844479
  (1, 291)  0.227264696182
  (1, 322)  0.0718526940442
  (1, 398)  0.118905396285
  : :
  (2553, 3165)  0.0985290985889
  (2553, 3172)  0.134514497354
  (2553, 3217)  0.0716087169489
  (2553, 3241)  0.172404983302
  (2553, 3342)  0.145912701013
  (2553, 3498)  0.149172538211
  (2553, 3772)  0.140598133976
  (2553, 4308)  0.0704700896603
  (2553, 4323)  0.0800039075449
  (2553, 4505)  0.163830579067
  (2553, 4663)  0.0513678549359
  (2553, 4664)  0.0681930862174
  (2553, 4738)  0.114639856277
  (2553, 4855)  0.140598133976
  (2553, 4942)  0.138370066422
  (2553, 4967)  0.143088901589
  (2553, 5001)  0.185244190321
  (2553, 5008)  0.0876615764151
  (2553, 5010)  0.108531807984
  (2553, 5053)  0.136354534152
  (2553, 5104)  0.0928665728295
  (2553, 5148)  0.171292088292
  (2553, 5152)  0.172404983302
  (2553, 5191)  0.104762377866
  (2553, 5265)  0.123712025565

希望对您有所帮助还是您想要其他信息?

【问题讨论】:

您说矩阵大小相同的事实表明添加特征有问题。您确定要插入密集矩阵并且还要打印新的矩阵尺寸吗?否则你是对的,这真的很奇怪大小是一样的。 除此之外,我最近一直在考虑你的问题(是的,你让我参与其中!)我仍然有一个“概念”的疑问。我的意思是,您问如何添加新功能,而我提出了一个可能的解决方案。但是,如果您告诉我这个新功能是,例如,文本样本的情感,从概念上讲,我倾向于说这隐含在样本本身中。所以这有点多余。 除非您以更语义化的方式执行情感分析,以便真正添加新信息。但是,如果情绪基于单词极性(pos,neg),您的 BOW 应该在您的 tf-idf 表示中收集该信息。不知道这对你是否有意义,干杯! 是的,我将新特征添加到密集矩阵中,但之后再次将其转换为稀疏矩阵:dense_matrix = train_matrix.todense() np.insert(dense_matrix, dense_matrix.shape[1], train_df['sentiment'], axis=1 train_matrix = csr_matrix(dense_matrix) 也许你的观点是对的,它隐含在 BOW 中,但这是为了我的论文,我需要按照我的主管的要求做这些实验 :-) 【参考方案1】:

一种选择是将这两个新功能添加到您的 CountVectorizer 矩阵中作为

由于您没有执行任何 tf-idf,因此您的计数矩阵将填充整数,因此您可以将新列编码为 int 值。

您可能需要尝试多种编码,但您可以从以下内容开始:

情绪 [-5,...,5] 转换为 [0,...,10] 带有句子主题的字符串。只需将整数分配给不同的主题('unicorns':0, 'batman':1, ...),您可以保留字典结构来分配整数并避免重复主题。

以防万一您不知道如何将列添加到您的 train_matrix:

dense_matrix = train_matrix.todense() # countvectorizer returns a sparse matrix
np.insert(dense_matrix,dense_matrix.shape[1],[val1,...,valN],axis=1)

请注意,[val1,...,valN] 列需要与 num 具有相同的长度。您正在使用的示例

尽管它不再是严格意义上的词袋(因为并非所有列都代表词频),但只需添加这两列即可添加您想要包含的额外信息。并且朴素贝叶斯分类器认为每个特征对概率的贡献是独立的,所以我们在这里没问题。

更新:更好地使用“one hot”编码器来编码分类特征(http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html)。通过这种方式,您可以通过为新功能分配整数值来防止奇怪的行为(也许您仍然可以使用情绪来做到这一点,因为在从 0 到 10 的情绪等级中,您假设 9 情绪更接近情绪 10 的样本而不是另一个情绪为 0)。但是对于分类特征,您最好进行一次性编码。 因此,假设您有 3 个主题,那么您可以使用相同的添加列技术,现在您必须添加 3 而不是一个 [topic1,topic2,topic3]。这样,如果您有一个属于 topic1 的样本,您会将其编码为 [1 , 0 , 0],如果那是 topic3,您的表示是 [0, 0, 1] (您用 1 标记对应于的列话题)

【讨论】:

非常感谢。还有一个问题:如果我使用 tf-idf 并且浮点情绪介于 -1 和 1 之间,那仍然是在我的训练和测试矩阵中附加一个列的正确方法吗? 我是否可以对 SVC 分类器使用相同的方法,或者那是错误的(SVC 中的功能也是独立的吗?)? 嘿,如果你使用 tf-idf,你可以在 [0,1] 范围内标准化你的情绪。是的,我鼓励您将结果与 SVC 进行比较,无需考虑独立与否,只需将其视为额外功能即可。不过,不要忘记对主题使用热编码。 一个问题,当我添加这些时,我得到完全相同的精确召回率和 fscore,就好像我不使用情绪功能一样。有没有可能这不符合预期,因为所有浮点数都完全相同似乎很奇怪 在为每一列(特征)添加情绪及其值后,您能否打印两个训练样本?你有多少功能?我想在这里看到的是,如果您的新功能在一般示例中几乎不代表任何内容,因此不会改变结果。如果是这样,我们可以想办法对更多特定特征进行加权,对吗?干杯,您的案例提出了非常有趣的问题【参考方案2】:

一种不那么老套的方法是使用 scikit-learn 的 FeatureUnion 并将文本嵌入基本上连接到表格数据嵌入。

查看其他 2 个 SO 问题的答案:

use Featureunion in scikit-learn to combine two pandas columns for tfidf How to add another feature (length of text) to current bag of words classification? Scikit-learn

然后,您可以将 FeatureUnion 的输出作为管道的一部分传递给分类器。

【讨论】:

以上是关于sklearn中带有词袋和附加情感特征的文本分类器的主要内容,如果未能解决你的问题,请参考以下文章

基于朴素贝叶斯分类器的情感分析

词袋模型(新闻文本分类)

sklearn 除了文本之外的其他输入用于文本分类

SciKit One-class SVM 分类器训练时间随着训练数据的大小呈指数增长

情感分析之TF-IDF算法

朴素贝叶斯构建“饥饿站台”豆瓣短评情感分类器