NLP—tokenizer,关于类的操作
文本处理
def filter(path1,path2):
f1=open(path1,"r",encoding='utf-8')#读入评论
f2=open(path2,"w",encoding='utf-8')#清洗评论并保存
lis=f1.readlines()
for line in lis:
line=line.strip().split("\t")
line[1] = re.sub("我在:http:.*", "", line[1])
line[1] = re.sub("我在这里:http:.*", "", line[1])
line[1] = re.sub("http:.*", "", line[1])
f2.write(line[1]+"\n")
f1.close()
f2.close()
读入的文件的格式跟上一次的微博文本评论一样,可以采用类似的清洗方法,但是当时在使用harvesttext函数的时候,并没用帮我把url清洗掉,于是直接使用正则表达式。使用re.sub()做正则表达式的匹配和替换,"我在:http:.*“指的是从我在http:开始匹配到结尾,将其替换为空字符。在清洗的过程中,我发现评论的url前缀有三种情况,为"我在:http:”,"我在这里:http:‘’,“http:”。将每条评论按行写入一个新的文本,同时该文本一行表示一条评论。
图像绘制
def picture_of_distribution(char):
len_c=[]
len_w=[]
for line in char:#提前生成一各数字列表
x=len(jb.lcut(line.strip(), cut_all=False))
len_w.append(x)
y=len(line.strip())
len_c.append(y)
plt.figure(figsize=(16,16))
plt.subplot(2,1,1)
plt.boxplot(len_w,showmeans=True)
plt.title("word_split_distribution")
plt.subplot(2,1,2)
plt.boxplot(len_c,showmeans=True)
plt.title("char_split_distribution")
plt.savefig("D:\\经管大三\\现代程序设计\\week5\\boxplot.png")
plt.figure(figsize=(16,16))
plt.subplot(2,1,1)
sns.distplot(len_w)#这个distplot函数巨坑,要不是为了拟合曲线真不想用
plt.title("word_split_distribution")
plt.subplot(2,1,2)
sns.distplot(len_c)
plt.title("char_split_distribution")
plt.savefig("./hist_plot.png")
plt.show()
该函数传入了一个列表,每个元素指一条评论,以"\n"结尾。
首先,对每条评论通过两种方法截断,一种是按字截断,一种是按照分词截取,统计其长度。
接着将两种方式统计的评论长度绘制箱线图和直方图。但是在使用seaborn直方图的时候,pc报错显示distplot函数将未来将要被弃用,改为displot就可以正常绘制,如果需要添加拟合曲线,设置参数kde=True即可。
箱线图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMGMyopl-1665400325972)(D:\经管大三\现代程序设计\week5\boxplot.png)]
通过分析箱线图,发现词和字分割方式的中位数在15到25之间。这也比较符合实际情况,大家评论的时候也不太愿意长篇大论的码字,当然不排除有些人喜欢发很多字的评论,观察箱线图即可看出,这些离群值,大大拉升了平均值,使得均值高于中位数很多。
直方图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-edkWqb9Z-1665400325974)(D:\经管大三\现代程序设计\week5\hist_plot_2.png)]
通过在窗口界面自动返回的坐标显示字切割的众数在15左右,词众数在10左右。发现一个很奇特的现象,按字分词到150以后就几乎没有了。但是通过查阅,微博评论字数限制在140,那么为什么会出现这种情况呢?我觉得存粹是因为画直方图的时候,采用了区间的方式,恰好包含了超出150的部分。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AA8pJu7F-1665400325975)(D:\经管大三\现代程序设计\week5\char_hist_plot.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6YsTAgF1-1665400325976)(D:\经管大三\现代程序设计\week5\word_hist_plot.png)]
以上采用的是displot函数
通过分析,对于字数分割的评论,选取15到20长度是比较合适的;对于词分割的评论,选取10到15长度是比较合适的。
类的定义
class Token:
def __init__(self,char,coding="w",PAD=0):#这一步函数是做初始化和对实例进行赋值
__dic={}#不希望外部访问
__dic["PAD"]=0
self.char=char#此时每个元素还是代表一行评论
self.coding=coding
i=1
char_ = [item.strip() for item in char] # 因为后面是按行读入,而读入类的是需要作为整个字符串做分词的,所以需要删去回车键,做点小操作
char_ = " ".join(char_)
if coding=="w":#按词进行编码
word_lis=jb.lcut(char_,cut_all=False)
for item in word_lis:
if item not in __dic.keys():
__dic[item]=i
i+=1
elif coding=="c":#按字编码
for cha in char_:
if cha in __dic.keys():
__dic[cha]=i
i+=1
self.dic=__dic#便于之后类内的函数调用
def tokenize(self,sentences):
list_of_chars=[]
if self.coding=="w":
list_of_chars=jb.lcut(sentences.strip(), cut_all=False)#先删除末尾行的\n
elif self.coding=="c":
for i in sentences.strip():
list_of_chars.append(i)
return list_of_chars#返回分词列表
def encode(self,list_of_chars):
tokens=[]
for i in list_of_chars:
tokens.append(self.dic[i])
return tokens
def trim(self,tokens,seq_len):
while len(tokens)<seq_len:
tokens.append(0)
tok=tokens[:seq_len]
return tok
def decode(self,tokens):
#key=list(self.dic.keys())这样子不可行,因为字典不是按顺序排列的,可以利用items返回键值对
dic=self.dic
dic=sorted(dic.items(),key=lambda x:x[1])#对字典按照键值排序,同时返回成列表的键值对
key=[]
value=[]
for item in dic:
x, y = item
key.append(x)
value.append(y)#加入键值对
for item in tokens:#键入的是数字
print(key[item],end=" ")
print("\n")
def encode_all(self,seq_len):
lis=self.char
tokens=[]
for line in lis:
toke=self.tokenize(line)
if len(toke)==seq_len:#输出的时候连成一个完整的句子
toke="".join(toke)
tokens.append(toke)
print(toke)
return(tokens)
main函数
path1="./final_none_duplicate.txt"
path2="./filter_comment.txt"
#filter(path1,path2)
f1=open(path2,"r",encoding="utf-8")
char=f1.readlines()
picture_of_distribution(char)
s=Token(char,coding="w")
list_of_chars=s.tokenize(char[0])
print(char[0])
tokens=s.encode(list_of_chars)
print(tokens)
tok=s.trim(tokens,15)
print(tok)
s.decode(tokens)
all=s.encode_all(15)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0BegVdTc-1665400325978)(C:\Users\kerrla\AppData\Roaming\Typora\typora-user-images\image-20220930172015747.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rAcl4Tul-1665400325979)(D:\经管大三\现代程序设计\week5\长度为15的评论.png)]
与第二周的作业中one-hot方法相比,one-hot将特征词作为向量,然后将每条语料用特征词向量表示。而tokenizer方法则将所有的词都转化为数字,然后将预料表示为向量。区别就在于one-hot可以反映出预料的含义,如果将情绪词作为特征词向量,则能反映语料所表达的情绪,但是one-hot不能反映语料本身;tokenizer可以反映预料本身的结构,但是这种表示方法并不能反映语料的含义,同时tokenizer方法灵活性不够,如果从外部输入一些语料库中没有的词,则无法被表示,同时这种处理方法对数据存储等方面消耗太大。
附加题
(3条消息) 一文读懂BERT(原理篇)_sunhua93的博客-CSDN博客_bert
tokenizer方法灵活性不够,如果从外部输入一些语料库中没有的词,则无法被表示,同时这种处理方法对数据存储等方面消耗太大。