自然语言处理案例 | 文本预测和生成

自然语言处理是计算机以一种聪明而有用的方式分析,理解和从人类语言中获得意义的一种方式。利用自然语言处理,开发者可以组织和构建知识来执行自动摘要、翻译、命名实体识别、关系提取、情感分析、语音识别和话题分割等任务。今天带大家看一个自然语言处理案例——文本预测和生成,步骤如下。本案例使用Jupyter Notebooks工具进行代码编辑和运行调试。


01

案例实践


1

导入所需的包


将程序所需的包导入。


import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from keras.layers import Dense, LSTM
from keras.utils import to_categorical
from keras.layers.embeddings import Embedding
from keras.preprocessing.text import Tokenizer
from keras.models import Sequential, load_model
from keras.preprocessing.sequence import pad_sequences


2

制作数据集


从指定的Excel文件中读入信息,制作数据集。


file_path = '../data/wanglihong.xlsx'
songs = pd.read_excel(file_path)
print(songs.shape)
songs.head()


结果如图6- 5所示。


图6- 5  歌词数据


为了清楚地看清数据内容,下面代码用于将前5条Lyrics列的文本信息打印出来。


for i in range(5):
print(i, '\n', songs['Lyrics'][i])


结果如下所示。


0 
 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人访 无言苍天笔墨寒 笔刀春秋以血偿 谈爱恨 不能潦草 战鼓敲啊敲 用信任 立下誓言我来熬 这缘分 像一道桥 旌旗飘啊飘 你想走 就请立马抽刀 爱一笔勾销 谈爱恨 不能潦草 红尘烧啊烧 以生死 无愧证明谁重要 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 血肉筑城万箭穿 盔甲染血映月光 远方胡笳催断肠 狼嚎骤起震边关 谈爱恨 不能潦草 战鼓敲啊敲 用信任 立下誓言我来熬 这缘分 像一道桥 旌旗飘啊飘 你想走 就请立马抽刀 爱一笔勾销 谈爱恨 不能潦草 红尘烧啊烧 以生死 无愧证明谁重要 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣
1
 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如戏 你爱的人到底是不是我 是否真正的我 是另一个样子 如果你愿意 我卸下我的面具 给你我全部 全部的我都给你 你挑着担 我牵着马 迎来日出 送走晚霞 给我一个反映 喊喊我的名字 美猴王的魅力 推前浪的行着 还在努力找传说中的幸福 一句道白 让你听得清楚 Do U Love Me 说说 你爱我到什么程度 Do U Want Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如戏 你爱的人到底是不是我 是否真正的我 是另一个样子 如果你愿意 我卸下我的面具 给你我全部 全部的我都给你 你挑着担 我牵着马 迎来日出 送走晚霞 给我一个反应 喊喊我的名字 美猴王的魅力 推前浪的行着 还在努力找传说中的幸福 一句道白 让你听得清楚 Do U Love Me 说说 你爱我到什么程度 Do U Love Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me? Do U Love Me 说说 你爱我到什么程度 Do U Want Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me
2 
 原来默罕默德就是杜明汉 杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌 他根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根本本 根本 不喜欢 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根本就不会用丹田唱歌 根根本 根根根本 我真没有想到啊 这明星效应 还真你拉灵 为什么还不回来 根根根本 不回来 为什么还不回来 根根根本 不回来 为什么还不回来 根根根本 为什么还不回来 阿德呀 阿德呀
3 
 跟着我Flow 跟着我Flow 这么自由 这么自由 Yi Li A E Yi Li A O 跟着我Flow 跟着我Flow…Flow…Flow I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪 ABC Do re mi fa sol 节奏轻轻地甩 微妙地笑 酷酷地跳 这是新的style 不如你一起来加入 跟着我Flow (我手指开始) 跟着我Flow (我弹指开始) 这么自由 (那韵律开始 hey hey hey) 这么自由 (我们都开始 ) (我们都开始) 歌声多亲切 灵感开始倾泻 的一种感觉 woo… 感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接 Just Flow…(Just Flow) I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我Flow (我手指开始) 跟着我Flow (我弹指开始) 这么自由 (那韵律开始) 这么自由 (我们都开始) (我们都开始) I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go (我双脚开始go) 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我Flow (跟着我Flow) 跟着我Flow (跟着我Flow) 这么自由 (这么自由 ) 这么自由 (这么自由) 跟着我Flow 跟着我Flow 这么自由 这么自由
4 
 happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 你似乎看见大楼阴影复活包围过来 自由到不自在期待的色彩都成了黑白 谁是你的朋友谁是你的真爱 究竟你想要证明些什么 woo yeah 你的一切脆弱我心里明白 我只想要立刻带你离开 you can get out get out get out of your nest you don't have to be the one you can get out get out get out of your nest you don't have to be the best happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 自由到不自在一切成了黑白 自由到不自在一切成了黑白 早晨的报纸晚上变成垃圾满街覆盖 一半已经昏迷努力的叫另一半醒来 你想发现什么想知道什么 没有人能够给你答案 woo yeah 你的一切脆弱我心里明白 我只想要立刻带你离开 you can get out get out get out of your nest you don't have to be the one you don't have to be the best you can get out get out get out of your nest happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 没有人能够给你答案你想发现什么


下面代码去掉Lyrics列中第4条(下标[3])文本中的所有字母。


song = re.sub(r"[a-zA-Z()''…?.,!!,-]+", '', songs['Lyrics'][3])
song


执行后的结果显示如下,这段文本中的所有字母都被去掉了。


'跟着我 跟着我 这么自由 这么自由 跟着我 跟着我 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪 节奏轻轻地甩 微妙地笑 酷酷地跳 这是新的 不如你一起来加入 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 歌声多亲切 灵感开始倾泻 的一种感觉 感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 一听到 我双脚开始 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 跟着我 跟着我 跟着我 这么自由 这么自由 这么自由 这么自由 跟着我 跟着我 这么自由 这么自由 '


下述代码去掉文本中的无效空格。


re.sub('\s{2,}', ' ', song)


执行结果如下所示。


'跟着我 跟着我 这么自由 这么自由 跟着我 跟着我 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪 节奏轻轻地甩 微妙地笑 酷酷地跳 这是新的 不如你一起来加入 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 歌声多亲切 灵感开始倾泻 的一种感觉 感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 一听到 我双脚开始 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 跟着我 跟着我 跟着我 这么自由 这么自由 这么自由 这么自由 跟着我 跟着我 这么自由 这么自由 '


下述代码定义文本函数,对文本进行处理。


def regex_func(text):
    text = re.sub(r"[a-zA-Z()''…?.,!!,-]+", '', text)
    text = re.sub('\s{2,}', ' ', text)
    return text
new_songs = pd.DataFrame(columns=songs.columns)
new_songs['Title'] = songs['Title']
length = []
for i in range(len(new_songs)):
    new_songs.loc[i]['Lyrics'] = regex_func(songs['Lyrics'][i])
    length.append(len(new_songs['Lyrics'][i]))
new_songs['Length'] = length
new_songs.head()


3

数据预处理:输入输出


对文本数据进行预处理,进行输入输出。


# 序列化
text=''
for i in range(len(new_songs)):
    text+=new_songs['Lyrics'][i]
print(len(text))
token=Tokenizer()
token.fit_on_texts(text)
token.word_index


上面代码输出结果如下:


{'的': 1,
'我': 2,
'你': 3,
'不': 4,
'是': 5,
'⼀': 6,
'爱': 7,
'在': 8,
'⼼': 9,
'有': 10,
'这': 11,
'了': 12,
'么': 13,
'就': 14,
'⼈': 15,
'想': 16,
'个': 17,
'来': 18,
'能': 19,
...


输入下面代码,来统计每个字的个数:


token.word_counts


输出结果如下:


OrderedDict([('秦', 2),
('时', 93),
('明', 62),
('⽉', 35),
('汉', 4),
('关', 17),
('万', 27),
('⾥', 132),
('⻓', 28),
('征', 3),
('⼈', 195),
('未', 46),
('还', 106),
('但', 42),
('使', 18),
('⻰', 31),
('城', 23),
('⻜', 77),
('将', 26),
...


输入下述代码:


sequences = token.texts_to_sequences(text)
# print('"', texts[: 10],'"', '分别被映射成了数字:')
print('"{}"{}'.format(text[: 10], '分别被映射成了整数:'))
print(sequences[: 10])


上面代码输出结果如下:


"秦时明⽉汉时关 万⾥"分别被映射成了整数:
[[1062], [46], [87], [171], [805], [46], [341], [], [220], [31]]


输入下述代码:


num_words = 400
tokenizer = Tokenizer(num_words=num_words)
tokenizer.fit_on_texts(text)
print('字典的⻓度:', len(tokenizer.word_index))


上面代码输出结果如下:


字典的⻓度:1636


输入下述代码:


sequences = tokenizer.texts_to_sequences(text)
print('"{}"{}'.format(text[: 10], '分别被映射成了整数:'))
print(sequences[: 10])


上面代码输出结果如下:


"秦时明月汉时关 万里"分别被映射成了整数:
[[], [46], [87], [171], [], [46], [341], [], [220], [31]]


输入下述代码:


sequences=pad_sequences(sequences)
print(sequences[: 10])


上面代码输出结果如下:


[[ 0]
[ 46]
[ 87]
[171]
[ 0]
[ 46]
[341]
[ 0]
[220]
[ 31]]


输入下述代码:


star = 0
end = 0
new_songs['Sequences'] = ''
for i in range(len(new_songs)):
    end += new_songs['Length'][i]
    new_songs.loc[i, 'Sequences'] = sequences[star: end]
    star = end
new_songs.head()


上面代码输出结果图6- 6所示。


图6- 6  文本统计运行结果


输入下述代码:


new_songs['Sequences'][0][: 15]


上面代码输出结果如下:


[0, 46, 87, 171, 0, 46, 341, 0, 220, 31, 212, 0, 15, 127, 43]


输入下述代码:


max_len = 10 # 滑窗长度,也就是输入序列的长度
len_lrc = new_songs['Length'][0] # 每首歌歌词的长度
X = []
y = []
for i in range(len_lrc - (max_len+1)):
    X.append(sequences[i: i + (max_len+1)])
    y.append(sequences[i + (max_len+1)])
# 这里是先将X,y合并成一个大矩阵,那么大矩阵的shape=(?, 11)
def build_matrix(sequence, max_len = 10):
    max_len += 1
    matrix = []
    length = len(sequence)
    for i in range(length - max_len):
        matrix.append(sequence[i: i + max_len])
    matrix = np.array(matrix)
    X = matrix[:, :-1]
    y = matrix[:, -1]
    return X, y
# n = 91 歌曲数目
X, y = build_matrix(new_songs['Sequences'][0])
for i in range(1, len(new_songs)):
    sequence = new_songs['Sequences'][i]
    XX, yy = build_matrix(sequence)
    X = np.concatenate([X, XX])
    y = np.concatenate([y, yy])
X.shape,y.shape


X.shape和y.shape输出结果如下:


((32574, 10), (32574,))


模型代码如下:


model = Sequential()
model.add(Embedding(num_words, 128, input_length=X.shape[1]))
model.add(LSTM(64))
model.add(Dense(64, activation='relu'))
model.add(Dense(num_words, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')

model.summary()


上面代码输出结果如图6- 7所示。


图6- 7  模型数据概括


模型加载代码如下所示:


y = to_categorical(y, num_classes=num_words)
#model.fit(X, y, batch_size=256, epochs=500, verbose=0)
# 模型加载使用
model = load_model('../model/lrc_model_0.h5')


4

预测


test_lrc = '当节奏开始转' # 输入歌词开头
test_sequence = tokenizer.texts_to_sequences(test_lrc) # 序列化
test_sequence = pad_sequences(test_sequence).reshape(1, -1)
test_sequence = pad_sequences(test_sequence, X.shape[1]) # 输入序列长度不足10,故使用pad_sequences将其补足
test_sequence
model.predict(test_sequence).argmax()
# 输入一个文本将其转化为序列
def input_sequence(text, max_len=10):
    sequence = tokenizer.texts_to_sequences(text) # 序列化
    sequence = pad_sequences(sequence).reshape(1, -1) # 填充0
    sequence = pad_sequences(sequence, maxlen=max_len) # 补足或截断
return sequence
# 得到字典内的汉字
def next_word(y_pred):
    idx = np.argmax(y_pred) # 最大值的下标
    if idx == 0: # 下标为0时,字典内并不存在,故视为空格
        return ' '
    else:
        return tokenizer.index_word[idx]
lrc = '当节奏开始转'
for i in range(200):
    X_sequence = input_sequence(lrc)
    y_pred = model.predict(X_sequence)
    word = next_word(y_pred)
    lrc += word
lrc = re.sub('\s+', ' ', lrc) # 只需要一个空格
print(lrc)


输出结果如下:


array([[ 0, 0, 0, 0, 149, 374, 0, 38, 148, 131]], dtype=int32)
0
当节奏开始转 是你 的声次甜 让这次大己的 本有些飞 在过去没有 也给欢离开你 听爱情留不一场 这 成 人的总会无 我的手彼悲夜 着 飞 算 人 都是你 心里你爱跟着 此刻会给你 马多的开始 这在风 的世 一 气的 喜欢 你在心说 你回家 开 怀 应你爱的 想给我你一起我哭下有的人 没有人记不能说的问 太多话我还在我出现在原泪的如没有 前去的 气 这一个梦 我为她流泪从来不相信爱对你的就是


定义generating_lrc()函数,代码如下所示。


def generating_lrc(lrc, length=200):
    for i in range(200):
        X_sequence = input_sequence(lrc)
        y_pred = model.predict(X_sequence)
        word = next_word(y_pred)
        lrc += word
    lrc = re.sub('\s+', ' ', lrc) # 只需要一个空格
    return lrc
generating_lrc('大城小爱')


执行generating_lrc('大城小爱')输出结果如下:


'大城小爱的 我一回 就像飞机带我找到永不相知说 相知钟 这当来看你被 你是我会无 你是过心里 想找你的总会常走天飞在知晚样方方方 当一夜不夜夜样一样来我就记一中 楚 的声落 千年爱情 你是我怀过好中的更 在转 不起感受美美世天的别人陪 出 了满不 自有 还 不停 让你留下你 就再 我爱自由 没有 期待在这就是一些 比传友 寂寞的 一个 却情全再来 让我们错完没有一个 '


执行下面代码:


generating_lrc('他根本就不会用丹田唱歌')


该代码的输出结果如下:


'他根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根根本 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根根本 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根根本 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根根本 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根根本 根根本 根根'


02

参考书籍


《人工智能概论

ISBN:9787302564201

作者:赵克玲 瞿新吉 任燕

定价:69元



扫码优惠购书



内容简介


本书不是一本简单的人工智能基础入门教材,不是知识点的铺陈,而是致力于将知识点融入案例中,深入浅出地对知识点进行全面系统的讲解。全书内容涵盖人工智能概述、Python基础、机器学习、计算机视觉、语言识别、自然语言处理、知识图谱和人工智能行业解决方案,并精心设计大量的应用案例,强化学生的动手和实践能力。


本书特色


采用思维导图对课程和章节重要知识点进行梳理,便于理解和记忆。

每章配有目标、正文、总结和习题,使教学内容和过程形成闭环。

理论联系实践,基于应用,并提供微课视频,帮助初学者能够快速学习和掌握。


教学资源


配套资源丰富,包括微课视频、教学课件、程序代码、习题答案、教学大纲、考试大纲等资源。




03

精彩推荐


本文由“公众号文章抓取器”生成,请忽略上文所有联系方式或指引式信息。有问题可以联系:五人工作室,官网:www.Wuren.Work,QQ微信同号1976.424.585