在对文本进行特征化的时候,最常见的是词袋模型。
词袋模型(Bag of Words,简称BoW),即将所有词语装进一个袋子里,每个词语都是独立的,把每一个单词都进行统计,同时计算每个单词出现的次数。也就是说,词袋模型不考虑文本中词与词之间的上下文关系,仅仅考虑所有词的权重,而权重与词在文本中出现的频率有关。
一般来说,词袋模型首先会进行分词,在分词之后,通过统计每个词在文本中出现的次数,我们就可以得到该文本基于词的特征,如果将各个文本样本的这些词与对应的词频放在一起,就是我们常说的向量化。向量化完毕后一般也会使用TF-IDF进行特征的权重修正,再将特征进行标准化。再进行一些其他的特征工程之后,就可以将数据带入机器学习算法进行分类聚类了。但是它只考虑了词频,没有考虑上下文的信息,会有一定局限性。
首先,CountVectorizer
from sklearn.feature_extraction.text import CountVectorizer
corpus = ['我爱 中国','爸爸妈妈妈妈 爱我','爸爸妈妈 爱中国']
vectorizer = CountVectorizer(ngram_range=(1,2))
features = vectorizer.fit_transform(corpus)
print('CountVectorizer:')
print(vectorizer.get_feature_names())
print(vectorizer.vocabulary_)
print(features)
结果如下:
CountVectorizer:
['中国', '我爱', '我爱 中国', '爱中国', '爱我', '爸爸妈妈', '爸爸妈妈 爱中国', '爸爸妈妈妈妈', '爸爸妈妈妈妈 爱我']
{'我爱': 1, '中国': 0, '我爱 中国': 2, '爸爸妈妈妈妈': 7, '爱我': 4, '爸爸妈妈妈妈 爱我': 8, '爸爸妈妈': 5, '爱中国': 3, '爸爸妈妈 爱中国': 6}
(0, 1) 1
(0, 0) 1
(0, 2) 1
(1, 7) 1
(1, 4) 1
(1, 8) 1
(2, 5) 1
(2, 3) 1
(2, 6) 1
TF-IDF 词频-逆向文件频率。再处理文本时,如何将文字转化为模型可以处理的向量呢? TF-IDF 是解决方案之一,字词的重要性与其在文本出现的频率成正比,与其在语料库中出现的频率成反比。
TF 为某个词在文章中出现的次数。为了消除不同文章大小之间的差异,便于不同文章之间的比较,标准化词频:TF = 某个词在文章中出现的总次数/文章的总词数。
IDF为逆文档频率。IDF=log(词料库的文档总数/包含该词的文档数+1) 避免分母为0,所以+1 TF-IDF值 = TF*IDF
# -*- coding: utf-8 -*-
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = ['我爱中国 中国','爸爸妈妈 爱 我','爸爸妈妈 爱 中国']
# corpus = ['我爱中国','爸爸妈妈爱我','爸爸妈妈爱中国']
print("TfidfVectorizer:")
vectorizer = TfidfVectorizer(min_df=1,
norm='l2',
smooth_idf=True,
use_idf=True,
ngram_range=(1, 1))
features = vectorizer.fit_transform(corpus)
print(vectorizer.get_feature_names()) #显示所有文本的词汇,列表类型
print(vectorizer.vocabulary_) #词汇表,字典类型
print(features) #文本矩阵,得到tf-idf矩阵,稀疏矩阵表示法
print(features.shape) #(3, 3)
print(features.toarray()) #.toarray() 是将结果转化为稀疏矩阵
print(features.toarray().sum(axis=0)) #统计每个词在所有文档中的词频
结果如下:
['中国', '我爱中国', '爸爸妈妈']
{'我爱中国': 1, '中国': 0, '爸爸妈妈': 2}
(0, 0) 0.6053485081062916
(0, 1) 0.7959605415681652
(1, 2) 1.0
(2, 2) 0.7071067811865476
(2, 0) 0.7071067811865476
(3, 3)
[[0.60534851 0.79596054 0. ]
[0. 0. 1. ]
[0.70710678 0. 0.70710678]]
[1.31245529 0.79596054 1.70710678]
分类模型1:Count Vectors + RidgeClassifier
导入需要的包
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
# from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
train_df = pd.read_csv('data/train_set.csv', sep='\t')
test_df = pd.read_csv('data/test_a.csv')
vectorizer = CountVectorizer(max_features=5000)
#vectorizer = TfidfVectorizer(ngram_range=(1,3), max_features=5000,smooth_idf=True) # 0.907
train_test = vectorizer.fit_transform(train_df['text'])
train_X,test_X,train_y,test_y = train_test_split(train_test,train_df['label'].values, test_size=0.3)
clf = RidgeClassifier()
clf.fit(train_X, train_y)
del train_df
val_pred = clf.predict(test_X)
print(f1_score(test_y, val_pred, average='macro'))
分类模型2:TF-IDF + RidgeClassifier
import pandas as pd
# from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
train_df = pd.read_csv('data/train_set.csv', sep='\t')
test_df = pd.read_csv('data/test_a.csv')
vectorizer = TfidfVectorizer(ngram_range=(1,3), max_features=5000,smooth_idf=True) # 0.907
train_test = vectorizer.fit_transform(train_df['text'])
train_X,test_X,train_y,test_y = train_test_split(train_test,train_df['label'].values, test_size=0.3)
clf = RidgeClassifier()
clf.fit(train_X, train_y)
del train_df
val_pred = clf.predict(test_X)
print(f1_score(test_y, val_pred, average='macro'))
也正在尝试线性回归、随机森林