说在前面

美食(图片来源于互联网).jpg在空间侧边栏的笔者的自我介绍中,有一行是“厨房爱好者”,虽然笔者不怎么会做菜,但确实,厨房是我的一个爱好。当然,笔者的爱好很多,数学、物理、天文、计算机等,都喜欢,都想学,弄到多而不精。在之前的文章中也已经提到过,数据挖掘也是我的一个爱好,而当数据挖掘跟厨房这两个爱好相遇了,会有什么有趣的结果吗?

笔者正是做了这样一个事情:从美食中国的家常菜目录下面,写了个简单的爬虫,抓取了一批菜谱数据下来,进行简单的数据分析。(在此对美食中国表示衷心感谢。选择美食中国的原因是它的数据比较规范。)数据分析在我目前公司的高性能服务器做,分析起来特别舒服~~

这里共收集了18209个菜谱,共包含了9700种食材(包括主料、辅料、调料,部分可能由于命名不规范等原因会重复)。当然,这个数据量相对于很多领域的大数据标准来说,实在不值一提。但是在大数据极少涉及的厨房,应该算是比较多的了。

简单的统计

最简单可以做的,就是对材料进行统计分析。大家猜一下,出现最多的什么呢?

不用对美食有什么研究,读者都应该可以想到,出现最多的肯定是盐!盐常被称为“百味之首”,很少有菜是不放盐的。接下来是料酒,再接下来是生抽,都是调味料、配料等,从中也可以看出,中国菜是非常讲究用料的,各种配料让人满目林立。主菜中,土豆出现在28位,五花肉出现在38位,等等。

盐 11200
料酒 4601
生抽 4413
姜 3671
葱 2854
鸡精 2579
白糖 2440
糖 2303
油 2297
蒜 2058
鸡蛋 1924
酱油 1883
老抽 1625
胡椒粉 1619
花椒 1571
胡萝卜 1324
......

Word2Vec的结果

把每个菜谱看成一个分好词的句子,我们可以用这个“语料库”来训练一个Word2Vec模型,看看能得到什么有趣的结果?(就算没得到结果也不要紧,反正是探索嘛。)整个训练过程居然很快,几乎不到一秒钟。

简单对不了解的读者科普一下,Word2Vec是一个可以将词语转化为实数向量的模型,词语只有转化为数字后,才能交给计算机处理。而Word2Vec得到的向量还有一些特殊性质,比如两个词向量的余弦值,代表着两个词的相似程度。

Word2Vec的模型训练出来后,首先可以做的是比较两个词语的相似度,有些结果是很普通的,比如

>>> pd.Series(model.most_similar(u'五花肉'))
0 (排骨, 0.882662177086)
1 (带皮五花肉, 0.866969347)
2 (干豆角, 0.864805340767)
3 (鹌鹑蛋, 0.850470840931)
4 (酸菜, 0.842567443848)
5 (鸭腿, 0.841659963131)
6 (三黄鸡, 0.837065219879)
7 (老卤汤, 0.828875720501)
8 (鸡珍, 0.827436089516)
9 (鲫鱼, 0.826281666756)

然而会有些让人意外的结果,比如:

>>> pd.Series(model.most_similar(u'鸡肉'))
0 (玉米, 0.939546108246)
1 (茶树菇, 0.914446234703)
2 (甜玉米, 0.888315618038)
3 (鲜虾, 0.88096922636)
4 (蟹味菇, 0.870144784451)
5 (红萝卜, 0.86743336916)
6 (意面, 0.864846467972)
7 (丘比沙拉汁, 0.860477805138)
8 (猪里脊, 0.85995388031)
9 (白蘑菇, 0.855247914791)

这里显然“鸡肉”跟“玉米”居然高度相似!这表明,它们之间肯定有不得不说的故事。

背后的原因在哪里呢?Word2Vec模型的原理在于词的共现,因此,这个现象的原因可能是:1、玉米和鸡肉经常放在一起煮;2、玉米和鸡肉经常分别和相似的菜料一起煮。事实上稍加观察,就会发现两者均有,主要是它们经常用来熬汤,配料也类似

含有鸡肉的菜谱(部分):
140 [鸡肉, 玛咖, 枸杞, 红枣, 桂圆, 莲子, 姜]
144 [鸡肉, 二荆条, 植物油, 老姜, 大蒜, 干辣椒, 花椒, 盐, 料酒, 生抽, 白糖]
267 [鸡肉, 土豆, 青椒, 洋葱, 面粉, 姜蒜, 小辣椒, 老抽, 白糖, 生抽, 花椒大料...
313 [鸡肉, 啤酒, 土豆, 花椒, 八角, 小辣椒, 姜蒜, 生抽, 老抽]
520 [鸡肉, 面包糠, 鸡蛋, 糯米粉, 生抽, 蚝油, 盐, 胡椒粉]
961 [胡瓜, 鸡肉, 虾干, 红枣, 姜, 八角, 葱]
1005 [糯米, 鸡肉, 虾仁, 姜丝, 葱花, 生抽, 蚝油, 胡椒粉, 淀粉]
1095 [鸡肉, 鸡蛋清, 面粉, 生姜, 大蒜, 料酒, 盐, 黑胡椒]
1178 [鸡肉, 牛奶, 盐, 胡椒粉, 蒜粉, 低筋面粉, 淀粉, 冰水, 花生碎, 食用油, 麦...
1551 [鸡肉, 口蘑, 洋葱, 干辣椒, 葱, 姜, 蒜, 花椒, 冰糖, 盐]

含有玉米的菜谱(部分):
106 [鸡翅, 排骨2~3块, 盐, 姜, 芹菜, 料酒, 胡萝卜, 玉米, 红枣, 洋参片, 虫...
172 [山药, 玉米, 龙骨, 盐, 姜]
316 [猪骨, 玉米, 铁棍准山, 红枣]
441 [玉米, 番茄, 豆腐, 植物油, 老姜, 大葱, 花椒, 盐, 牛肉粉]
450 [山药, 排骨, 胡萝卜, 生姜, 料酒, 十三香, 枸杞, 玉米, 葱段, 八角, 精盐]
483 [红萝卜, 南瓜, 西芹, 玉米, 西兰花, 松子]
485 [莲藕, 胡萝卜, 香菇, 花生, 红枣, 玉米, 姜片]
509 [排骨, 玉米, 杏鲍菇, 枸杞, 香叶, 味精, 盐]
789 [鸡翅, 金针菇, 香菇, 白菇, 鸡腿菇, 滑子菇, 干贝, 虫草花, 玉米, 盐, 姜,...
828 [肉丁, 玉米, 胡萝卜, 鱼露, 生抽, 食盐, 花生油]

看来我们的玩意还确实产生了一些有趣的结果,单从我们的经验可能不容易发现“鸡肉”跟“玉米”的相关性,然而通过数据挖掘,只要有了足够多的数据,均可以发现一些有趣的结果。类似的结果还有:牛肉跟鱿鱼的相似性达到了96%,跟土豆的相似性有91%,等等!大家可以看着下面的数据,试图解释一下牛肉跟鱿鱼的结果:

含有牛肉的菜谱(部分):
46 [牛肉, 胡萝卜, 香葱, 咖喱粉, 盐, 椰浆, 土豆, 洋葱, 姜, 韩国酱油, 泰式鱼露]
70 [牛肉, 木耳, 胡萝卜, 红彩椒, 青椒, 葱花, 姜丝, 蒜末, 花生油, 郫县豆瓣酱,...
148 [牛肉, 青椒, 洋葱, 姜蒜, 花椒, 香叶, 八角, 老抽, 生抽, 孜然粉, 胡椒粉]
272 [牛肉, 毛芋, 八角, 香叶, 桂皮, 花椒, 姜, 辣椒, 冰糖, 葱, 盐, 料酒, 生抽]
290 [牛肉, 胡萝卜, 洋葱, 红酒, 肉汤, 盐, 胡椒粉, 番茄酱, 黄油, 面粉, 月桂叶...
404 [牛肉, 香叶, 八角, 花椒, 姜蒜, 蚝油, 生抽, 盐, 鸡精]
433 [豆芽, 牛肉, 葱, 青椒, 蚝油, 盐]
452 [牛肉, 白砂糖, 花椒, 酱, 盐, 胡萝卜, 酱油, 八角, 蒜, 料酒]
455 [牛肉, 干黄酱, 十三香, 肉桂粉, 八角粉, 花椒粉, 姜粉, 盐, 老汤]
534 [土豆, 牛肉, 盐, 料酒, 生抽, 大蒜, 生姜, 香菜]

含有鱿鱼的菜谱(部分):
187 [鱿鱼, 排骨酱, 糖, 耗油, 洋葱, 辣椒, 甜椒]
284 [鱿鱼, 甜椒]
374 [鱿鱼, 洋葱, 白芝麻, 蒜蓉辣酱, 葱, 姜, 香葱, 烧烤酱]
996 [洋葱, 丝瓜, 鱿鱼, 油, 盐, 酱油, 白糖, 料酒, 耗油]
1468 [鱿鱼, 圆葱, 生菜, 一品鲜酱油, 蒜蓉辣椒酱, 糖, 蚝油, 料酒, 盐, 鸡精]
1502 [鱿鱼, 青红辣椒, 姜蒜, 盐, 白糖, 生抽, 淀粉, 花椒粒]
1577 [鱿鱼, 彩椒, 黄豆酱, 姜]
1619 [虾, 白贝, 鱿鱼, 草菇, 东阴功酱, 鲜柠檬叶, 鱼露, 椰浆, 糖]
1796 [蛏子, 鱿鱼, 韭菜, 白胡椒粉, 料酒, 盐, 姜]
1798 [鱿鱼, 孜然, 盐, 花生油]

Apriori关联规则

另一个可能有意义的尝试是挖掘关联规则,由于数据量不大,这里简单地使用Apriori算法

在挖掘规则之前,首先对数据进行一下预处理:1、把盐去掉,因为盐数目太大,如果不去掉,挖掘出来的规则很多都包含盐的,那无外乎就是告诉我们“做菜记得放盐”,这是没有什么意义的规则;2、去掉只出现一次的材料,这些材料信息量太少,基本不会出现在规则中,如果不去掉,会增加计算量。

这样处理之后,如果要求支持度(规则的出现比例)为0.01,置信度(规则的可信度)为0.8,那么得到以下规则:

规则 支持度 置信度
料酒--葱--蒜--姜 0.019935 0.912060
糖--葱--蒜--姜 0.011203 0.879310
料酒--花椒--葱--姜 0.010544 0.872727
料酒--老抽--葱--姜 0.011643 0.868852
八角--葱--姜 0.016695 0.858757
料酒--糖--葱--姜 0.013345 0.846690
料酒--生抽--蒜--姜 0.013345 0.840830
生抽--葱--蒜--姜 0.012741 0.840580
老抽--蒜--姜 0.013290 0.831615
花椒--葱--姜 0.019221 0.825472
料酒--蒜--姜 0.032511 0.821082
料酒--生抽--葱--姜 0.019057 0.816471
老抽--葱--姜 0.017903 0.808933
料酒--葱--姜 0.050799 0.805749

它们的意思是:出现了料酒、葱、蒜,那么也要把姜放下去;出现了糖、葱、蒜,也要记得放姜;等等。这些规则都以姜结束,告诉我们什么时候需要放姜,在做菜中,这些规则是比较有意义的(当然是对于新手来说)。这个规则也说明,中国菜中,姜是一个很重要的配料

可以稍微放宽一点条件,试图挖掘到更多的规则。将置信度要求降低到0.7,得到

规则 支持度 置信度
葱--蒜--姜 0.038497 0.799316
桂皮--香叶--八角 0.018013 0.782816
冰糖--桂皮--八角 0.010160 0.780591
花椒--蒜--姜 0.014169 0.779456
生抽--香叶--八角 0.010874 0.770428
料酒--桂皮--八角 0.014938 0.764045
桂皮--八角 0.031633 0.761905
桂皮--花椒--八角 0.015267 0.761644
老抽--香叶--八角 0.011423 0.759124
胡椒粉--葱--姜 0.014498 0.758621
桂皮--老抽--八角 0.013070 0.757962
糖--葱--姜 0.022297 0.753247
桂皮--生抽--八角 0.011148 0.751852
料酒--香叶--八角 0.012411 0.750831
花椒--香叶--八角 0.014608 0.745098
葱--醋--姜 0.011203 0.744526
冰糖--生抽--老抽 0.010929 0.742537
香叶--八角 0.028777 0.738028
姜--桂皮--八角 0.011917 0.735593
淀粉--葱--姜 0.011038 0.730909
姜--香叶--八角 0.010215 0.723735
姜--糖--蒜--葱 0.011203 0.720848
糖--蒜--姜 0.015542 0.712846
生抽--葱--姜 0.032402 0.704898
葱--酱油--姜 0.017244 0.700893

如果说关于姜的规则还是过于普通,那么这时候得到的规则应该就更加有意义了,比如说“桂皮--香叶--八角”、“冰糖--桂皮--八角”、“桂皮--生抽--八角”等等,这些组合应该就是卤味相关的配方,这些配方对于一般的厨房爱好者来说不一定清楚,但是通过关联规则,可以将它们挖掘出来

还有一些置信度更高、支持度稍低的规则:

规则 支持度 置信度
料酒--老抽--葱--蒜--姜 0.005602 0.953271
料酒--花椒--葱--蒜--姜 0.005547 0.952830
料酒--糖--葱--蒜--姜 0.007634 0.952055
料酒--桂皮--葱--姜 0.005711 0.936937
料酒--生抽--葱--蒜--姜 0.007743 0.921569
桂皮--花椒--葱--姜 0.005217 0.913462
料酒--白糖--蒜--姜 0.005931 0.805970
料酒--葱--姜 0.050799 0.805749
冰糖--老抽--香叶--八角 0.005162 0.803419

这是更加详细精准的调料配方。要注意,这是计算机自动挖掘出来的结果,大厨是我们的计算机。

最后

本文试图将自己感兴趣的两个爱好——数据挖掘和厨房——结合起来,得到一些看上去比较有趣的结果。事实上是得到了一些看上去有趣的结果,当然,里边也包含了一些笔者对厨房的认识,但是否真的有趣,还需要读者来评价。

这样的挖掘本质上是文本挖掘,或者可以归结为自然语言处理的领域,从本文可以看到,所用的方法基本也是自然语言处理的方法,而了解的读者就会知道,自然语言处理领域的难度在于特征的构建——即怎么用数字来表达一个词语。本文做了一个尝试,但是由于数据量不够等原因,其中的结论不一定准确,这个尝试不算特别成功,但是过程是具有参考性的。也许更多的数据,能够增加研究结果的价值。

从直觉来看,这种挖掘是有意义的,我们可以从一个普通的领域中,挖掘出一些我们不知道的信息,也许这些信息我们都知道,只是未曾留意过。但计算机帮助我们发现了它,从而能够让我们正视它,或者更好地利用它。数据挖掘可以帮助我们更好地生活。的确,数据挖掘技术应该平民化、大众化,因为我们的生活才是我们最重要的数据来源。

最后分享所爬取到的数据:菜谱数据.zip


转载到请包括本文地址:http://kexue.fm/archives/3587/

如果您觉得本文还不错,欢迎点击下面的按钮对博主进行打赏。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!