大家好,本文志在发表一篇文本挖掘+苏打绿歌词 的文章,意义如下:

  1. 有完整的文本预处理、分词、主题探究等文本挖掘流程和代码,可供参考借鉴。
  2. 数据集是苏打绿自出道以来的歌词,探究了新词、主题、创作可能。
  3. 适合追星族自己上手操作,不论分析歌手的歌词、演员的台词等等,都能有所启发。
  4. 适合帮助数据分析新人找到有意思的课题进行思路开拓和研究~

先来一张资深打粉证明- -

声明:这篇文章纯粹出于我对于苏打绿无可比拟的喜爱与珍惜,所以在学习文本挖掘这门课程的时候不由自主选择了用他们的歌词作为研究对象。希望我能从自己的角度,完成文本挖掘+歌词探究的Idea,以此更加深入的了解我所热爱的这个团体,也能够帮助更多的人了解和喜欢上他们。


许多人评价说,华语乐坛已经趋向衰败,没有80,90年代的辉煌。在中国大陆,流行音乐中存在缺乏原创力、法律不健全、盗版猖獗、音乐格调低俗等现象。音乐的价值取向也逐渐趋向商业化,以追求利益为目标而缺乏了艺术价值。但中国乐坛现在仍有许多优秀的作品未被深入了解探究,以歌词中蕴含著美感与乐趣,使音乐更有独特的中华文化魅力。

以作词闻名的不仅有香港著名作词人林夕(创作量达4000,为王菲、陈奕迅等歌王歌后都作过词)、方文山(周杰伦的御用词人)、黄伟文(香港著名填词人)等,更有独立乐团苏打绿主唱吴青峰,毕业于台湾政治大学中文系,曾获台湾金曲奖「最佳作词人奖」。

知名乐团苏打绿2001年成立于校园,2003年确立6人阵容,2004年5月,苏打绿正式出道,发行第一张单曲《空气中的视听与幻觉》。2005年,苏打绿发行了《SodaGreen》。2006年,苏打绿发行专辑《小宇宙》。2012年,苏打绿获得第21届金曲奖最佳乐团奖。2013年,苏打绿发行专辑《秋:故事》,该专辑成为2013年度iTunes Store最受欢迎专辑。2014年,苏打绿开始了十周年世界巡回演唱会。2016年苏打绿获得第27届台湾金曲奖最佳国语专辑奖、最佳乐团奖、最佳编曲人奖、最佳作词人奖和最佳专辑制作人奖。

本文中,作者从文本(数据)挖掘的角度去「探索」苏打绿乐团的作品,挑战不同场景下(现代汉语和歌词文本)文本处理和分析的异同点,结合数据之美和诗歌之雅,用跨界思维去发现一些有趣的东西。

本文的语料是台湾乐坛苏打绿自出道以来的94首歌词,基本涵盖从<空气中的视听与幻觉>到<冬 未了>中的所有歌曲,约38735个字元

文本挖掘的经典流程是:获取文本——文本预处理——分词、去停用词——建模。在本文中,在这个过程中,作者意识到,歌词文本有其特殊性,如果直接进行分词,可能会造成分词的不准确,进而影响下一步的研究,因此在分词之前加入基于互信息和左右熵的新词发现的环节;接下来以苏打绿发行的四季专辑(韦瓦第计划)为研究对象,探究歌词的主题变化;最后基于GRU神经网路进行歌词生成,完成歌词的处理、挖掘、创作,三大部分。

本文研究框架

发现新词

—— 歌词有什么好研究的?

歌词文本作为一类特殊的文本,有其独特的艺术性和价值。通常来讲,在使用python进行文本分词的时候,会使用jieba分词模块。使用现有分词模块会面对的问题是,如果一些辞汇不在其中,会造成分词不准确的现象。

那么,发现新词的规则可以如何制定呢?本文主要从互信息左右熵两个概念入手,制定新词发现的规则。

  • 互信息

——成词的标准之一:内部凝固程度

互信息的定义为:

I(x,y)=log(p(x,y)/p(x)p(y))

什么是凝固程度?比如说一个词「电影院」,如果「电影」和「院」真的是各自独立地在文本随机出现,那么他两正好出现在一起的概率会很小。我们通过计算P(电影)×P(院)远小于P(电影院),这时候我们就会发现「电影院」很有可能是一个有意义的词。因此我们枚举文本片段的组合方式,然后设置凝聚程度的最小值。

  • 左右熵

——成词的标准之二:自由运用程度

左右熵的定义为:(以左熵为例)

E_{L}(W)=-sum_{forall a}{P(aW)log_{2}(P(aW|W))}

什么是自由运用程度?比如说一个词「辈子」, 用法非常固定,除了「一辈子」、「这辈子」、「上辈子」、「下辈子」,基 本上「辈子」前面不能加别的字了。以至于直觉上会觉得「辈子」不能单独成词。因此我们说能够自由运用是一个词的关键。

我们这里使用左右熵来衡量主要是想表示预选词的自由程度,左右熵越大,表示这个词的左边右边的词换的越多,那么它就很有可能是一个单独的词。得具有丰富的左邻词集合与右邻词集合。

先介绍信息熵的概念,信息熵能够反映一个事件的结果平均会给你带来多大的信息量。如果某个结果的发生概率为p,当你知道它确实发生了,那么你得到的信息量为-log(p)。 如果一颗骰子的六面是1,1,1,2,2,3。那么我们投到1时,得到的信息量是-log(1/2);投到2时,得到的信息量是-log(1/3);投到3时得到的信息量是-log(1/6)。事情越不确定,信息熵越大。

我们使用信息熵来衡量一个文本片段的左邻字集合与右邻字集合有多随机。

凝固程度与自由程度缺一不可,只看凝固程度的话容易找到半个词,只看自由度的话容易得到无意义的垃圾片语。

接下来进入新词发现的流程:

流程:

  1. 输入: 按行分割的未切词文本
  2. 文档清洗, 去除非中文字元
  3. 构建子串-频率字典, 计算长度从1到max_word_length的所有子串的频率
  4. 构建新词候选集, 计算所有子串-频率字典中的子串的PMI值,PMI大于min_pmi的所有子串构成新词候选集
  5. 生成合法新词, 计算新词候选集中的所有子串左右邻居信息熵,信息熵高于min_entropy的所有子串构成最终的新词集
  6. 输出:新词集

## 正则表达式清洗文本模块 ##

import codecs
import re

filepath = E:/研究生课程/文本挖掘/final project/sodagreen_lyrics.txt
key = [u演唱,u单曲,u专辑,u苏打绿,u,u,u编曲,u史俊威,u苏打绿,u作词,u作曲,u演唱]
new = []
with open(rE:/研究生课程/文本挖掘/final project/sodagreen_lyrics.txt,r,encoding=utf-8) as f:
content = f.readlines()
for line in content:
if True:
line = re.sub(r"[s+.!/_,$%^*(+"]+|[+——!,。??、~@#¥%……&*()+]+", "", line)
line = re.sub(r[0-9a-zA-Z-|」「*-|《》)]+, , line)
line.strip()
if len(line) != 0 and all(i not in line for i in key):
new.append(line+ )
with codecs.open(E:/研究生课程/文本挖掘/final project/mypart/new.txt,w) as f:
for x in new:
f.write(x)

##看看生成文本啥样##

文本预处理前
文本预处理后

##基于清洗的文本进行新词发现##

def read_txt(filepath):
dataset=[]
for line in open(filepath,r,encoding=utf-8):
line = re.sub(r[0-9a-zA-Z], , line)
dataset.append(line)
return dataset
raw_sentences = read_txt(E:/研究生课程/文本挖掘/final project/mypart/new.txt)
text = .join(raw_sentences).replace(
,"")
stop_word=[,,),(,,,,,,
,,, ,-,,,.,,[,],,/,.,",u3000,,,,,,?]

for i in stop_word:
text=text.replace(i,"")

min_entropy=0.8
min_p=4
max_gram=4
count_appear=3

def gram(text,max_gram):
t1=[i for i in text]
loop=len(t1)+1-max_gram
t=[]
for i in range(loop):
t.append(text[i:i+max_gram])
if max_gram==1:
return t1
else:
return t
import math
def pro(word):
len_word=len(word)
total_count=len(word_all[len_word])
pro=freq_all[len_word][word]/total_count
return pro
def entropy(alist):
f=FreqDist(alist)
ent=(-1)*sum([i/len(alist)*math.log(i/len(alist)) for i in f.values()])
return ent

freq_all=[0]
word_all=[0]
for i in range(1,max_gram+1):
t=gram(text,i)
freq=FreqDist(t)
word_all.append(t)
freq_all.append(freq)

#筛选一部分符合互信息的单词
final_word=[]
for i in range(2,max_gram+1):
for j in word_all[i]:
if freq_all[i][j]<count_appear:
pass
else:
p=min([pro(j[:i])*pro(j[i:]) for i in range(1,len(j))])
if math.log(pro(j)/p)>min_p:
final_word.append(j)
final_word=list(set(final_word))

##新词发现展示##

中间是发现的新词,挑出几首作为示例,每首歌里 上面是jieba分词结果,下面是基于新词发现的分词结果。可以看到,「控制狂"这个词就被发现啦~~~还有"再遇见","背著你」等等~

哈哈哈开心。

新词发现展示

主题解读

——苏打绿在唱什么? 韦瓦第计划了解一下~

韦瓦第计划(Project Vivaldi),由台湾知名乐团苏打绿发起,灵感来源于以音乐呈现文字、写出了四季小提琴协奏曲的18世纪初古协奏曲之父-安东尼奥·维瓦尔第。苏打绿以「One Season, One Concept」,四个季节,四座城市,用四种情绪制作四张专辑,发动跨国「音」谋,打造完全「苏打绿」的曲风。

主题分析,在这里用了TextRank的方法:

TextRank 演算法是一种用于文本的基于图的排序演算法。其基本思想来源于谷歌的 PageRank演算法, 通过把文本分割成若干组成单元(单词、句子)并建立图模型, 利用投票机制对文本中的重要成分进行排序, 仅利用单篇文档本身的信息即可实现关键词提取、文摘。和 LDA、HMM 等模型不同, TextRank不需要事先对多篇文档进行学习训练, 因其简洁有效而得到广泛应用。

流程:

  1. 分词、去停用词得到候选关键词
  2. 构建候选关键词图
  3. 根据公式,迭代传播各节点的权重,直至收敛
  4. 对节点权重进行倒序排序,从而得到最重要的T个单词,作为候选关键词

去除停用词并且统计TOPK词频和主题
def final_words(stop_word_filepath,seg_list,k):
stop_words= read_txt(stop_word_filepath)
new_stop_words=[]
for i in stop_words:
i = i.replace(
,"")
new_stop_words.append(i)
new_stop_words.append( )
new_seg_list=[]
for word in seg_list:
if word!=
:
if word not in new_stop_words:
new_seg_list.append(word)
data = dict(Counter(new_seg_list))
data2 = sorted(data.items(), key=lambda x: x[1], reverse=True)
tfidf= analyse.extract_tags("".join(new_seg_list), topK=k, withWeight=False, allowPOS=())
textrank=analyse.textrank("".join(new_seg_list), topK=k, withWeight=False, allowPOS=(ns, n, vn, v))
return new_seg_list,data2[:k],tfidf,textrank

利用TextRank模型对四季专辑进行主题挖掘,可以得到如下的主题挖掘结果:

春:时间,回家,生命,梦境,天空,逝去,保留,寻找,烟火,盛开,期待,燃烧,游戏,美丽,颜色,迎接,停手,合奏,肩膀,日光

夏:魔鬼,庆祝,歇斯底里,幻想,背叛,地点,长大,爱情,倒退,追求,胸膛,世界,弄污,拥有,英雄,生活,走过,森林,下班,地狱

秋:时间,天地,世界,海洋,答答,天使,大地,改变,情绪,天空,伤口,谎言,故事,不见,人生,生命,翅膀,幻象,婴儿,狩猎

冬:欲望,星辰,投诉,世界,陪伴,感觉,细菌,轮回,有没有,带来,情绪,艺术,能源,否定,有罪,活著,灭绝,理睬,生恨,交给

生成词云图为:

台东春天的温暖民谣——《春.日光》

春.日光 主题词云图

伦敦夏天的热情摇滚——《夏/狂热》

夏/狂热 主题词云图

北京秋天的忧伤诗歌——《秋:故事》

秋:故事 主题词云图

柏林冬天的庄严古典——《冬 未了》

冬 未了 主题词云图

苏打绿韦瓦第计划,就是每张主题都这么明晰又吸引人啊- - 。春夏秋冬,每个季节都被你们包裹围绕了。

AI创作

—— 你能写歌吗?我不能。但AI可以。

生成歌词的项目还是有一些。网上大家可以搜索看看,有汪峰、周杰伦等等的歌词生成项目。

通常来讲,RNN是比较基础的文本生成神经网路。但是传统的RNN在训练long-term dependencies 的时候会遇到很多困难,最常见的便是vanish gradient problen(梯度消失)。在这个基础上,大牛们设计了更加精密的recurrent unit,如LSTM,GRU。LSTM和GRU都能通过各种Gate将重要特征保留,保证其在long-term 传播的时候也不会被丢失;还有一个不太好理解的作用就是有利于BP的时候不容易vanishing。

LSTM的重复网路模块的结构很复杂,它实现了三个门计算,即遗忘门、输入门和输出门;GRU保持了LSTM的效果同时又使结构更加简单。

在探索过程中,我们采取了两种训练策略进行训练:

首先是整首训练:给每个歌词 两个标识符作为开头和结尾,将每首歌词独立作为样本放入模型进行训练。整首训练的弊端是歌词序列长度较大,模型训练时会弱化远端信息;数据量较少,训练效果不好;无法控制输出歌词长度。

接下来我们采取了句训练:将歌词数据集每句拆分成一行,作为整体进行训练。训练时随机采样某一定长度的句组构成batch。句训练的优点是可以生成指定长度的歌词;可以自定义歌词的生成输入(歌词开头)。

在训练过程中,我们采用adam优化器,设置起始学习率为0.001,用交叉熵损失函数做反向传播。对于纯歌词样本数据,我们发现在训练了10000个epoches后,模型的过拟合程度较高,生成的歌词文本有较多和原文重复。故取节点10000作为截取保存点。同样的,对于歌词+诗样本数据,我们训练了40000个epoches。

GRU生成苏打绿风格歌词

然后——由于作者是较为资深的苏打绿歌迷——所以我知道老吴很喜欢夏宇的诗啊——不信你们看看——

所以我不由得想到,假如把夏宇的诗词也加入训练,是不是会有更神奇的效果~

GRU生成苏打绿+夏宇风格歌词

啊总之这个歌词肯定是不能直接拿来用,但是自己看看,然后修改修改,还是很好用的~


最后我送上一个Bonus~(对于打粉来说可能不是,嘻嘻,是公开的秘密~)

就,吴青峰就是诗人啊。

这是秋专辑里的所有歌的歌名。

这是每首歌的最后一句:

大家把最后一个字连起来,读一读?

致敬苏打绿,我永远爱你们呀。

最后@飞奔的咸鱼,我的队友,嘻嘻。

参考:

  1. 新词发现

新词发现 - sinat_33731745的博客 - CSDN博客?

blog.csdn.net

2. GRU神经网路

深度学习:循环神经网路(RNN)的变体LSTM、GRU - std=c++11 - CSDN博客?

blog.csdn.net
图标

推荐阅读:
相关文章