漫谈《集合啦!动物森友会》的大头菜价格趋势与马尔可夫链

前言

还要买更多吗?(曹卖说话有奇怪的口音哈哈哈哈

虽然笔者自己并不是炒菜党,每周只是象征性地囤上五六百棵刷成就里数(以及用来吃),但是大头菜价格背后的细节还是很有些意思的。以下是部分大佬已经做过的工作(orz

下面先简单复述一下大头菜的价格趋势。

大头菜价格趋势

动森中大头菜价格的4种趋势如下,中文译名似乎已经约定俗成了。

  • 0型:Random/Fluctuating(波动型);
  • 1型:Large Spike(三期型);
  • 2型:Decreasing(下跌型);
  • 3型:Small Spike(四期型)。

关于每种趋势的具体数据表现,请参见上面的链接。

在每一周中,大头菜价格的趋势是固定的,直到下个周日曹卖来到岛上时才会变。大头菜的价格在一周间的每天上午、下午都会变动,亦即一周可以分为12期(周一到周六的每个半天)。

上周的大头菜价格趋势会以一定概率影响本周的价格趋势(玩家初始购买大头菜的那一周默认为四期型),通过代码可以得出概率值如下表。

可见,大头菜价格趋势的变化是一个马尔可夫链,完全符合马尔可夫性质,下面先从数学角度介绍之。

马尔可夫链与马尔可夫性质

以下给出马尔可夫链的形式化定义。

设有随机过程{X(t), t∈T},其中时间T={0, 1, 2, ...},有限状态空间I={i0, i1, i2, ...}。

若对任一时刻n,以及任意I中的状态(j0, j1, ..., jn-1, j, k),均有:

P[X(n+1)=k | X(n)=j, X(n-1)=jn-1, ..., X(1)=j1, X(0)=j0] = P[X(n+1)=k | X(n)=j]

则将X(t)称为一个离散时间马尔可夫链(discrete-time Markov chain, DTMC)

马尔可夫链是马尔可夫过程(Markov process)在离散时间、有限状态空间条件下的表现,它符合马尔可夫性质(Markov property),即:

X(t)在未来时刻n+1的状态X(n+1)=k只与现在时刻n的状态X(n)=j有关,而与过去的状态X(n-1)=jn-1, ..., X(1)=j1, X(0)=j0全部无关。

这种“未来与过去无关,只与现在有关”的性质非常重要,也被称为“无记忆性”(memorylessness)。看官如果在算法课上深入学习过动态规划的话,会知道动态规划必须满足“无后效性”,它与“无记忆性”是同义词。

转移概率与转移矩阵

说完了定义,再回头看看大头菜价格的特征:

上周的大头菜价格趋势会以一定概率影响本周的价格趋势。

可见确实具有马尔可夫性质,并且是(关于时间)齐次的——亦即它的一步转移概率Pjk = P[X(n+1)=k | X(n)=j]与n的取值无关,而是完全遵循上文表格中给出的概率分布。所以,在Turnip Prophet小程序中,会要求玩家输入上周的大头菜价格趋势。

如果我们将一步转移概率的表格用矩阵的形式表示,就称为一步转移矩阵,如下所示。

一步转移概率和一步转移矩阵是马尔可夫链的核心,很容易推导出齐次马尔可夫链的n步转移矩阵和一步转移矩阵之间的关系:Pn = P1n。根据Chapman-Kolmogorov方程,可以得出:

P(n) = P(0)Pn = P(0)P1n

也就是说,一个马尔可夫链的概率分布完全由它的初始概率分布与一步转移矩阵决定,这是用马尔可夫链进行预测的基础。

遍历性与极限分布

在Turnip Prophet小程序中,如果玩家选择“不知道”上周大头菜的价格趋势,该如何推算出本周趋势价格趋势的概率呢?有了上一节的铺垫,我们先以四期型为初始状态,迭代计算30次趋势的概率分布,Python代码如下。

init = np.array([0.45, 0.25, 0.15, 0.15])
trans_matrix = np.array(
    [[0.2, 0.3, 0.15, 0.35],
    [0.5, 0.05, 0.2, 0.25],
    [0.25, 0.45, 0.05, 0.25],
    [0.45, 0.25, 0.15, 0.15]]
)
current = init
for i in range(30):
    result = np.dot(current, trans_matrix)
    print(i, "\t", result)
    current = result

查看输出结果。

0    [0.32   0.2525 0.1475 0.28  ]
1    [0.353125 0.245    0.147875 0.254   ]
2    [0.34439375 0.24823125 0.1474625  0.2599125 ]
3    [0.34682063 0.24706594 0.14766531 0.25844813]
4    [0.34611508 0.24746091 0.14758677 0.25883725]
5    [0.34632692 0.24733093 0.14761437 0.25872778]
6    [0.34626194 0.24737303 0.14760511 0.25875991]
7    [0.34628214 0.24735951 0.14760814 0.2587502 ]
8    [0.34627581 0.24736383 0.14760716 0.25875319]
9    [0.34627781 0.24736246 0.14760748 0.25875226]
10   [0.34627718 0.24736289 0.14760738 0.25875255]
11   [0.34627738 0.24736276 0.14760741 0.25875246]
12   [0.34627731 0.2473628  0.1476074  0.25875249]
13   [0.34627733 0.24736279 0.1476074  0.25875248]
14   [0.34627733 0.24736279 0.1476074  0.25875249]
15   [0.34627733 0.24736279 0.1476074  0.25875248]
16   [0.34627733 0.24736279 0.1476074  0.25875248]
17   [0.34627733 0.24736279 0.1476074  0.25875248]
18   [0.34627733 0.24736279 0.1476074  0.25875248]
19   [0.34627733 0.24736279 0.1476074  0.25875248]
20   [0.34627733 0.24736279 0.1476074  0.25875248]
21   [0.34627733 0.24736279 0.1476074  0.25875248]
22   [0.34627733 0.24736279 0.1476074  0.25875248]
23   [0.34627733 0.24736279 0.1476074  0.25875248]
24   [0.34627733 0.24736279 0.1476074  0.25875248]
25   [0.34627733 0.24736279 0.1476074  0.25875248]
26   [0.34627733 0.24736279 0.1476074  0.25875248]
27   [0.34627733 0.24736279 0.1476074  0.25875248]
28   [0.34627733 0.24736279 0.1476074  0.25875248]
29   [0.34627733 0.24736279 0.1476074  0.25875248]

我们可以发现,4种趋势的概率分布收敛到了[0.34627733 0.24736279 0.1476074 0.25875248]。也就是说,当玩家买入大头菜的次数比较多之后,本周大头菜价格趋势为波动型、三期型、下跌型、四期型的概率分别约为34.6%、24.7%、14.8%和25.9%。这四个值正好就是当玩家选择“不知道”上周大头菜的价格趋势时,预测器使用的概率:

function get_transition_probability(previous_pattern) {
  if (typeof previous_pattern === 'undefined' || Number.isNaN(previous_pattern) || previous_pattern === null || previous_pattern < 0 || previous_pattern > 3) {
    // TODO: Fill the steady state pattern (https://github.com/mikebryant/ac-nh-turnip-prices/pull/90) here.
    return [0.346278, 0.247363, 0.147607, 0.258752];
  }

  return PROBABILITY_MATRIX[previous_pattern];
}

我们还可以将代码中的初始分布换成其他值,最终会收敛得到一样的结果,这种特性称为马尔可夫链的遍历性。也就是说,如果对状态空间中的一切状态i、j,存在与i无关的常数π(j),使得lim pij(n)=π(j),那么该马尔可夫链就具有遍历性。另外,如果Σ π(j) = 1,那么π(j)叫做转移概率的极限分布

周中大头菜具体价格的预测

这部分与马尔可夫链的关系就不大了。在根据上周的大头菜价格趋势推断出本周趋势的概率之后,就是根据复杂的随机化算法(假设符合正态分布)对不符合各趋势的价格区间做逐一排除,最终为玩家呈现出可能性最高的价格组合。具体逻辑可以参考Turnip Prophet代码中的predictions.js文件(比较长),以及issues区中的说明与讨论

The End

明天早起搬砖,民那晚安晚安。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容