带有词袋的文本分类器和 sklearn 中的附加情感特征
text classifier with bag of words and additional sentiment feature in sklearn
我正在尝试构建一个分类器,除了词袋之外,它还使用情感或主题(LDA 结果)等功能。我有一个带有文本和标签的 pandas DataFrame,我想添加一个情感值(-5 到 5 之间的数字)和 LDA 分析的结果(一个带有句子主题的字符串)。
我有一个单词分类器的工作包,它使用 sklearn 中的 CountVectorizer 并使用 MultinomialNaiveBayes 执行分类。
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
希望对您有所帮助,或者您还需要其他信息吗?
一种选择是将这两个新特征作为 列.
添加到您的 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 相同。您正在使用的示例
即使它不再是严格意义上的词袋(因为并非所有列都代表词频),只需添加这两列即可添加您想要包含的额外信息。而朴素贝叶斯分类器认为每个特征都独立地贡献概率,所以我们在这里没问题。
Update: better use a 'one hot' encoder to encode categorical features (http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html). This way you prevent weird behavior by assigning integer values to your new features (maybe you can still do that with sentiment, because in a scale of sentiment from 0 to 10 you assume that a 9 sentiment is closer to a sample with sentiment 10 rather than another with sentiment 0). But with categorical features you better do the one-hot encoding.
So let's say you have 3 topics, then you can use same technique of adding columns only now you have to add 3 instead of one [topic1,topic2,topic3]. This way if you have a sample that belongs to topic1, you'll encode this as [1 , 0 , 0], if that's topic3, your representation is [0, 0, 1] (you mark with 1 the column that corresponds to the topic)
一个不那么棘手的方法是使用 scikit-learn 的 FeatureUnion
并基本上将文本嵌入连接到表格数据嵌入。
查看其他 2 个 SO 问题的答案:
- How to add another feature (length of text) to current bag of words classification? Scikit-learn
然后您可以将 FeatureUnion 的输出作为管道的一部分传递到分类器中。
我正在尝试构建一个分类器,除了词袋之外,它还使用情感或主题(LDA 结果)等功能。我有一个带有文本和标签的 pandas DataFrame,我想添加一个情感值(-5 到 5 之间的数字)和 LDA 分析的结果(一个带有句子主题的字符串)。
我有一个单词分类器的工作包,它使用 sklearn 中的 CountVectorizer 并使用 MultinomialNaiveBayes 执行分类。
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
希望对您有所帮助,或者您还需要其他信息吗?
一种选择是将这两个新特征作为 列.
添加到您的 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 相同。您正在使用的示例
即使它不再是严格意义上的词袋(因为并非所有列都代表词频),只需添加这两列即可添加您想要包含的额外信息。而朴素贝叶斯分类器认为每个特征都独立地贡献概率,所以我们在这里没问题。
Update: better use a 'one hot' encoder to encode categorical features (http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html). This way you prevent weird behavior by assigning integer values to your new features (maybe you can still do that with sentiment, because in a scale of sentiment from 0 to 10 you assume that a 9 sentiment is closer to a sample with sentiment 10 rather than another with sentiment 0). But with categorical features you better do the one-hot encoding. So let's say you have 3 topics, then you can use same technique of adding columns only now you have to add 3 instead of one [topic1,topic2,topic3]. This way if you have a sample that belongs to topic1, you'll encode this as [1 , 0 , 0], if that's topic3, your representation is [0, 0, 1] (you mark with 1 the column that corresponds to the topic)
一个不那么棘手的方法是使用 scikit-learn 的 FeatureUnion
并基本上将文本嵌入连接到表格数据嵌入。
查看其他 2 个 SO 问题的答案:
- How to add another feature (length of text) to current bag of words classification? Scikit-learn
然后您可以将 FeatureUnion 的输出作为管道的一部分传递到分类器中。