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