马尔科夫链
- 最近看了一篇文章,用二十行shell写的一个马尔科夫链
- 正好自己比较喜欢shell,现在摘录下来
代码
mrkfeed.awk
: 这个用来成一个模型文件。./mrkfeed.awk < chatlog.txt >> model.mrkdb
#!/usr/bin/awk -f
{
for(i=1; i<NF; i++) {
print $i, $(i+1)
}
print $i
}
./mrkwords.sh
:生成一段文字的过程
#!/bin/sh
file="${1:-~/.mrkdb}" # 选择参数当中第一个以.mrkdb结尾的文件
n="${2:-1}" # 要生成的词的最大数量
key="$3" # 起始单词
[ ! -z "$key" ] && echo "$key"
[ "$n" -le 0 ] && exit
if [ -z "$key" ]; then
word=$(shuf -n 1 < "$file" | cut -d' ' -f1)
else
word=$(grep -Fw "$key" < "$file" | awk -v key="$key" '$1 == key {print $0}' | shuf -n 1 | awk '{print $2}') || exit
[ -z "$word" ] && exit
fi
# 单词个数-1, 重复执行
exec "$0" "$file" "$(( n - 1 ))" "$word"
执行过程
# 清洗聊天文件,使用语料生成一个模型文件
corpus=/usr/share/fortunes/goedel # 英文语料
sed -e '/^%$/d' < $corpus >> goedel.txt
./mrkfeed.awk < goedel.txt >> model.mrkdb
# 使用模型文件生成一段对话
./mrkwords.sh model.mrkdb 50 | tr '\n' ' '
思考
这里的模型文件实际上是一个一个的词对,比如说(is, me)这个词对在语料当中出现了100次,那么在模型文件当中就会有100行(is, me),每次抽取的时候实际上是根据当前词对的概率最大来进行的,所以非常的短小和精妙
同时我也想起了word2vec算法在实现负采样的时候,实际上也是生成一个非常巨大的词表,按照词的概率填充词表,负采样的时候,就随机从这个巨大的词表当中抽取负样本,这样就是按照概率来抽取负样本
文章来源
- https://0x0f0f0f.github.io/posts/2019/11/really-fast-markov-chains-in-~20-lines-of-sh-grep-cut-and-awk/