文本数据与图像数据本质一样,图像本身的每个通道,像素点值就是数据本身。而文本数据要被计算机理解,首先要被处理成数值型,也就是说需要给文本编码,如embedding。这篇笔记记录将文本数值化。
实例
一个样本文件有5000条记录,存在于txt中。如下为样本文本中的索引为204的记录:
1 | with open(train_file, 'r') as f: |
输出:
1 | 5000 |
格式是:类别+样本描述。
分成label和content:
1 | label, content = lines[204].strip('\r\n').split('\t') |
分词
使用jieba对content进行分词:
1 | word_iter = jieba.cut(content) |
写入文件的每一条数据格式:
1 | 体育 vs 热火 首发 : 新 老三 巨头 对抗 小奥 单挑 大 Z 新浪 体育讯 北京 时间 5 月 4 日 , 热火 和 凯尔特人 迎来 第二 回合 巅峰 对决 , 本场 比赛 双方 主帅 均 未 对 首发 名单 做出 任何 更改 。 而 凯尔特人 主帅 道 格 - 里 弗斯 赛前 也 向 媒体 表示 , 本场 比赛 “ 大 鲨鱼 ” 沙奎尔 - 奥尼尔 将 继续 作壁上观 , 以下 为 双方 首发 名单 — — 凯尔特人 : 隆多 、 雷 - 阿伦 、 皮尔斯 、 加内特 、 杰 梅因 - 奥尼尔 热火 : 毕比 、 韦德 、 詹姆斯 、 波什 、 伊尔 戈斯卡 斯 ( 小林 ) |
如上述过程将源文件中每一条记录执行此操作后写入目标文件。整理成函数:
1 | def generate_seg_file(input_file, output_seg_file): |
此时三个样本集各自的分词结果。
统计词频
对上一步得到的分词后的文件进行词频统计。如对索引为204的记录统计:
1 | with open(output_seg_file, 'r') as f: |
结果为:
1 | {'绿衫': 1, '军': 1, 'vs': 1, '热火': 3, '首发': 3, ':': 3, '新': 1, '老三': 1, '巨头': 1, '对抗': 1, '小奥': 1, '单挑': 1, '大': 2, 'Z': 1, '新浪': 1, '体育讯': 1, '北京': 1, '时间': 1, '5': 1, '月': 1, '4': 1, '日': 1, ',': 4, '和': 1, '凯尔特人': 3, '迎来': 1, '第二': 1, '回合': 1, '巅峰': 1, '对决': 1, '本场': 2, '比赛': 2, '双方': 2, '主帅': 2, '均': 1, '未': 1, '对': 1, '名单': 2, '做出': 1, '任何': 1, '更改': 1, '。': 1, '而': 1, '道': 1, '格': 1, '-': 4, '里': 1, '弗斯': 1, '赛前': 1, '也': 1, '向': 1, '媒体': 1, '表示': 1, '“': 1, '鲨鱼': 1, '”': 1, '沙奎尔': 1, '奥尼尔': 2, '将': 1, '继续': 1, '作壁上观': 1, '以下': 1, '为': 1, '—': 2, '隆多': 1, '、': 8, '雷': 1, '阿伦': 1, '皮尔斯': 1, '加内特': 1, '杰': 1, '梅因': 1, '毕比': 1, '韦德': 1, '詹姆斯': 1, '波什': 1, '伊尔': 1, '戈斯卡': 1, '斯': 1, '(': 1, '小林': 1, ')': 1} |
此字典中键为词语,值为键出现的频数。当然这只是对一条记录的统计,对所有记录统计才有意义。
按词语频数排序,方便之后输入模型的截取操作。****
1 | sorted_word_dict = sorted( |
结果:
1 | [('、', 8), (',', 4), ('-', 4), ('热火', 3), ('首发', 3), (':', 3), ('凯尔特人', 3), ('大', 2), ('本场', 2), ('比赛', 2), ('双方', 2), ('主帅', 2), ('名单', 2), ('奥尼尔', 2), ('—', 2), ('绿衫', 1), ('军', 1), ('vs', 1), ('新', 1), ('老三', 1), ('巨头', 1), ('对抗', 1), ('小奥', 1), ('单挑', 1), ('Z', 1), ('新浪', 1), ('体育讯', 1), ('北京', 1), ('时间', 1), ('5', 1), ('月', 1), ('4', 1), ('日', 1), ('和', 1), ('迎来', 1), ('第二', 1), ('回合', 1), ('巅峰', 1), ('对决', 1), ('均', 1), ('未', 1), ('对', 1), ('做出', 1), ('任何', 1), ('更改', 1), ('。', 1), ('而', 1), ('道', 1), ('格', 1), ('里', 1), ('弗斯', 1), ('赛前', 1), ('也', 1), ('向', 1), ('媒体', 1), ('表示', 1), ('“', 1), ('鲨鱼', 1), ('”', 1), ('沙奎尔', 1), ('将', 1), ('继续', 1), ('作壁上观', 1), ('以下', 1), ('为', 1), ('隆多', 1), ('雷', 1), ('阿伦', 1), ('皮尔斯', 1), ('加内特', 1), ('杰', 1), ('梅因', 1), ('毕比', 1), ('韦德', 1), ('詹姆斯', 1), ('波什', 1), ('伊尔', 1), ('戈斯卡', 1), ('斯', 1), ('(', 1), ('小林', 1), (')', 1)] |
整理成函数,对所有记录统计。注意该操作只针对训练集:
1 | def generate_vocab_file(input_seg_file, output_vocab_file): |
打开结果文件vocab_file
查看:
1 | 1 <UNK> 10000000 |
第一列为序号,表示第几个词,第二列为词(出现的数组和百分比都是文本中的实际数字),第三列为该词出现的频数。两点说明:
- 频数太小的词无意义,因为神经网络为概率模型,只出现一次没有统计意义。
- 而频数很高但通用的词(停用词)同样无意义,因为通用的词在分类问题中不能提供有用信息,从信息论角度看,使用通用词训练模型不能减少模型的不确定性。这两点之后会处理。
对label统计:
1 | def generate_category_dict(input_file, category_file): |
结果写入catecory_file
, 并且控制台输出:
1 | 体育 5000 |
类别频数相同,表示这是一个极度均匀数据集。这是理想的!
统计词的频率,是为了截取,每个词的数值化,可用其序号代替。
整个过程生产5个文件:
- seg_train_file: 分词后的训练集
- seg_val_file: 分词后的验证集
- seg_test_file: 分词后的测试集
- vocab_file: 训练集的词频统计
- category_file: 训练集的类别统计
完整程序与数据文件这里。
敲黑板对于如本笔记所处理的极度均匀的数据集,评价模型时可以使用准确率。但是对于极度偏斜(Skewed Data)的数据,如在数据集中某类病症的发病样本数与未发病样本书之比远小于1,只使用准确率评价模型是远远不够的。这时就需要使用其他模型评估方法如混淆矩阵(Confusion Matrix)等。