暴力写诗(二)(单字概率)

上篇说到,我们已经获取了 118722 首五言诗,并且格式是完美的 JSON 格式。接下来,我们就要开始动手了。

首先,我们来理一理思路。我们要写的五言诗一共是 4 行,每行 5 个字,合计 20 个字。例如:

《登鹳雀楼》(能写出这样的诗,是我们的梦想)

白日依山尽黄河入海流欲穷千里目更上一层楼


我们要做的事,其实就是在所有的汉字中,挑出 20 个放到这个 5 x 4 的表格中,一个位置放一个字,并且,重点在于,放的合适

万诗开头难,我们从第一个字开始。一首诗的第一个字应该是什么字,或者说应该是哪些字呢?我们把手头的10来万首诗拿出来看一下。

大家可以设想一下,如果把这 10 多万诗的每一首的第一个字都记下来,对于一个字来说,每出现一次我们就划一个正字,那么我们就知道了古人们写诗时,第一个字的用字习惯啦!(问题:这个习惯存在吗? 有用吗?)

而如果我们把每一个位置,古人写诗时的用字习惯都统计出来,那岂不离写出好诗近了很多?这实在是太暴力、太粗糙、太有效啦!

赶紧行动,看汉字数数开始:

import sys
import json

with open('five.json', 'r', encoding='utf-8-sig') as f:
    data = json.loads(f.read())

word_frequency = {}
words_num = 0

for _ in data:
    poem = _['paragraphs']
    if poem:
        for sentence_num, sentence in enumerate(poem):
            # 去掉 ,和。
            sentence = sentence.replace('。', '')
            sentence = sentence.replace(',', '')
            # 有些诗中混入了奇怪的句子,要剔除
            if len(sentence) != 10:
                continue
            for word_num,word in enumerate(sentence):
                # 大于四句的诗,我们循环着计入
                pos = word_num + (sentence_num % 2) * 10
                if word in word_frequency.keys():
                    word_frequency[word][pos] += 1
                else:
                    words_num += 1
                    word_frequency[word] = [0 for i in range(20)]
                    try:
                        word_frequency[word][pos] += 1
                    except:
                        print(sentence)
                        print(pos)
                        sys.exit()

json_data = json.dumps(word_frequency, indent=4, ensure_ascii=False)
with open('words_freq.json', 'w', encoding='utf-8-sig') as f:
    f.write(json_data)

上面这段代码我们统计出了,这 10 多万首诗中,一共用到了 10754 个汉字(竟然这么多),对于每一个字,我们都统计出了它在一首诗中 20 个位置所出现的次数。打开生成的 words_freq.json,我们可以看到,例如:

 "花": [
        614,
        1085,
        782,
        1175,
        587,
        1025,
        1766,
        433,
        813,
        888,
        482,
        1434,
        726,
        719,
        538,
        791,
        827,
        301,
        1237,
        1019
    ],
    "乱": [
        252,
        166,
        205,
        114,
        329,
        105,
        157,
        378,
        204,
        67,
        234,
        56,
        148,
        139,
        227,
        108,
        178,
        429,
        109,
        107


也就是说,对于“花”字,我们统计出了,在一首五言诗中,第1到第20个位置,它出现过的次数。也就是

但是,统计出这个对于我们写诗并没有直接的用处啊!

对我们可能有用处的是,对于某一个位置,比方说第一个字,最有可能出现的字是哪一些,或者还有哪些字不可能出现在第一个字。

因此,我们需要将上面得到 words_freq.json 文件再重新统计一下。如何统计呢,按位置来统计:

import json

with open('words_freq.json', 'r', encoding='utf-8-sig') as f:
    data = json.loads(f.read())

pos_frequency = {}

for _pos in range(20):
    pos_frequency[_pos] = {}
    for _word in data.keys():
        if data[_word][_pos]:
            pos_frequency[_pos][_word] = data[_word][_pos]

json_data = json.dumps(pos_frequency, indent=4, ensure_ascii=False)
with open('pos_freq.json', 'w', encoding='utf-8-sig') as f:
    f.write(json_data)

通过上面这块代码,我们就得到了每一个位置,可能出现的字,以及那个字它总共出现的次数。现在让我们把每个位置出现的机率最大的100个字找出来吧!

import json

pos_top100 = {}

with open('pos_freq.json', 'r', encoding='utf-8-sig') as f:
    data = json.loads(f.read())

for _pos in data.keys():
    _data = data[_pos]
    # 对字典的值进行排序,返回一个二元祖组成的列表
    pos_top100[_pos] = sorted(_data.items(), key=lambda x:x[1], reverse=True)[:100]
    print(_pos)
    for _word in pos_top100[_pos]:
        print(_word[0], end=' ')
    print('')

json_data = json.dumps(pos_top100, indent=4, ensure_ascii=False)
with open('pos_top100.json', 'w', encoding='utf-8-sig') as f:
    f.write(json_data)

找出来的结果如下:

0
我 一 不 山 天 人 春 君 风 何 有 吾 自 老 清 江 秋 高 平 白 日 今 古 云 此 昔 大 野 世 万 南 谁 东 岂 三 夜 长 客 朝 西 小 水 相 行 青 故 去 未 寒 雨 幽 上 道 月 玉 岁 无 中 时 旧 四 归 独 远 地 明 出 石 欲 北 公 黄 百 新 忆 诗 草 但 子 金 为 孤 晚 当 五 所 千 二 前 已 少 竹 坐 十 落 久 花 文 海 生
1
人 生 来 日 风 年 山 子 月 有 君 知 时 水 云 我 雨 然 言 为 闻 事 行 道 中 家 门 色 客 公 心 如 昔 上 里 国 花 无 此 见 马 得 落 以 从 地 去 酒 书 物 者 气 居 朝 今 哉 树 当 老 路 世 下 游 意 石 声 身 作 思 处 之 林 与 阳 草 怀 木 欲 能 是 岁 不 夜 城 明 叶 光 海 诗 将 舟 士 高 看 雪 竹 古 鸟 天 出
2
不 无 有 一 三 何 天 如 山 千 多 风 春 非 虽 方 与 人 生 今 云 秋 出 自 未 青 知 来 初 江 清 已 日 得 为 开 长 亦 东 在 归 古 寒 从 行 当 犹 随 復 本 南 金 空 西 真 心 岂 同 新 入 久 高 临 忽 百 万 连 时 分 花 思 谁 黄 皆 白 见 闻 老 大 成 既 重 五 明 相 终 十 中 逢 登 固 通 两 朝 二 惊 看 欲 能 吹
3
不 无 山 何 云 中 人 可 天 相 如 有 为 风 自 一 三 已 所 未 千 上 南 年 清 时 生 难 江 高 秋 日 春 花 水 我 多 十 其 新 长 前 成 寒 金 行 城 月 方 林 门 明 家 此 下 子 来 初 幽 万 阳 朝 世 归 西 公 书 知 空 犹 能 君 之 大 东 古 心 雨 百 青 华 流 远 馀 名 里 尘 海 白 玉 佳 吾 与 復 仙 深 飞 声 溪 将
4
人 日 子 远 事 去 水 月 里 客 地 来 雨 下 路 上 间 在 处 老 外 道 尽 酒 时 山 后 心 好 士 色 中 乐 意 树 久 出 晚 雪 者 见 落 重 石 别 起 梦 游 白 年 气 语 合 静 云 寺 门 节 草 物 国 夜 少 生 近 书 竹 动 风 行 急 归 至 古 马 叶 此 影 海 言 得 明 望 花 木 秀 薄 迹 世 足 过 手 诗 死 有 长 早 曲 天 深
5
不 一 风 山 天 何 清 无 人 春 高 云 江 万 秋 此 相 今 千 寒 归 未 长 三 青 日 心 幽 谁 有 孤 中 新 我 行 白 空 诗 岂 吾 花 时 自 所 君 东 百 为 西 金 闲 南 如 飞 终 生 朝 来 林 独 松 深 黄 老 烟 还 安 文 欲 霜 四 平 开 身 亦 其 夜 大 岁 犹 当 明 微 出 远 水 名 溪 香 萧 坐 得 神 流 世 重 月 宁 可 下
6
风 人 山 来 日 此 我 然 为 心 生 云 年 有 花 与 月 事 子 以 水 门 见 行 声 復 知 气 时 作 君 不 家 色 言 中 雨 书 如 意 光 物 得 是 道 流 名 里 寒 林 深 高 无 酒 怀 去 落 在 地 者 明 马 处 上 能 世 空 之 身 歌 居 若 思 下 归 情 游 成 叶 路 木 觉 客 天 语 朝 亦 望 诗 公 城 香 舟 闻 欲 夜 闲 从 今 树
7
不 一 无 亦 有 自 如 日 未 在 何 入 已 万 出 为 得 见 白 復 天 独 更 岂 非 生 水 多 与 欲 尚 犹 古 此 相 千 夜 落 上 空 满 山 百 几 风 老 可 忽 心 长 事 月 三 玉 皆 谁 清 到 起 雨 当 似 半 下 照 方 动 正 去 共 两 同 旧 过 云 今 意 春 望 人 乃 又 久 是 远 岁 向 莫 秋 成 五 来 道 雪 尽 草 若 常 四 安
8
不 自 可 一 无 未 有 相 所 山 人 云 已 中 如 水 上 为 月 与 日 天 何 清 其 风 此 里 復 更 我 子 玉 夜 能 下 得 亦 江 在 生 难 欲 见 成 幽 秋 南 长 时 雨 海 春 易 寒 石 旧 花 远 高 古 气 万 白 空 故 路 世 前 酒 青 三 地 林 道 客 树 十 金 百 千 心 四 新 馀 老 来 九 马 之 后 草 归 露 知 大 几 吾 行 深
9
人 时 深 风 春 中 生 长 年 行 秋 心 新 清 明 情 开 天 游 声 归 山 来 空 流 间 寒 香 知 然 云 尘 身 门 家 多 书 城 衣 迟 飞 林 名 闲 诗 花 同 馀 阴 成 期 还 烟 居 光 前 愁 平 稀 分 微 轻 难 头 通 亲 枝 留 红 边 凉 楼 悲 吟 贤 闻 传 乡 言 台 泉 州 休 关 鸣 穷 过 回 真 舟 水 里 阳 音 寻 方 之 何 东 初
10
不 一 何 我 谁 人 此 山 天 自 风 君 相 今 有 岂 无 吾 清 平 未 如 欲 长 高 老 云 江 归 春 但 莫 明 时 行 三 愿 白 独 青 日 更 秋 故 所 安 空 万 从 中 为 东 夜 虽 当 若 朝 世 大 古 坐 客 水 西 幽 千 百 小 可 惟 南 因 况 忽 寒 诗 新 孤 公 终 野 却 上 黄 遥 还 向 远 心 去 方 只 已 是 四 生 唯 他 应 道
11
知 来 人 生 年 风 时 然 山 有 君 言 云 心 为 日 中 无 闻 能 如 我 当 行 今 子 门 此 花 朝 得 书 从 家 将 看 声 公 哉 怜 以 怀 思 何 见 事 应 身 须 游 月 令 光 头 是 诗 之 成 明 流 名 逢 情 间 非 馀 林 高 深 天 水 期 道 寒 欲 作 衣 问 舟 堂 不 者 阳 歌 归 去 居 方 城 因 物 意 与 前 客 华 兹 夫 酒 上
12
不 无 一 有 如 何 三 天 千 虽 今 与 知 多 山 方 自 人 非 风 未 归 得 亦 犹 为 春 清 同 长 生 云 随 从 万 出 真 来 空 秋 在 青 已 行 谁 当 相 江 日 能 新 百 忽 开 岂 应 见 时 皆 还 成 东 入 金 思 復 初 心 两 五 终 寒 南 君 花 明 此 高 看 古 重 欲 白 既 大 分 二 吾 黄 聊 将 闻 西 久 固 更 独 望 老 正
13
不 有 可 无 自 一 何 山 未 相 人 中 上 所 已 日 云 此 天 如 风 为 其 下 我 水 月 子 清 里 万 世 白 时 得 雨 来 与 夜 归 玉 古 生 三 年 千 高 海 大 远 南 知 江 十 行 长 处 復 在 道 明 见 地 百 春 老 能 事 成 花 旧 公 草 外 客 家 林 新 门 前 石 心 秋 君 幽 之 难 寒 馀 多 阳 几 欲 吾 金 城 尘 北 马 物
14
人 事 去 子 日 处 客 月 意 在 来 水 远 间 下 里 地 酒 路 上 者 心 尽 雨 乐 中 见 老 道 时 色 外 后 语 梦 士 此 好 出 树 石 落 起 山 游 得 别 晚 夜 物 雪 言 年 归 望 白 风 节 气 手 马 草 生 之 近 眼 醉 行 少 书 句 至 笑 足 力 我 重 云 曲 过 久 国 合 叶 影 问 动 思 友 死 兴 迹 苦 门 恨 花 息 诗 志 然
15
不 一 何 无 风 此 谁 天 相 万 未 山 清 千 人 归 犹 高 长 吾 春 云 空 为 今 岂 白 时 有 自 终 日 应 更 还 我 秋 心 江 行 独 三 亦 安 寒 老 所 莫 百 青 来 聊 欲 孤 如 可 幽 已 花 岁 宁 诗 飞 得 坐 中 但 明 夜 新 大 水 四 月 从 君 其 身 知 落 松 烟 况 多 远 玉 生 当 流 同 且 金 东 重 小 深 草 世 方 西
16
此 日 与 我 有 为 是 人 得 復 月 事 见 以 作 风 子 不 然 意 水 来 山 处 气 里 雨 心 道 色 觉 知 去 在 酒 君 落 欲 物 地 年 用 语 云 生 上 下 路 笑 能 首 如 自 马 可 世 使 时 言 望 古 亦 夜 老 花 树 鸟 思 者 之 坐 叶 必 入 似 影 木 中 若 客 声 足 向 石 尔 无 尽 草 行 看 往 外 门 海 手 梦 载 歌 家 书
17
不 一 有 无 亦 自 在 为 如 未 见 何 更 已 得 入 白 日 出 復 此 万 是 独 岂 与 天 欲 几 老 满 生 空 非 可 相 上 到 尚 故 两 共 莫 犹 夜 水 落 问 正 千 百 当 长 月 玉 同 向 谁 旧 照 皆 似 下 又 风 寄 心 作 多 望 古 忽 过 起 山 安 尽 五 动 半 事 若 看 清 对 去 人 即 成 乃 方 今 且 九 意 还 知 终 醉 远
18
不 无 人 相 可 云 中 山 自 何 一 如 为 天 所 清 风 有 生 时 成 其 与 江 能 未 长 花 春 已 难 吾 年 三 此 寒 谁 归 秋 金 青 前 我 上 来 心 新 馀 高 空 君 日 南 水 知 行 幽 林 飞 平 月 阳 千 西 明 得 子 书 深 朝 同 尘 家 重 公 华 龙 復 之 衣 玉 里 东 门 在 下 离 城 烟 苍 黄 孤 头 流 夜 忘 多 须 白 足
19
人 心 生 风 时 声 来 归 情 中 春 行 年 山 明 知 秋 深 天 书 流 诗 然 云 清 长 衣 名 尘 同 花 游 香 期 空 飞 多 寒 还 间 城 家 新 愁 门 身 前 开 言 闲 头 光 如 吟 留 亲 平 迟 林 难 轻 音 烟 舟 何 枝 成 闻 传 看 悲 阴 泉 思 忧 穷 馀 阳 回 寻 关 台 凉 楼 边 贤 歌 神 青 君 船 翁 休 通 乡 居 州 安 为 颜

在古人的智慧凝结成的五言诗中,第1到第20个字,每一个字出现几率最大的100个字,我们都找出来啦。那么我们可以写成诗了,写的方法很简单,从每一个位置的100个字中,随机挑一个,组成一首诗。让我们试试,先写个 5 首吧!:

import json
import random

with open('pos_top100.json', 'r', encoding='utf-8-sig') as f:
    data = json.loads(f.read())

for _ in range(5):
    poem = []
    for _pos in data.keys():
        _list = data[_pos]
        poem.append(_list[random.randrange(0,100)][0])
    for _, word in enumerate(poem):
        if _ % 5 == 0:
            print('')
        print(word, end='')
        
    print('')

运行一下!激动人心的诗,写出来啦:

山诗时山树
花香望南门
从堂与物月
西歌几风间
​
行今久清下
所言是行开
平须天多梦
身欲不烟光
​
坐与不来诗
白若五时过
此心忽玉至
夜行忽心名
​
君古五百死
千月云生山
坐名皆客云
远必尚来通
​
吾昔真阳有
下色古深深
故此復花时
人知看秋楼


这五首诗,读一遍,再读一遍,再读一遍,坑爹嘛!你要说这是诗!语文老师已经坐不住了。

不过,不用着急,虽然这都不是诗,但你的承认,也差不多有那么个意思了嘛!让我们来细细思考下,要说这是诗的话,它分别有些什么问题。

第一:最明显的,你说它是诗,但它根本不押韵!也就是说,第二行最后一个字和第四行最后一个字不是同样的韵母。

第二:平仄不对。一三五虽可不论,但最起码两联中的“二四”平仄不成对

第三:最关键,最难也是最致命的,那就是它狗屁不通! 话都没写通,你怎么好意思说它是一首诗呢?


问题找出来了,接下来我们就一个一个的解决吧!好诗指日可待啦!


<待续>

发布于 2019-11-22

文章被以下专栏收录