手把手 | 用R分析宋詞三百首 自己動手寫個“機器詩人”

最近中國詩詞大會很受歡迎,才女武亦姝憑借超強的記憶力和超快的反應能力一炮走紅,成為大家心目中的偶像。
在欣賞節目的同時,我也不禁想到,既然古代的詩人能夠創作出這些美好的詩篇,那我是不是也能創作幾首屬於自己的詩詞作品呢?可惜,經過一番嚐試,我發現自身的文學功底不夠,恐怕無法完成這樣艱巨的任務。看來人和人還是有很大的差距。
當然,我並沒有氣餒。就像著名的無限猴子定理闡述的那樣,哪怕是讓一隻猴子在打字機上隨機地按鍵,隻要按鍵的時間足夠長,那麼幾乎必然能夠打出任何特定的文字,甚至是莎士比亞的全套著作。我覺得我的編程能力應該比猴子還是要略強一籌,所以打算試試用我熟悉的語言R 來創作幾首『歪詩』。
詞頻分析
既然要創作詩詞,那麼就要先了解詩詞中最常出現的詞匯和意象是什麼。我在 github 上找到了一些古典中文的語料庫(鏈接),其中有不少唐詩宋詞的文本,隻不過是繁體的。我選擇了《宋詞三百首》作為了我的文本庫,對它進行詞頻分析。
其實做法很簡單,大概就是分這麼幾步:
-
把文本拆分成一個一個的單詞;
-
把單詞按照出現的頻率、次數進行排序
-
用可視化把結果展示出來
下麵的部分我會討論一下具體的操作,不感興趣的觀眾請往後翻到結果的部分。
第一步、第二步。
第一步
-
導入文本庫:
> fileName <- "宋詞三百首.txt" > SC <- readChar(fileName, file.info(fileName)$size)# 大概檢查一下> substr(SC, 1000, 1100)[1] "醒。送春春去幾時回,臨晚鏡。傷流景。往事後期空記省。○沙上並禽池上暝。雲破月來花弄影。重重簾幕密遮燈,風不定。人初靜。明日落紅應滿徑。\n\n詞牌:青門引\n作者:張先\n詞文:乍暖還輕冷。風雨晚來方定。庭軒寂"
-
用分詞包『結巴R』 (鏈接) 裏麵的 worker() 公式完成分詞:
> cc = worker()> analysis <- as.data.frame(table(cc[SC]))# 重新排序> analysis <- analysis[order(-analysis$freq),]# 簡單改變一下文件的命名、格式> names(analysis) <- c("word","freq")> analysis$word <- as.character(analysis$word)# 看一下這個分詞文件的開頭> head(analysis) word freq470 作者 3106120 詞文 3106121 詞牌 3101024 又 751014 去 553124 月 54
看來在宋詞三百首中,出現最多的詞語是『作者』,『詞文』,『詞牌』,總共出現了310次。這是因為每首詩詞開始時,文檔中都會介紹這首詩詞的作者、詞文和詞牌,從而幹擾了我們的文本分析。
第二步
我用 R 包 wordcloud2把結果簡單地進行了一下可視化:
wordcloud2(analysis)
然後得到了這張圖。
嗯,碩大的一個『詞文』出現了很多次,看來我們在可視化的時候要把它去掉。
我把出現頻率大於300次的詞語刨除之後,根據分詞結果的字數(一字,二字,三字)重新進行了可視化,結果如下:
wordcloud2(analysis[analysis$freq>1& analysis$freq < 300 & nchar(analysis$word) == 1,])wordcloud2(analysis[analysis$freq>1& analysis$freq < 300 & nchar(analysis$word) == 2,])wordcloud2(analysis[analysis$freq>1 & analysis$freq < 300 & nchar(analysis$word) == 3,])
現在的結果就正常多了。我們看到,一個字的詞語中,出現頻率較多的有『誰』,『又』,『人』,『去』,『夢』, 『是』, 『處』,『月』 等等。
兩個字的詞語中,『何處』,『斜陽』,『相思』這些詞使用頻率最多,給我一種在看網絡小說標題的感覺。
三個字的詞語中,出現最多的往往是詞牌名和作者名。
完成了簡短的詞頻分析,下麵就要開始最重要的『詩詞創作』部分了!
詩詞創作
準備
創作宋詞,先要明確一個詞牌名。我選擇了李白的《清平樂·畫堂晨起》作為範例。
畫堂晨起,來報雪花墜。高卷簾櫳看佳瑞,皓色遠迷庭砌。盛氣光引爐煙,素草寒生玉佩。應是天仙狂醉,亂把白雲揉碎。
R 的中文分詞包『結巴R』的功能中,有一項可以用來分辨詞語的詞性。我將範例進行分詞後,再用這項功能分析一下各部分的詞性。
> cipai <- "畫堂晨起,來報雪花墜。高卷簾櫳 看 佳瑞,皓色遠 迷 庭砌。盛氣光引 爐煙,素草寒生玉佩。應是天仙狂醉,亂把白雲揉碎。"> tagger <- worker("tag")> cipai_2 <- tagger <= cipai> cipai_2 n x x n v a n g v "畫堂" "晨起" "來報" "雪花" "墜" "高" "卷簾" "櫳" "看" x x a v x n x x x "佳瑞" "皓色" "遠" "迷" "庭砌" "盛氣" "光引" "爐煙" "素草" x nr x n x d p nr v "寒生" "玉佩" "應是" "天仙" "狂醉" "亂" "把" "白雲" "揉碎"
其中每個字母代表什麼詞性,我也沒有很理解。據我的猜測,n 應該是名詞,x是沒有分辨出來的詞性,v是動詞, a是形容詞,至於『nr』, 『p』, 『d』是什麼,實在是猜不出來,在幫助文檔中也沒有找到。如果有朋友知道的話,希望能不吝賜教。
最後,我從之前提煉的宋詞詞頻庫中,選取了至少出現過兩次的一字或兩字詞語,作為詩詞創作的素材庫:
> example <- subset(analysis, freq >1 & nchar(word) <3 & freq < 300)# 提取詞性文件> cixing <- attributes(cipai_2)$names# 將素材庫進行詞性分類> example_2 <- tagger <= example$word
創作
下麵,我們終於要開始用 R 創作詩歌了!我自己想了一個創作的算法,可以說很簡單,甚至說有點可笑。
步驟是這樣的:我從範本詞牌的第一個詞開始,隨機在素材庫中選取詞性相同,字數相等的單詞,填入提前設置好的空白字符串中。
舉個例子,原詩的第一個詞是『畫堂』,是個二字的名詞。那麼,我就在素材庫中隨機選擇一個二字的名詞,填入這個空間中。然後,繼續分析下一個詞。
具體方程的代碼如下:
> write_songci <- function(m){set.seed(m)empty <- ""for (i in 1:length(cipai_2)){ temp_file <- example_2[attributes(example_2)$name == cixing[i]] temp_file <- temp_file[nchar(temp_file) == nchar(cipai_2[i])] empty <- paste0(empty, sample(temp_file,1)) }result <- paste0(substr(empty, 1,4), ",", substr(empty,5,9),"。", substr(empty, 10,16), ",", substr(empty, 17,22),"。", substr(empty, 23,28), ",", substr(empty, 29,34),"。", substr(empty, 35,40), ",", substr(empty, 41,46),"。")}
結果
做了這麼多工作,終於到了驗收結果的部分。請各位來欣賞幾首 R 創作的歪詞作品吧:
> lapply(1:5, write_songci)[[1]][1] "幽香凝佇,春空賞花回。淨關塞旆感春歸,朝天淺爭前度。江聲已失無跡,香非凝笑秋千。過盡細雨歸鴻,欲對蓬萊歸來。"[[2]][1] "流年漏永,春空愁腸覺。穩黃花笮收敗壁,數峰深鋪已斷。寄語舊香非煙,歸夢如夢殷勤。沈沈啼鶯老來,卻把丁香不堪。"[[3]][1] "愁腸簾外,前度芳心困。少陽臺瘞切桃蹊,幾人細鎖新樣。腸斷缺月中酒,潘鬢行遍何曾。歸雁芳草修竹,不對秋水垂下。"[[4]][1] "一川晏殊,阮郎斷鴻展。重暮雲菰訪楊花,畫閣滿聽金尊。敗葉孤城雪滿,晝永隋堤碧雲。無準黃金年光,漸因綺羅開時。"[[5]][1] "煙柳清景,謝娘桃花如。窄蝴蝶琮誤中酒,花間碎掛斷煙。幽夢曉來千樹,蕭娘數峰翩翩。蟲網暗想未醒,曾向丁寧聚散。"
既然是計算機生成的詩,自然談不上什麼文學性。不過,雖然大部分內容看上去不知所雲,有些詞句還是有些意思的,比如『幽香凝佇』,『愁腸簾外』,『孤城雪滿』等等。之前在調試的時候,還出現過類似於『風煙淚暗霜前, 古岸頻聽金蓮』這樣的詞句,無厘頭之餘,莫名地居然還有些押韻。
感想
這篇文章到此就結束了,希望大家讀得還愉快。最後談談自己的感想。
-
很多讀者可能會問,既然用 R 寫出來的詩毫不合文理,為什麼還要進行這樣的工作呢?這種練習是不是在侮辱中文和古典詩詞呢?我倒是覺得,我們對語言應該存有一種開放的態度。詩詞說到底,也是一種風雅的文字遊戲。我們又何嚐不能抱著遊戲的態度,把這個練習當做一個有趣的消遣呢?
-
用計算機代碼作詩的主意並非是我原創。清華大學早在一年前就推出過作詩機器人薇薇,宣稱可以通過圖靈測試。
-
有些詞句,如『何處東風約』,『萬朵千峰映碧垂』等還是略顯生硬,不過比我這裏創作的詩詞已經強的太多了。本文的小程序比較簡短,總共隻使用了不到50行代碼,可以說是比較粗略的一個版本,僅供大家參考。感興趣的讀者可以設計更精密的算法,使用更高級的統計方法改進創作的質量。
-
古詩詞向來被認為具有很高的藝術價值。今天的我們有越來越多的工具,可以係統化地總結、歸納詩詞的規律,這大概也是過去的詩人怎麼也想不到的。或許有一天,計算機真的能學習出作詩的秘訣,給我們帶來更多全新的靈感和更好的詩句。我們拭目以待。
-
原文發布時間為:2017-03-06
本文來自雲棲社區合作夥伴“大數據文摘”,了解相關信息可以關注“BigDataDigest”微信公眾號
最後更新:2017-05-23 16:33:41
上一篇:
演講實錄丨任福繼 闊步迎接人機共生時代 --談機器人智商和情商
下一篇:
Nature重磅| IBM再放大招!量子計算今年實現商業通用!
WinForm中提示Circular base class dependency involving 'TestEncryption.Form' and 'TestEncryption.Form
Snapchat正挑戰Facebook統治地位 激戰短消息
Java Reflection(九):泛型
安華金和成為阿裏“數據安全合作夥伴計劃”首批成員
android識別 單擊和雙擊事件
Windows下的tail一二三:tail、BareTail、WinTail
RDS 高可用保障之 – 隱式主鍵
OSS社區工具與插件全新升級
poj 2538 WERTYU
C#讀書筆記