数据预处理优化、词云和tf-idf
这次换了一个中文的多文件多分类数据集,下面是数据集和代码:
链接:https://pan.baidu.com/s/1dRCS5rCMbq2_lfGkr4vjJw
提取码:ojdl
这里我没有用他文件夹里给的stoplist。
多文件数据集的读入处理
有时候我们的数据集并不是csv文件,而是更加原始的txt文件,而且还可能存储在多个文件中,这也更贴近实际情况,这次用的数据集就是一个多级目录的多文本数据集,测试集和训练集分别存放在test和train文件夹下(他给的stoplist我没用),下面包括四个文件夹(对应四个分类):女性、体育、文学、校园,每个分类下面有多条文本.所以我们首先要把多个文本中的数据一起整合起来:
#读入数据
#文件夹遍历函数:
def getData(path):
lableData=[]
reviewData=[]
#获取分类
lables=os.listdir(path)
#处理每个分类下的文件
for lable in lables:
lablePath=path+'/'+lable
reviews=os.listdir(lablePath)
#获取每条文本
for review in reviews:
reviewPath=lablePath+'/'+review
file= open(reviewPath, 'r', encoding='ansi')
reviewData.append(file.read())
lableData.append(lable)
file.close()
#标签规格化:
le = LabelEncoder()
resultLable=le.fit_transform(lableData)
return reviewData,resultLable
test_Review,testLable=getData('text_classification/test')
train_Review,trainLable=getData('text_classification/train')
这里经常会有博客强调转码的问题——因为文本文件里存的是ansi码,需要转成utf-8,我这里实测在读文件的时候注明encoding='ansi’就可以了,不需要转码。
file= open(reviewPath, 'r', encoding='ansi')
因为中文的句子是连在一起的,所以要用jieba包手动分词:
#中文分词:
def cut(data):
train_word = [jieba.cut(words) for words in data]
train_cut = [' '.join(word) for word in train_word]
return train_cut
testReview=cut(test_Review)
trainReview=cut(train_Review)
词云和数据预处理优化
词云是我们分析数据的一个非常重要的工具:
词云可以用这种直观粗犷的方式显示你所要统计的数据中经常出现的文本,在用词云之前先对每个分类的中出现的词进行整合(由词组成的句子的集合变为词的集合):
#对不同标签的词分别进行统计:
def getLableWord(str):
ar=[]
for i in range(len(trainLable)):
lab=trainLable[i]
rec=trainReview[i]
if (lab==str):
sentence = list(map(lambda x: x.strip() if len(x.strip()) > 0 else None, jieba.cut(rec))) # 每句话里的单词拿出来
for wd in sentence:
if not(wd in stoplist):ar.append(wd)
return ar
List0=getLableWord(0)
List1=getLableWord(1)
List2=getLableWord(2)
List3=getLableWord(3)
然后是用统计得到的各分类的词列表构造词云:
#词云:
def drawCloud(CloudAr):
# 词频统计
word_counts = collections.Counter(CloudAr) # 对分词做词频统计
word_counts_top10 = word_counts.most_common(10) # 获取前10最高频的词
print(word_counts_top10) # 输出检查
# 词频展示
wc = wordcloud.WordCloud(
font_path='C:/Windows/Fonts/simfang.ttf', # 设置字体格式
background_color='white',
max_words=200, # 最多显示词数
max_font_size=100 # 字体最大值
)
wc.generate_from_frequencies(word_counts) # 从字典生成词云
plt.imshow(wc) # 显示词云
plt.axis('off') # 关闭坐标轴
plt.show() # 显示图像
drawCloud(List0)
drawCloud(List1)
drawCloud(List2)
drawCloud(List3)
运行输出长这样:
统计出各分类中出现的高频词汇并打印,有的高频词汇会在各分类中都出现,比如“的”,这就是无效词汇,把他们加到stoplist里作为停止词过滤掉:
topNum=20
Counts0 = collections.Counter(List0) # 对分词做词频统计
Counts0_topN = Counts0.most_common(topNum) # 获取前topNum最高频的词
Counts1 = collections.Counter(List1) # 对分词做词频统计
Counts1_topN = Counts1.most_common(topNum) # 获取前topNum最高频的词
Counts2 = collections.Counter(List2) # 对分词做词频统计
Counts2_topN = Counts2.most_common(topNum) # 获取前topNum最高频的词
Counts3 = collections.Counter(List3) # 对分词做词频统计
Counts3_topN = Counts3.most_common(topNum) # 获取前topNum最高频的词
bagCounts=Counts0+Counts1+Counts2+Counts3
#去除无用词:
for elem0 in Counts0_topN:
for elem1 in Counts1_topN:
for elem2 in Counts2_topN:
for elem3 in Counts3_topN:
if (elem0[0]==elem1[0])and(elem1[0]==elem2[0])and(elem2[0]==elem3[0]):
stoplist.append(elem0[0])
注意这里统计出来的Counts3_topN是键值对的形式:(词汇,次数),所以不能直接用in来判断;in判断比较的是键值对对象相不相等,我们只是要比较键值对里的词汇:
tf-idf
之前我们在把句子转化为句子向量的时候用的都是词袋模型,就是统计所有单词,生成一个包含所有单词的长度为len词袋,之后把每个句子变成一个len维的向量,每一位代表一个词,值为那个词在句子里出现的次数。这样出现次数越多,即越能体现文本特征的向量权值就越大。
但有时候诸如“的”,“在”、“了”之类的词并没有什么意义,出现概率却比较高,于是就出现了tf-idf模型,TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
TFIDF的主要思想是:如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
tf-idf想找出最有个性、最特立独行的特征,所以会抑制高频词的权重,即使有时候高频词只是在同一类中多次出现,其权重也会受到抑制;而且tf-idf还会导致有时候一些“不同寻常”的文本中多次出现、但总出现次数很少的生僻词被误认为是代表词。
我们做特征工程追求的是泛化能力,即寻找能更好的概括整体文本的特征的词汇,与tf-idf追求的结果恰恰相反,所以我们可以看到像alert、script这种在安全从业者看来明显的攻击特征在上面结果中的权值反而很低。
#tf-idf模型:
tv=TfidfVectorizer(stop_words=stoplist)
wordBag=trainReview+testReview
lenTrain = len(trainReview)
tv.fit(wordBag)
#训练集和测试集放在一起处理使词库更大
WordCount = tv.transform(wordBag)
train_count=WordCount[:lenTrain]
test_count=WordCount[lenTrain:]
testCount = test_count.toarray()
trainCount = train_count.toarray()
本例中tf-idf模型就起了反作用,使用tf-idf只跑出了0.885的正确率,而词袋模型则为0.91: