文本分类流程(一)文本分类的大致步骤+数据爬取+数据预处理 您所在的位置:网站首页 中美新闻产品分类的不同 文本分类流程(一)文本分类的大致步骤+数据爬取+数据预处理

文本分类流程(一)文本分类的大致步骤+数据爬取+数据预处理

2023-11-15 06:12| 来源: 网络整理| 查看: 265

文本分类大体被我分为4类,链接如下: 文本分类流程(一)文本分类的大致步骤+数据预处理------毕业论文的纪念 文本分类(二)文本数据数值化,向量化,降维 文本分类(三)–对已经处理好的数据使用KNN、Naive Bayes、SVM分类方法 文本分类(四)–分类好坏的评价

文章目录 代码部分--Github:文本分类的基本步骤:1.数据获取2.数据清洗3.文本数据---->数值向量4.使用分类分方法。5.进行评估 每步的具体做法 + 代码:==1.数据获取====2.数据清洗==

代码部分–Github:

Github

本文主要介绍文本分类的前几个步骤,数据获取+数据清洗 下一个模块文本分类(二)文本数据数值化,向量化会开始讲解文本文本数据到数值数据的过渡,将文本数据转化为数值数据,并且提取转化后的特征,降维,输入到文本分类器中进行训练、测试、评估。

文本分类的基本步骤: 1.数据获取

方法:网页爬虫,使用别人的代码或者自己写代码(GitHub上找有没有你需要的)

2.数据清洗

方法:

去重,去除重复的评论。如果数据抓取的好,则可以不用执行这一步,不过一般得搞一搞,免得有评论刷评的。去除上面得到的空字符串手工标记数据的类别,正类为1,负类为-1去除其他的表情符号(包括表情符号,一些常见的标点符号,特殊的字符),使用正则表达式匹配\W就可以做到(亏我当初还去网上一个个的查找,删除。如果一个评论中只有上一步所表述的符号,则将其全部去除之后会得到一些空的字符串,再像第二步一样,去除所得到的空字符串。删除停用词(自己在CSDN上搜索停用词,复制粘贴到文本txt文档中)。同上,如果去除了只有停用词的字符串,则去除空字符串。去除停用词的字符串之间使用空格来连接,以便以后使用counterVectorizer和TfidfVectorizer将文本数据转化为数值数据。 注意:我将初始的文本数据全部都放进一个列表中,将标记文本的正负类也按照相应的索引放在一个列表中对应存储。每次去除特殊字符或者是停用词得到空字符串时,将原来存有文本的列表comments中的相关元素删除,也要与之对应的class删除。这里一定要记住是哪个index下面的数据被删除了,再将这个Index对应的class也删除。 3.文本数据---->数值向量 4.使用分类分方法。

机器学习相关的:KNN, Naive Bayes, SVM, AdaBoost, 决策树,逻辑回归,神经网络,深度学习。我主要使用的是前三种,各种方法之间进行对比。 简单贴下比较好的算法介绍的相关文章: 机器学习(二)分类算法详解 分类算法总结 聚类算法与分类算法的总结

5.进行评估

方法:主要使用accuracy,precision,recall,f1-score来评价。

每步的具体做法 + 代码: 1.数据获取

开始是自己跟着静觅-Python3网络爬虫开发实战教程这个网站来学习网页爬虫,因为刚刚接触网页原理,很多参数都看不懂。有一种强迫症的存在,就想着要将所有的东西全部学会,跟着他的教程一步步地敲击代码,记笔记,这样做让我感受不到进步,并且需要学习的东西太多,时间紧迫,没有一种抓住重点的感觉。遂将此教程暂时搁置在一边,了解了一下大致讲的什么,之后有需要再过来针对性的学习。最后学习了requests, beautifulsoup, xpath, css, pymysql,json等相关的知识,就没有再继续看了。

前一步的中间接受网友的建议去学习scrapy框架还有xpath,css,将scrapy中文网实验网站的所有能够爬取的都爬取了,还有根据上面所学的知识利用scrapy去爬取豆瓣影评。搞了也差不多有一个星期,当时就觉得自己似乎可以去爬取京东的店铺评论了(现在想想当时咋就那么不自量力呢)。好,有想法我就去做,去使用xpath中学习到的知识去爬取京东的评论,发现在利用F12所看到的内容居然与查看源代码所看见的内容是不一样的。我们能够从前者看见网页中所呈现的所有元素,然而对于后者,我们就只能够从其中看见一些简单的javascript函数,还有一些json字符串。当时我很纳闷啊,怎么是这样的。试了很多次了,还是这样,问别人也不太明白,就简单的将其当作是京东采取的一些反爬虫机制了。

因为时间真的太紧张了,数据获取的工作始终没有进展,于是就开始接受网友的建议直接去GIthub上搜索相关的代码,找到了美团的评论爬取代码,修改了一下,只获取店铺的评论,其他的完全不管,这样将数据以及相应的Index存储到csv文件中。数据获取的工作当时我以为的就是暂时到这个地步就结束了。

借鉴修改所得代码如下:

parse_restaurant_id.py

# -*- coding: utf-8 -*- # __author__ = "zok" [email protected] # Date: 2019-04-17 Python: 3.7 """ 这是上面一个大神的代码,我拿来自己使用的 他的GitHub地址为:https://github.com/wkunzhi/SpiderCrackDemo/tree/master/MeiTuan ------- 创建一个类,获取店铺id使用 在之后餐馆解析时,继承此类,使用getId获取店铺Id """ import requests import json import re import csv # 目标:创建一个类,其中有一个属性,是一个函数,可以提取餐馆的id class ParseId(object): # 设置请求头 def __init__(self): headers = { 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36' } self.urls = self.getUrl() self.headers = headers # 获取这些网页 def getUrl(self): urls = [] for i in range(1,60): urls.append(('https://yituan.com/meishi/c17/pn'+'%s'+"/")%(i)) return urls def getId(self): id_list = [] k = 1 for v in self.urls: html = requests.get(v,headers = self.headers) # 进行正则匹配,寻求店铺id信息 re_info = re.compile(r'\"poiId\":(\d{4,})') id = re_info.findall(html.text)# 获得的是列表 # 想利用writerows将列表添加到csv文件中 for v in id: id_list.append((k,v)) k+=1 # 将店铺ID保存到CSV文件中 with open(r'D:\lagua\study\coding\pythonPractice\meituanComment\poId.csv','w+',newline="") as f: writer = csv.writer(f) writer.writerows(id_list) temp_id = [] for il in id_list: temp_id.append(il[1]) return temp_id

parse_id_comments.py

# -*- coding: utf-8 -*- # __author__ = "zok" [email protected] # Date: 2019-04-17 Python: 3.7 """ 这是上面一个大神的代码,我拿来自己使用的 他的GitHub地址为:https://github.com/wkunzhi/SpiderCrackDemo/tree/master/MeiTuan ------- 目标: 根据店铺获取评论 局限性:一个店铺只能获取10条评论 """ import requests import json import time import csv import sys # 当引用模块和当前模块不再同一个目录下时,要将引入的模块添加进来 from urllib import parse sys.path.append(r'D:\lagua\study\coding\pythonPractice\meituanComment\meituanComment\spiders\parse_restaurant_id.py') from parse_restaurant_id import ParseId # 创造解析类,用来提取用户评论 class ParseComments(object): def __init__(self, shop_id): self.shop_id = shop_id# 从具有这个属性,实例需要有具体的shop_id self.get_data()# 规定类自带的属性 self.coms_ = self.get_data() # 获取数据---从网页上下载数据 def get_data(self): url_code = self.get_originUrl() # 获取原始的url # 我的ssl证书有问题,访问https会出现问题,美团支持http和https,所以最后改为http没有问题 url = 'http://www.meituan.com/meishi/api/poi/getMerchantComment?' params = { # 利用字典传入参数 'platform': '1', 'partner': '126', 'originUrl': url_code, # 是字典中的一个必须的关键url 'riskLevel': '1', 'optimusCode': '1', 'id': self.shop_id, # 从终端传入的商品id 'offset': '0', 'pageSize': '10', 'sortType': '1', } # 加入请求头,模拟浏览器 headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36', } response = requests.get(url=url, params=params, headers=headers) # 获得requests对象,发送网页请求,并且获得响应 data = response.text # 我们所需要分析的数据 self.parse(data) # 交给下面的parse函数解析 return self.parse(data) ## 获得不同商品对应的url def get_originUrl(self): # 获取某个餐馆的具体url----与某一家餐馆一一对应 """编码解码 """ needParse = ('http://www.meituan.com/meishi/' + '%s'+ '/')%self.shop_id return parse.quote_plus(needParse) # quote_plus 函数用加号来代替URL中的空格-----构造某个商品的url # 对某个网页下的数据进行解析,提取出我们所想要的数据 def parse(self, data): """解析数据 """ data_dict = json.loads(data) #是Json格式的数据 将json字符串--->json对象 print('parse is running....') try: coms = [] # 某个店铺的评论,一个店铺会有 10 条 for item in data_dict.get('data').get('comments'): # 获取数据字典中的data数据,data中也含有comments的数据 coms.append(item.get('comment')) except: print('Error!!!!!!!!!!!!!') print('%s'%self.shop_id) return coms # 将从每个店铺中获取到的评论返回,作为类的一个元素可以传到相应实例中 @staticmethod # python返回函数的静态方法,不强制传递参数 # 函数的执行,可以不用创造实例 def parse_time(timeStamp): # 解析时间戳,备用--- """13位 解码时间 """ time_stamp = float(int(timeStamp) / 1000) time_array = time.localtime(time_stamp) return time.strftime("%Y-%m-%d %H:%M:%S", time_array) # 数据已经在另一个文件中被解析,只需要拿出来就可以,不必自己执行函数获取 # 要在ParseId后面加上(),因为这是调用的一个类,需要继承这个类,,之后再继承这个类的属性,执行函数 ids = ParseId().getId() # 创建实例---将数据写进csv文件中 special_shops = [] comments_ = []# 存放所有店铺的coms for shop_id in ids: pc = ParseComments(shop_id) special_shops.append(pc) for v in pc.coms_:# coms是类中的一个变量,在执行parse函数时我返回了,并且将其作为这个类的一个属性,在创建实例时继承了下来 comments_.append(v) """ 这是改变之后的: 在写进文件夹之后直接根据相应的评论长度建立一个index,将它与相应的comments写入到csv文件中 """ # 底下是将数据写入到csv文件中,要指明为utf-8,否则会出现乱码 with open(r'D:\lagua\study\coding\pythonPractice\MT_test.csv', 'w+', encoding='utf-8',newline='') as f: writer = csv.writer(f) to_be_write = [] index_= list(range(len(comments_))) # 序列号 for v1,v2 in zip(index_,comments_):# 将两个列表打包 to_be_write.append([v1,v2]) # 最后得到的是[[1,'a'],[2,'b'],[3,'c']]这样的形式,可以用writerows写进csv文件中 writer.writerows(to_be_write)##### 注意此处写入是用的元组---用元组形式写入,事实上得到的是列表 2.数据清洗

跟我在最开始介绍的差不多。说说我做了哪些尝试吧。我开始的时候是去网上找如何进行数据的预处理,对比自己获取的文本,看看有哪些东西需要删除的,机器不能够识别的全部都删除。这样下来文本基本上就干净了。

在将字符串与其相应的文本评论相对应时,我尝试了一些方法。开始是想要用json来存储数据,将评论的文本作为键,1,-1当作是键值value。去学习了一堆的json字符串转化为字典的方法,如何将字典转化为json格式的数据。最后搞来,学习了一些字典以及json相关的知识,在这个过程中我突然想到其实这些不必这么复杂,直接使用列表将元素相对应也就可以,我对列表掌握的还比较好。

开始的数据我还傻乎乎的每次处理数据先从相应的csv文件中读取,处理完之后再将数据放回csv文件中。不谈及效率,因为我也无法评判效率的高低,就是觉得代码特别臃肿,我将此做法跟一个网友交流一番之后发现这样不好,csv只是一个存储数据的一个文件,数据最开始可以从csv中获取,最后将我们处理好的最终数据存储在csv文件中,这样比较好,不然的话,每次存取很麻烦。

嘿嘿,我就按照他说的来做,在数据处理的过程中将所有的数据都存放在列表中。在这里要注意的是,开始我以为我的数据量过大,有几百k,列表承受不住,其实完全不用担心,列表好着呢,他肚量可大了,尽情地放。

在这里我还学习了一些文本处理的一些编程技巧:将所有数据处理的函数都包装成一个过滤器,将待处理的数据输入处理器中,输出处理完的数据,再接着将这个数据输入到下一个过滤器中。有一种石英砂过滤器的感觉。

列表1---->过滤器1------>列表2------>过滤器2-------…-------->列表n

列表1 过滤器1 列表2 过滤器2 ...

以上的过滤器就可以封装成一个链({过滤器1,过滤器2,…过滤器n}),我们将初始数据输入,将最后要得到的输出返回就可以啦。这就是所谓的包装,哈哈,外面不知道我里面干了啥,特别的神秘,就这样暗悄悄地将数据处理完毕啦,看我多么的神秘,多么的厉害哈哈!

之后查看资料发现在sklearn中就有这样一个模块,对开始的文本数据预处理,转化为数值向量,放进分类器中训练,得到评价指标。这就是sklearn下的pipeline模块。

具体参考资料如下: sklearn 中的 Pipeline 机制 sklearn学习笔记3——pipeline 我也来简单的写一下: 举个简单的例子,使用KNN来进行分类

from sklearn.preprocessing import StandardScaler# 标准化处理 from sklearn.decomposition import PCA from sklearn.pipeline import Pipeline# 管道包 from sklearn.neighbors import KNeighborsClassifier from last_process_2 import noStopWord_comments,noStopWord_class# 我处理得到的评论列表极其对应的类别 import re from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer# 向量化的类 from sklearn.model_selection import train_test_split# 将数据分割为训练集与测试集合 from sklearn import preprocessing# 数据处理使用 # 将开始的字符串用空格隔开---最后得到的是一个列表,里面中的每个元素都是“你 今天 很 好看” 这样的形式,方便使用tfidfVectorizer讲文本数据转化为向量 def get_split(x): temp = [v for v in re.split(' ',x) if v is not ''] return temp def joinData(data_to_join):# 空字符串将文本隔开 temp = [' '.join(x) for x in data_to_join] return temp corpus = joinData([get_split(v) for v in noStopWord_comments]) # 得到的是一个列表 tfidf = TfidfVectorizer()# 创建实例,继承方法 retfidf = tfidf.fit_transform(corpus) # 拟合+转换 input_data_matrix = retfidf.toarray()# 数值矩阵 x_train,x_test,y_train,y_test=train_test_split(input_data_matrix,noStopWord_class,test_size=0.2,random_state=400)# 切割训练数据 pipe_knn = Pipeline([('sc',StandardScaler()),('PCA',PCA(n_components=200)),('clf',KNeighborsClassifier())]) pipe_knn.fit(x_train,y_train)# 拟合+transform数据 print(pipe_knn.score(x_test,y_test))# 得到分类的准确率,即得分 # 0.8073770491803278

第一步处理代码: final_process_1.py

""" 1、去重,作为初始数据处理 2、去空tag【】【】 3、去除空字符串'' 得到我想要的数据,进行人工标记 ———————————————————— """ import csv import re # 将数据全部都存放再一个列表中 class InitialProcess(object): path_initial = r'D:\lagua\study\coding\pythonPractice\DataProcess\MT.csv' # 从美团上获取的初始文本 path_meituan = r'D:\lagua\study\coding\pythonPractice\DataProcess\MeiTuan.csv'# 数据处理第一道得到的index文本 # 去重 def noRepeat(self,x): uni = [] for v in x: if v not in uni: uni.append(v) return uni # 去除只带有标签的评论 def noTags(self,x): def f_replace(x): temp = x.replace('【口味】','').replace('【环境】','').replace('【服务】','').replace('【等位】','').replace('\n','').strip() return temp return [f_replace(v) for v in x] # 将空字符串去掉 def noVocant(self,x): temp = [v for v in x if v is not ''] return temp # 读取之前获取的数据 def getData(self,path): seg_all = [] with open(path,'r',encoding='utf-8') as f: reader = csv.reader(f) for line in reader: seg_all.append(line[1]) print("列表说:我将csv中的数据搞到手啦") return self.noRepeat(seg_all) def get_index(self,x): temp = [i for i,v in enumerate(x) if v==''] return temp # 将文件写进csv文件中 def writeCSV(self,path2,data): with open(path2,'w',encoding='utf-8',newline='') as f: writer = csv.writer(f) for k,v in enumerate(data): writer.writerow([k,v]) def do_thisMethod(self): data = self.getData(self.path_initial)# 获取数据,顺便去重 data_noTag = self.noTags(data)# 去除标签 data_noVocant = self.noVocant(data_noTag) # 去除上一步可能得到的空字符串 self.writeCSV(self.path_meituan,data_noVocant) # 写进文档存储,以后就在这里面提取数据,进一步处理 IniPro = InitialProcess()# 继承类 IniPro.do_thisMethod()# 实例化之后使用类中的方法

去除停用词。 开始我们讲过,我们是直接将从网上获取的一些停用词复制粘贴到txt文档中的。我们去除停用词首先要读取文档中的停用词,将这些汉字词语符号删除。这里这里会遇到一个问题,是有关编码的,我们一般的汉字存储是ASNI格式,我们要用python读取,需要将数据转化为unicode格式。

具体这样做:将我们开始保存的txt文本另存为一个txt文件,在这时,你可以看见相关页面中有选择编码的格式,自己选择为unicode格式即可,之后就读取这个文件中的停用词。

在读取文本的时候还有一点需要注意:

def stopwordslist(): # 返回列表 with open(path_stop,'r',encoding='utf-8', errors='ignore') as f: stopwords = [line.strip() for line in f.readlines()] return stopwords

加上errors='ignore’参数以便忽略错误,继续执行读取函数。 这里遇到了一个编码的问题:Python中读取txt文本出现“ ‘gbk’ codec can’t decode byte 0xbf in position 2: illegal multibyte sequence”的解决办法

第二步:去除无效字符 + 停用词代码: final_process_2.py

""" 目的:数据第二步清洗 1、读取文本数据+相应类别,各自分别放进comments和class_的列表中 2、使用正则表达式去除其他符号 3、从停用词列表中读取数据,去除停用词,每个文本得到的剩下单词用' '空格连接起来 4、将分类所得到的正负文本放进不同的文档中,自己检查看大体上是否分类正确 """ import csv # import sys import jieba import re # import importlib path_meituan = r'D:\lagua\study\coding\pythonPractice\DataProcess\MeiTuan.csv' path_class = r'D:\lagua\study\coding\pythonPractice\DataProcess\class_.csv' # 类别 path_stop = r'D:\lagua\study\coding\pythonPractice\DataProcess\stopWords_3.txt' # 停用词 path_neg = r'D:\lagua\study\coding\pythonPractice\DataProcess\neg_newMeiTuan.txt' path_posi = r'D:\lagua\study\coding\pythonPractice\DataProcess\posi_newMeiTuan.txt' # 读取类别 def get_class(): class_ = [] with open(path_class,'r',encoding='utf-8',errors='ignore',newline='') as f: reader = csv.reader(f) for line in reader: temp = line[0].replace('\n','').strip() class_.append(int(temp)) return class_ # 获取数据--文本评论 def getData(path): # 获取数据 seg_all = [] with open(path,'r',encoding='utf-8') as f: reader = csv.reader(f) for line in reader: seg_all.append(line[1]) # csv第一列是index,第二列是文本评论 return seg_all def get_index(x): # 获得待删除的Index temp = [i for i,v in enumerate(x) if v==''] return temp # 根据index删除元素---主要针对comments来讲 def delete_comments_accord_index(x,index): # 针对comments删除元素 to_be_delete = [v for i,v in enumerate(x) if i in index] for i in to_be_delete: x.remove(i) return x # 根据index删除元素,对class来讲 # class中的元素只有1,-1处理方式和comments不一样 def delete_class_accord_index(class_,index): # 针对class删除元素 temp = [] for i,v in enumerate(class_): if i not in index: temp.append(v) return temp # 去除其他符号 def splitOther(data_split): """ params: data_split:待切分的数据 return: 返回:是空元素的index + 待被去除index的文本---以元组的形式返回 """ def re_split(desstr): temp = ''.join(re.split(r'\W',desstr)) return temp temp = [re_split(desstr) for desstr in data_split] # 获得待删除的index index = get_index(temp) return (index,temp) # 由index删除列表元素 def indexProcess(func,last_comments,last_class): """ params: func:清洗数据的某个函数 last_comments:待处理的文本评论列表 last_class:待处理的文本类别 return: 返回已经去除了相应元素的文本列表 + 对应的class """ noFunc_index = func(last_comments)[0] noFunc_comments = func(last_comments)[1] final_noFunc = delete_comments_accord_index(noFunc_comments,noFunc_index) class_noFunc = delete_class_accord_index(last_class,noFunc_index) return (final_noFunc,class_noFunc) def splitStop(data_split): # 创建停用词列表 # 从txt文档中读取停用词,放进列表中 def stopwordslist(): # 返回列表 with open(path_stop,'r',encoding='utf-8', errors='ignore') as f: stopwords = [line.strip() for line in f.readlines()] return stopwords stop_words_list = stopwordslist() stopwords = {}.fromkeys(stop_words_list) # 建立一个函数去掉字符串中的停用词 def cutStopWords(word): segs = jieba.cut(word, cut_all=False) final = '' for seg in segs: if seg not in stopwords: final += seg final +=' ' return final splitStopData = [cutStopWords(v) for v in data_split] index = [i for i,v in enumerate(splitStopData) if v==''] return (index,splitStopData) # 自己检查使用,看是否将文本与标签相对应 def wirteClass(path_neg,path_posi,comments,class_): # 根据类别写文档 file_neg = open(path_neg,'w',encoding = 'utf-8',errors='ignore') file_posi = open(path_posi,'w',encoding = 'utf-8',errors = 'ignore') for i,v in enumerate(noStopWord_comments): # 使用try...except 来检测读写过程中的错误 try: if noStopWord_class[i]==-1: file_neg.write(v+'\n') else: file_posi.write(v+'\n') except: print('Error') file_neg.close() file_posi.close() class_ = get_class() # 获取类别 comments = getData(path_meituan) # 获取评论 # 充当过滤链 #----------------------------------------------------------- noOtherWord_comments,noOtherWord_class= indexProcess(splitOther,comments,class_) # 根据index处理comments和class noStopWord_comments,noStopWord_class=indexProcess(splitStop,noOtherWord_comments,noOtherWord_class) #----------------------------------------------------------- wirteClass(path_neg,path_posi,noStopWord_comments,noStopWord_class)

好啦,前两步的所有东西就记录在这里,因为还有很多步骤的细节可以展现,在这里写出来就太多啦,放在下一章文本分类(二)文本数据数值化,向量化写。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有