NLP知识点:文本数据的预处理
1. 为啥要有预处理?
NLP(Natural Language Processing)指的是自然语言处理,就是研究计算机理解人类语言的一项技术。
要研究语言处理,那么首先得有语言文本。之前讲过利用Tokenizer分词器对固定格式的文本进行序列化处理。
在序列化之前,如何把这些文本按照一定的格式处理好,也是一项基础的工作,这一步叫数据的预处理。
2. 文本存储的几种载体
一般直接可读的文本数据会存储在这么几种文件里:
数据库:sqlite、mysql……
表格文件:csv、excel……
纯文本文件:txt、json……
下面我们就挨个来讲一下,如何读写这些文件。
2.1 数据库
数据库存储文本信息,有很多优势:
支持大数据量存储
查询高效
支持复杂的关联关系
拿sqlite数据库举例子,看一下如何进行数据的读取。
下面有一个数据库文件,大小为8KB。
数据库里面有一张名称叫"ci"的表,数据结构和内容如下:
表里面存储了25条数据,是25篇宋词,每条数据包含序号(value)、词牌名(rhythmic)、作者(author)、内容(content)。
假设,我们要使用每首词的内容作为训练集,那么我们该如何组织数据呢?
# 导入sqlite的支持 import sqlite3 # 保存每首词的内容 str_array = [] # 指定文件位置(同级目录data下的data.db文件)建立连接 conn = sqlite3.connect('./data/data.db') # 执行查询语句,只获取author, content两个字段,获得游标(内含结果) cursor = conn.execute("SELECT author, content from ci;") # 循环结果 for row in cursor: # 获取结果(0 author, 1 content)中索引为1的数据 ci = row[1] # 加入内容列表 str_array.append(ci) # 关闭操作 cursor.close() conn.close() # 打印结果 print(str_array) 复制代码
最终打印结果如下:
[ '出砒霜,价钱可。\r\n赢得拨灰兼弄火。\r\n畅杀我。', '丞相有才裨造化,圣皇宽诏养疏顽。\r\n赢取十年闲。', '归。\r\n十万人家儿样啼。\r\n公归去,何日是来时。', '归。\r\n数得宣麻拜相时。\r\n秋前後,公衮更莱衣。', '百尺长藤垂到地,千株乔木密参天。\r\n只在郡城边。', '巍峨万丈与天高。\r\n物轻人意重,千里送鹅毛。\r\n\r\n' …… ] 复制代码
其中\r\n
是回车换行。我们看看巍峨万丈与天高。\r\n物轻人意重,千里送鹅毛。\r\n\r\n
在文本框的展示,能够帮助你更好地理解。
延伸知识:sqlite3的写入
数据的写入很简单,和数据读取类似。也是先建立连接,然后执行sql语句,这里多一个commit提交,最后断开连接。
下面举例说明,连续插入2条数据。
# 导入sqlite的支持 import sqlite3 # %% 数据表数据的写入 conn = sqlite3.connect('./data/data.db') for t in[(9998,"名称1","作者1","正文1"),(9999,"名称2","作者2","正文2")]: conn.execute("insert into ci values (?,?,?,?)", t) conn.commit() conn.close() 复制代码
2.2 表格文档
相比于数据库,表格类文档(csv、excel)也是一种很好的文本存储方式。
它双击就能打开,可以直接操作内容,也能利用自带的工具做一些数据处理。
下面有一个csv文件,里面有很多行,每一行是一首宋词,前三列分别是:词牌名、作者、内容。
假设,我们要使用每首词的内容作为训练集,那么我们该如何组织数据呢?
import csv # 建立存储内容的数组 str_array = [] # 构建阅读器,指定文件位置(同级目录data下的data.csv文件),指定编码格式 csv_reader = csv.reader(open("./data/data.csv",encoding="gbk")) # 循环每一行 for row in csv_reader: # 取出索引为2的列(第3列),存入数组 str_array.append(row[2]) # 打印数据 print(str_array) 复制代码
最终打印结果如下:
[ '出砒霜,价钱可。\r\n赢得拨灰兼弄火。\r\n畅杀我。', '丞相有才裨造化,圣皇宽诏养疏顽。\r\n赢取十年闲。', '归。\r\n十万人家儿样啼。\r\n公归去,何日是来时。', '归。\r\n数得宣麻拜相时。\r\n秋前後,公衮更莱衣。', '百尺长藤垂到地,千株乔木密参天。\r\n只在郡城边。', '巍峨万丈与天高。\r\n物轻人意重,千里送鹅毛。\r\n\r\n' …… ] 复制代码
这样,这个数组数据就可以使用了。
延伸知识:csv的写入
数据的写入和数据读取类似。先构建一个写入器 ,写入数据,最后需要关闭打开的文件。
下面举例说明,新建一个csv文件,然后插入1条数据。
import csv # 以写入的方式打开(新建)一个文件,指定编码 f_csv = open('./data/data2.csv','w',encoding='gbk', newline='') # 获取这个文件的写入器 csv_writer = csv.writer(f_csv) # 写入一行数据 csv_writer.writerow(['第一列','第二列','第三列']) # 关闭文件 f_csv.close() 复制代码
代码执行后,会在同级的data目录下新建一个data2.csv文件,然后写入一行3列的数据。
2.3 文本文档
文本文档(txt)是最轻量级的一种文本存储方式。
它不像数据库或者表格文件那样有关联关系,它只能罗列一段段文本,它也无法承载太多的数据,一般上万行文本就会导致它读取困难。
但是,它也是有优势的。那就是——使用方便。
打开文件往里面输入字符就可以了。
因为没有行列条数的概念,一般文本文档要存储数据集,都是以特殊字符作为区分,例如回车换行符,一行就是一条数据。
下面有一段文本,我们看看如何读取它。
import os # 保存每行文本内容的数组 str_array = [] # 指定文件位置(同级目录data下的data.txt文件) f_read = open('./data/data.txt','rb') # 读取一行文件 line = f_read.readline() # 如果此行存在 while line: # 读出内容 wstr = str(line, encoding = "utf-8-sig") # 添加到数组 str_array.append(wstr) # 接着再读下一行 line = f_read.readline() # 关闭文件 f_read.close() # 打印数组 print(str_array) 复制代码
最终打印结果如下:
[ '巍峨万丈与天高。物轻人意重,千里送鹅毛。\r\n', '远来犹自忆梁陈。江南无好物,聊赠一枝春。\r\n', '用心勤苦是新诗。吟安一个字,拈断数茎髭。\r\n', '扪窗摸户入房来。笙歌归院落,灯火下楼台。\r\n', '酥某露出白皑皑。遥知不是雪,为有暗香来。\r\n', '称觞喜对二阳临。况当弦月上,一醉祝千春。\r\n' ] 复制代码
延伸知识:txt的写入
数据的写入和数据读取类似。先打开一个文件 ,写入数据,最后需要关闭打开的文件。
下面举例说明,新建一个txt文件,然后写入文本。
import os # 以写入的方式打开(新建)data2.txt的文本 f_write = open('./data/data2.txt','w') f_write.write('写入文本第一行\n第二行') f_write.close() 复制代码
3. 组合拳:清洗数据并存为json文件
假设我们要训练一套关于宋词的数据,数据源就是下面数据库里的这张表的数据。
看似这些数据井井有条,其实并不是那么完美。
此时你有几个诉求:
去冗余:去掉头尾多余的数据,去掉重复的数据。
做筛选:只想要《临仙江》这种句式的数据。
换存储:因为数据量不大,想以json文本格式存储清洗后的数据。
分析:
去掉文本的头尾空格和换行,可以使用
strip()
方法。去除重复数据,可通过代码逻辑实现,将遇到的句子保存起来,下一个句子到已保存列表里面查找,能查到说明重复,查不到说明第一次见。《临仙江》的格式为:{[7个汉字]。<换行回车>[5个汉字],[5个汉字]。},可以通过正则匹配筛选出,正则表达式为:
^[\u4e00-\u9fa5]{7}。\r\n[\u4e00-\u9fa5]{5},[\u4e00-\u9fa5]{5}。$
。从数据库读取数据,筛选到合适的文本,组成json字符串写入文本即可。
代码如下:
import sqlite3 import json import re # 存储内容的数组 str_array = [] # 已经遇到过的内容 keys = {""} # 筛选 {7。5,5。}格式内容的正则表达式 pattern = re.compile(r'^[\u4e00-\u9fa5]{7}。\r\n[\u4e00-\u9fa5]{5},[\u4e00-\u9fa5]{5}。$') # 连接数据库 conn = sqlite3.connect('./data/data.db') # 执行查询,只获取内容字段,获得游标结果 cursor = conn.execute("SELECT content from ci;") # 循环结果 for row in cursor: # 获取索引为0的列 ci = row[0] # 裁剪头尾 ci = ci.strip() # 匹配格式 m = pattern.match(ci) # 没有匹配到 if m == None: print('\n没有匹配到:',ci) else: # 匹配到 print('\n匹配成功:',ci) # 是否出现过 if ci in keys: # 出现过,是重复的,不处理 print('\n已存在->',ci) else: # 没有出现过,加入出现列表,加入内容列表 keys.add(ci) str_array.append(ci) # 关闭游标和链接 cursor.close() conn.close() # 将内容列表转为json j_str = json.dumps(str_array, indent=2, ensure_ascii=False) # 打开(新建)文本 f_write = open('./data/data2.json','w') # 写入文本 f_write.write(j_str) # 关闭文件 f_write.close() 复制代码
生成的data2.json内容如下:
作者:TF男孩
链接:https://juejin.cn/post/7029165733598724103