想学中餐厅嘉宾陈学冬,现在该怎么办?

如何科学地“学习”中餐菜谱中文文件的编码向来是个大坑,这里我把文件转成了比较通用的UTF-8格式编码。可以用codecs模块指定编码格式来读取文件:import codecs
with codecs.open("recipe.txt", encoding="utf8") as f:
raw_data = f.read().strip().split("\n")
我对数据做了一些简单的预处理,现在的数据长这个样子:for line in raw_data[:2]:
print line
【菜名】板栗烧鸡【所属菜系】东北菜【特点】鸡肉酥烂,板栗香甜,时令佳肴,美味可口【原料】活雌鸡或阉鸡1只,约重克,菜油(或化猪油)100克,豆瓣25克,老姜50克,大葱10克,白糖或冰糖25克,花椒、料酒、酱油、精盐、味精、八角等适量。【制作过程】将鸡宰杀、拔毛、剖腹去内脏洗净,把鸡头、翅膀和脚至胫部切下,然后将鸡对剖开,将鸡肉斩成长3厘米、宽2厘米的长方块,把鸡头、翅膀和脚也斩成3厘米的段。锅置旺火上,下100克菜油烧热,然后将鸡块入热油锅中爆炒,待鸡肉变硬时,加入料酒及姜块、豆瓣、花椒,炒至水分渐干溢出香味时,即掺入适量水,放入少量盐、酱油和白糖、八角等。加盖焖烧至六七成熟时,再加入板栗同烧15分钟左右即可。起锅时加入葱段及味精,有少量汤汁为宜。
【菜名】鸳鸯戏飞龙【所属菜系】东北菜【特点】【原料】飞龙肉200克,鸡脯肉50克,口蘑、蛋清、火腿、菜心适量。【制作过程】1.飞龙肉切薄片,用蛋清糊上浆,下开水锅汆透捞出;2.用150克蛋清搅成蛋泡糊,鸡脯肉制成茸,加在蛋泡糊中拌匀,倒在模子中成鸳鸯形,用红、绿辣椒饰嘴、眼及翅膀,上笼蒸熟取出;3.飞龙片、火腿片、鲜蘑、油菜心下鸡清汤中烧开捞入碗中,余汤烧开撇净浮沫,调好味后倒入汤碗,再放入蒸好的鸳鸯即成。
每一行是一个数据,包括菜名、菜系、特点、原料、做法等细节。看一眼有多少个菜谱: print len(raw_data)
先来定义一个函数处理每一条数据,每行数据规律性还挺明显的,这里我用正则表达式提取相关信息: import re
def process_single_data(line):
pattern = r"【菜名】([^【]*)【所属菜系】([^【]*)【特点】([^【]*).*【原料】([^【]*).*【制作过程】([^【]*).*"
match = re.search(pattern, line)
return {"菜名": match.group(1),
"菜系": match.group(2),
"特点": match.group(3),
"原料": match.group(4),
"过程": match.group(5)}
print "处理下列数据出现错误:", line
随便处理一行试试:sample =
process_single_data(raw_data[1105])
for k in sample:
print k, sample[k]
菜名 香露全鸡
过程 1.将鸡治净,从背部剖开,再横切3刀,鸡腹向上放入炖钵,铺上火腿片、香菇,加入调料、鸡汤。2.钵内放入盛有高粱酒、丁香的小杯,加盖封严,蒸2小时后取出钵内小杯即成。
原料 肥嫩母鸡1只,水发香菇2朵,火腿肉2片,高粱酒50克,鸡汤750克,丁香子5粒
对所有的数据进行处理:data = map(process_single_data, raw_data)
在建模之前,我们先看看数据的分布。涉及画图,我们先导入必要的画图工具: import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
而且需要解决不显示中文的问题:plt.title("中文")
plt.show()
显示不出中文是因为它找不到合适的字体去显示。为此,我们可以使用FontProperties指定字体的路径来生成一个字体对象,然后画图的时候指定字体。我个人比较喜欢简单粗暴做法:直接找字体文件,放在当前文件夹用,比如宋体: from matplotlib.font_manager import FontProperties
font_song = FontProperties(fname="SIMSUN.TTC")
plt.title("中文", fontproperties=font_song)
plt.show()
菜系统计先看看有哪些菜系和数目,计数这种任务交给Counter就好了:from collections import Counter
data_tps = [s["菜系"] for s in data]
tps_cts = Counter(data_tps)
for k, v in tps_cts.items():
print k, v
浙江菜 1114
江苏菜 249
满汉全席 44
微波炉菜 85
日本料理 11
法国名菜 53
其他西餐 34
然后画个图:from matplotlib import cm
plt.subplots(figsize=(8, 8))
ax.pie([v for k, v in tps_cts.items()],
labels=[k for k, v in tps_cts.items()],
colors=cm.Vega20.colors)
ax.axis("equal")
for t in ax.texts:
t.set_font_properties(font_song)
plt.show()
这里,类别为全部大概是家常菜的意思吧(我猜的)。食材统计
食材统计是个比较麻烦的事情,先随便看看食材的数据长什么样子:for i in range(0, ):
print data[i]["原料"]
活雌鸡或阉鸡1只,约重克,菜油(或化猪油)100克,豆瓣25克,老姜50克,大葱10克,白糖或冰糖25克,花椒、料酒、酱油、精盐、味精、八角等适量。
燕窝(40克)、椰子(1个,750克)、味粉(15克)、鸡汤(250克)、精盐(少许)、小苏打粉(少许)
活鳝鱼350克。虾仁50克、熟火腿20克、猪腰片50克、水发冬菇20克,水发虾米10克、熟笋片30克…虾子5克。猪肉汤750克、绍酒15克、葱15克、姜7.5克、盐5克、味精3克、白胡椒粉1.5克。
光鸭(1只,1500克左右)、葱段(20克)、姜片(20克)、桂皮(20克)、茴香(13克)、红米(8克)、黄酒、冰糖(130克)、白酱、盐、麻油
节瓜600克(约1斤),草菇50克(约1两半),虾仁100克(约2两半),蟹肉75克(约2两),蛋白1只,上汤400毫升,姜1片,葱1条。盐1茶匙,糖1/4茶匙,粟粉、酒各1茶匙,水1汤匙,胡椒粉少许。
嫩母鸡(约1.25公斤左右)1只,胡萝卜100克,芹菜50克,葱头10O克,精盐10克,香叶半片,胡椒6粒,鸡清汤250毫升,生菜油500(罕耗100克),奶油15克,鸡油15克,红白菜200克,酸黄瓜100克,鲜西红柿100克,纸花2个,萝卜花2个,生菜叶10克。
水发鱿鱼(325克)、京葱花(40克)、大蒜头片(10片)、黄酒(12.5克)、醋(少许)、盐(6克)、味精(少许)、酱瓜米(少许)、菱粉(45克)、清汤(150克)。
鲜鱿鱼肉12两(约480克),西芹一条。西芹调味料:盐1/8茶匙,麻油少许。鱿鱼调味料:盐1/4茶匙,胡椒粉少许。椒麻汁料:花椒粒1茶匙,姜茸2茶匙,青葱茸2汤匙,糖2/3茶匙,醋,麻油各1茶匙,生抽,开水各2汤匙。
原料:面条500克,菠菜或小白菜300克,青椒(甜)3个,榨菜25克。葱10克,蒜1头,酱油10克,香醋5克,精盐3克,味精2克,香油15克,高汤适量。
主料扁豆150克,鸡油50克。调料料酒25克,味精5克,湿淀粉15克,鸡汤150克。
为了搞到食材,我们可以想办法去掉里面的一些关键词,比如多少克,少许,越重以及标点符号:def process_single_ingredient(line):
# 标点符号替换为空格
line = re.sub("[。,、/…~~:;:%]", " ", line) + " "
line = re.sub("([^(]*)", " ", line)
# 阿拉伯数字替换为空格
line = re.sub("\d+\S* ", " ", line)
# 汉语数字替换为空格
line = re.sub("[一二两三四五六七八九十几半]+\S* ", " ", line)
# 关键词替换为空格
for s in ["少许", "适量", "或", "等", "重", "约",
"各", "原料", "调味料", "主料", "辅料", "调料", "用料", "和", "及"]:
line = re.sub(s, " ", line)
# 字母替换为空格
line = re.sub(" \w+ ", " ", line)
line = re.sub(" +", " ", line).strip()
return line
for i in range(0, ):
print process_single_ingredient(data[i]["原料"])
活雌鸡 阉鸡 菜油 豆瓣 老姜 大葱 白糖 冰糖 花椒 料酒 酱油 精盐 味精
燕窝 椰子 味粉 鸡汤 精盐 小苏打粉
活鳝鱼 虾仁 熟火腿 猪腰片 水发冬菇 水发虾米 熟笋片 虾子 猪肉汤 绍酒 葱 姜 盐 味精 白胡椒粉
光鸭 葱段 姜片 桂皮 茴香 红米 黄酒 冰糖 白酱 盐 麻油
节瓜 草菇 虾仁 蟹肉 蛋白 上汤 姜 葱 盐 糖 粟粉 酒 水 胡椒粉
嫩母鸡 胡萝卜 芹菜 葱头 精盐 香叶 胡椒 鸡清汤 生菜油 奶油 鸡油 红白菜 酸黄瓜 鲜西红柿 纸花 萝卜花 生菜叶
水发鱿鱼 京葱花 大蒜头片 黄酒 醋 盐 味精 酱瓜米 菱粉 清汤
鲜鱿鱼肉 西芹 西芹 盐 麻油 鱿鱼 盐 胡椒粉 椒麻汁料 花椒粒 姜茸 青葱茸 糖 醋 麻油 生抽 开水
面条 菠菜 小白菜 青椒 榨菜 葱 蒜 酱油 香醋 精盐 味精 香油 高汤
扁豆 鸡油 料酒 味精 湿淀粉 鸡汤
这样结果就看起来不错的样子了,我们来做一下统计:data_ings = map(lambda x: process_single_ingredient(x["原料"]), data)
data_ings_all = " ".join(data_ings).split()
ings_cts = Counter(data_ings_all)
不出意外的话,排在前面的原料应该是各种调味品:for k, v in ings_cts.items():
if v & 200:
print k, v
鸡蛋清 299
水淀粉 254
胡椒粉 801
湿淀粉 619
芝麻油 434
植物油 274
熟猪油 325
花生油 410
食材预测有了食材,我们可以按照那篇英文文章的想法,用一个食材预测的任务来得到食物的Embedding向量。具体做法为:用菜谱中的每个食材,来预测菜谱中的其它食材。我们现在的食材有:print len(ings_cts)
我们现在去除那些只出现了次数比较少的食材:for k in
ings_cts.keys():
if ings_cts[k] &= 5:
ings_cts.pop(k)
剩下的有: print len(ings_cts)
然后将它们从1开始ID化: word_idx = {k: idx+1 for idx, k in enumerate(ings_cts)}
idx_word = {idx+1: k for idx, k in enumerate(ings_cts)}
接下来将数据ID化: data_ings_idx = map(lambda x: [word_idx.get(t, 0) for t in x.split()],
data_ings)
模型构造有了数据集,模型也就不难构造了:这里,我们使用keras来构造我们的Embedding模型:import keras
Using TensorFlow backend.
因为使用的是tensorflow的后端,而且是GPU版本的,我需要设置一下GPU选项,免得我的小程序什么都没做就吃掉所有的GPU显存(坑爹的tensorflow能不能不要认为这些卡都是我一个人在用!):import keras.backend as K
if K.backend() == "tensorflow":
config = K.tf.ConfigProto()
config.gpu_options.allow_growth = True
session = K.tf.Session(config=config)
K.set_session(session)
模型其实很简单,我们先构造一个N×D的Embedding矩阵,其中N是我的食材数目,D是我需要的食材向量的维度,那么N种食材就对应与这N个D维向量了,在Embedding的结果上加一个sigmoid输出的全连接层预测其它食材。输入维度为1,代表食材的种类,输出长度为N,代表这个食材与其它食材相关的概率。现在来构造这个模型:from keras.models import Sequential
from keras.layers import Embedding, Dense, Flatten
from keras.regularizers import l2
n_words = len(word_idx) + 1
model = Sequential()
model.add(Embedding(n_words, 50, input_length=1,
activity_regularizer=l2(0.01)))
model.add(Flatten())
model.add(Dense(n_words, activation="sigmoid",
activity_regularizer=l2(0.01)))
pile(optimizer="adam", loss="binary_crossentropy", metrics=["acc"])
构造训练集: data_x = []
data_y = []
for ings_idxs in data_ings_idx:
if len(ings_idxs) == 1:
for idx in set(ings_idxs):
y = np.zeros(n_words)
data_x.append(idx)
y[list(set(ings_idxs) - set([idx]))] = 1
data_y.append(y)
np.array(data_x)
np.array(data_y)
来随机化一下数据:rd_idx = np.arange(len(data_x))
np.random.shuffle(rd_idx)
训练模型:hist = model.fit(data_x[rd_idx], data_y[rd_idx],
validation_split=0.1, verbose=0, epochs=5)
训练完成,我们拿到这些Embedding的向量:emb = model.get_weights()[0]
算个距离度量,并看看一些跟食材最接近的都是什么:from scipy.spatial import distance
dist = distance.squareform(distance.pdist(emb, "cosine"))
print idx_word[np.argsort(dist[word_idx["盐"]])[1]]
print idx_word[np.argsort(dist[word_idx["鸡汤"]])[1]]
print idx_word[np.argsort(dist[word_idx["西红柿"]])[1]]
看起来还是蛮有意思的,然而并看不出什么靠谱的结论。菜系预测我们也可以用我们的数据来进行菜系预测,比如想象成一个序列预测问题,用一个输入序列来预测最终的菜系,序列处理可以使用一个RNN,比如LSTM,GRU等。这里我们先处理一下序列,如果使用“做法”序列当输入,好像这些序列有点太长了,因为最长的序列大概有1000个字,我们退而取其次,用“原料”序列当作输入。为此,我们可以先去掉原料中没什么用的部分,比如标点符号数字字母等:def process_rnn(line):
# 标点符号
line = re.sub("[。,、/…~~:;:%()]", "", line)
# 阿拉伯数字替换为空格
line = re.sub("[\d\w]", "", line)
return line
data_rnn =
[process_rnn(i["原料"]) for i in data]
做一下相关统计,去掉所有只出现过一次的字:word_cts = Counter("".join(data_rnn))
for k, v in
word_cts.items():
if v == 1:
word_cts.pop(k)
print len(word_cts)
将这些字和菜系都ID化,方便我们构造数据集:word_idx = {k: idx+1 for idx, k in enumerate(word_cts)}
idx_word = {idx+1: k for idx, k in enumerate(word_cts)}
tps_idx = {k: idx for idx, k in enumerate(tps_cts)}
idx_tps = {idx: k for idx, k in enumerate(tps_cts)}
将数据ID化:data_rnn_idx = map(lambda x: [word_idx.get(t, 0) for t in x], data_rnn)
data_tps_idx = np.array(map(lambda x: tps_idx[x], data_tps))
将RNN相关的模块导入:from keras.layers import LSTM, GRU
from keras.preprocessing.sequence import pad_sequences
原料序列一般是不等长的,我们用pad_sequences让它们等长,方便训练:data_rnn_idx = np.array(pad_sequences(data_rnn_idx))
接下来就是构造模型:n_seq = len(data_rnn_idx[0])
n_words = len(word_idx) + 1
n_tps = len(tps_idx)
rnn_model =
Sequential()
rnn_model.add(Embedding(n_words,
input_length=n_seq))
rnn_model.add(GRU(64))
rnn_model.add(Dense(128, activation="relu", name="feat"))
rnn_model.add(Dense(n_tps,
activation="softmax"))
pile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["acc"])
这里用的是GRU的RNN模型,并拿到序列的最后一个输出,在之后加上一层全连接和一层Softmax分类。训练这个模型:hist = rnn_model.fit(data_rnn_idx, data_tps_idx, epochs=50, verbose=0)
准确率为:print hist.history["acc"][-1]
我们现在把最后一层的特征拿出来:from keras.models import Model
feat_model = Model(inputs=rnn_model.input,
outputs=rnn_model.get_layer("feat").output)
data_feat = feat_model.predict(data_rnn_idx)
做一个TSNE降到2维:from sklearn.manifold import TSNE
data_feat_vis = TSNE(n_components=2, init='pca').fit_transform(data_feat)
可视化一下:_, ax =
plt.subplots(figsize=(15, 12))
for tp, idx in tps_idx.items():
ax.scatter(data_feat_vis[data_tps_idx==idx,0],
data_feat_vis[data_tps_idx==idx,1],
c=cm.Vega20.colors[idx], label=tp)
ax.set_xlim(-20, 40)
ax.set_ylim(-20, 20)
ax.set_xticks([])
ax.set_yticks([])
ax.legend(loc=0)
ltext = ax.get_legend().get_texts()
for t in ltext:
t.set_font_properties(font_song)
t.set_fontsize("xx-large")
plt.show()
一本正经地分析一下这张图:韩国菜明显风格跟天朝有差异浙江菜的隔壁是沪菜和江苏菜,江苏菜的隔壁是鲁菜微波炉菜(不知道什么鬼)混入了全部菜系之中闽菜和粤菜相邻粤菜的点分布的还挺开的(大概广东人什么都吃?)湘菜跟川菜也挺近的剩下的请恕我老眼昏花看不清楚,从地理上看,还是有点意思的。当然了,说到底这个任务都是我硬生生造出来的,并没什么用,而且,我也根本不懂怎么做菜,权当我是胡说八道好了,毕竟:人生呐,就该一本正经地胡说八道。原文发表于微信公众号:lijin_echo微信文章链接:14收藏分享举报{&debug&:false,&apiRoot&:&&,&paySDK&:&https:\u002F\\u002Fapi\u002Fjs&,&wechatConfigAPI&:&\u002Fapi\u002Fwechat\u002Fjssdkconfig&,&name&:&production&,&instance&:&column&,&tokens&:{&X-XSRF-TOKEN&:null,&X-UDID&:null,&Authorization&:&oauth c3cef7c66aa9e6a1e3160e20&}}{&database&:{&Post&:{&&:{&isPending&:false,&contributes&:[],&title&:&如何科学地“学习”中餐菜谱&,&author&:&li-jin-33-15&,&content&:&\u003Cp\u003E大概过年的时候围观了一篇这样的文章: \u003Ca href=\&http:\u002F\\u002F?target=https%3A\u002F\u002Fjaan.io\u002Ffood2vec-augmented-cooking-machine-intelligence\u002F\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003Efood2vec - Augmented cooking with\nmachine intelligence\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E,讲了一个把食物向量化的一个应用,还挺好玩的。\u003C\u002Fp\u003E\u003Cp\u003E大天朝物产丰富,在吃的方面绝对要比世界人民领先好几个档次,当然也是可以搞一搞这个的。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E数据预处理\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E我先找到一个叫《菜谱大全》的文本文件,处理了一下,命名为“recipe.txt”。\u003C\u002Fp\u003E\u003Cp\u003E涉及中文字符处理,先把所有的字符串转成Unicode:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kn\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&nn\&\u003E__future__\u003C\u002Fspan\u003E \u003Cspan class=\&kn\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eunicode_literals\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E中文文件的编码向来是个大坑,这里我把文件转成了比较通用的UTF-8格式编码。可以用codecs模块指定编码格式来读取文件:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eimport codecs\n\nwith codecs.open(\&recipe.txt\&, encoding=\&utf8\&) as f:\n
raw_data = f.read().strip().split(\&\\n\&)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E我对数据做了一些简单的预处理,现在的数据长这个样子:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efor line in raw_data[:2]:\n
print line\n【菜名】板栗烧鸡【所属菜系】东北菜【特点】鸡肉酥烂,板栗香甜,时令佳肴,美味可口【原料】活雌鸡或阉鸡1只,约重克,菜油(或化猪油)100克,豆瓣25克,老姜50克,大葱10克,白糖或冰糖25克,花椒、料酒、酱油、精盐、味精、八角等适量。【制作过程】将鸡宰杀、拔毛、剖腹去内脏洗净,把鸡头、翅膀和脚至胫部切下,然后将鸡对剖开,将鸡肉斩成长3厘米、宽2厘米的长方块,把鸡头、翅膀和脚也斩成3厘米的段。锅置旺火上,下100克菜油烧热,然后将鸡块入热油锅中爆炒,待鸡肉变硬时,加入料酒及姜块、豆瓣、花椒,炒至水分渐干溢出香味时,即掺入适量水,放入少量盐、酱油和白糖、八角等。加盖焖烧至六七成熟时,再加入板栗同烧15分钟左右即可。起锅时加入葱段及味精,有少量汤汁为宜。\n【菜名】鸳鸯戏飞龙【所属菜系】东北菜【特点】【原料】飞龙肉200克,鸡脯肉50克,口蘑、蛋清、火腿、菜心适量。【制作过程】1.飞龙肉切薄片,用蛋清糊上浆,下开水锅汆透捞出;2.用150克蛋清搅成蛋泡糊,鸡脯肉制成茸,加在蛋泡糊中拌匀,倒在模子中成鸳鸯形,用红、绿辣椒饰嘴、眼及翅膀,上笼蒸熟取出;3.飞龙片、火腿片、鲜蘑、油菜心下鸡清汤中烧开捞入碗中,余汤烧开撇净浮沫,调好味后倒入汤碗,再放入蒸好的鸳鸯即成。\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E每一行是一个数据,包括菜名、菜系、特点、原料、做法等细节。\u003C\u002Fp\u003E\u003Cp\u003E看一眼有多少个菜谱: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eprint len(raw_data)\n4577\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E先来定义一个函数处理每一条数据,每行数据规律性还挺明显的,这里我用正则表达式提取相关信息: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eimport re\n\ndef process_single_data(line):\n
pattern = r\&【菜名】([^【]*)【所属菜系】([^【]*)【特点】([^【]*).*【原料】([^【]*).*【制作过程】([^【]*).*\&\n
match = re.search(pattern, line)\n
if match:\n
return {\&菜名\&: match.group(1), \n
\&菜系\&: match.group(2), \n
\&特点\&: match.group(3), \n
\&原料\&: match.group(4),\n
\&过程\&: match.group(5)}\n
print \&处理下列数据出现错误:\&, line\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E
随便处理一行试试:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Esample =\nprocess_single_data(raw_data[1105])\nfor k in sample:\n
print k, sample[k]\n特点 \n菜名 香露全鸡\n过程 1.将鸡治净,从背部剖开,再横切3刀,鸡腹向上放入炖钵,铺上火腿片、香菇,加入调料、鸡汤。2.钵内放入盛有高粱酒、丁香的小杯,加盖封严,蒸2小时后取出钵内小杯即成。\n菜系 闽菜\n原料 肥嫩母鸡1只,水发香菇2朵,火腿肉2片,高粱酒50克,鸡汤750克,丁香子5粒\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E对所有的数据进行处理:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata = map(process_single_data, raw_data)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E在建模之前,我们先看看数据的分布。\u003C\u002Fp\u003E\u003Cp\u003E涉及画图,我们先导入必要的画图工具: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eimport numpy as np\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E而且需要解决不显示中文的问题:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eplt.title(\&中文\&)\nplt.show()\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-8b5ece1db95bdcc90eb3119_b.png\& data-rawwidth=\&335\& data-rawheight=\&233\& class=\&content_image\& width=\&335\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='335'%20height='233'&&\u002Fsvg&\& data-rawwidth=\&335\& data-rawheight=\&233\& class=\&content_image lazy\& width=\&335\& data-actualsrc=\&https:\u002F\\u002Fv2-8b5ece1db95bdcc90eb3119_b.png\&\u003E\u003Cbr\u003E\u003Cp\u003E显示不出中文是因为它找不到合适的字体去显示。\u003C\u002Fp\u003E\u003Cp\u003E为此,我们可以使用FontProperties指定字体的路径来生成一个字体对象,然后画图的时候指定字体。\u003C\u002Fp\u003E\u003Cp\u003E我个人比较喜欢简单粗暴做法:直接找字体文件,放在当前文件夹用,比如宋体: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom matplotlib.font_manager import FontProperties\n\nfont_song = FontProperties(fname=\&SIMSUN.TTC\&)\nplt.title(\&中文\&, fontproperties=font_song)\nplt.show()\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-aa7b1dfc0404_b.png\& data-rawwidth=\&352\& data-rawheight=\&244\& class=\&content_image\& width=\&352\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='352'%20height='244'&&\u002Fsvg&\& data-rawwidth=\&352\& data-rawheight=\&244\& class=\&content_image lazy\& width=\&352\& data-actualsrc=\&https:\u002F\\u002Fv2-aa7b1dfc0404_b.png\&\u003E\u003Cbr\u003E\u003Cp\u003E\u003Cb\u003E菜系统计\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E先看看有哪些菜系和数目,计数这种任务交给Counter就好了:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom collections import Counter\n\ndata_tps = [s[\&菜系\&] for s in data]\ntps_cts = Counter(data_tps)\n\nfor k, v in tps_cts.items():\n
print k, v\n沪菜 87\n浙江菜 1114\n韩国 310\n湘菜 75\n江苏菜 249\n满汉全席 44\n微波炉菜 85\n日本料理 11\n海派菜 19\n鲁菜 285\n川菜 352\n全部 1323\n云南菜 18\n淮阳菜 34\n东北菜 52\n闽菜 114\n法国名菜 53\n京菜 123\n粤菜 195\n其他西餐 34\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E然后画个图:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom matplotlib import cm\n\n_, ax =\nplt.subplots(figsize=(8, 8))\nax.pie([v for k, v in tps_cts.items()], \n
labels=[k for k, v in tps_cts.items()], \n
colors=cm.Vega20.colors)\nax.axis(\&equal\&)\nfor t in ax.texts:\n
t.set_font_properties(font_song)\nplt.show()\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-40fa261e9b6c872bbc9a2ed_b.png\& data-rawwidth=\&407\& data-rawheight=\&360\& class=\&content_image\& width=\&407\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='407'%20height='360'&&\u002Fsvg&\& data-rawwidth=\&407\& data-rawheight=\&360\& class=\&content_image lazy\& width=\&407\& data-actualsrc=\&https:\u002F\\u002Fv2-40fa261e9b6c872bbc9a2ed_b.png\&\u003E\u003Cbr\u003E\u003Cp\u003E这里,类别为全部大概是家常菜的意思吧(我猜的)。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E食材统计\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E
食材统计是个比较麻烦的事情,先随便看看食材的数据长什么样子:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efor i in range(0, ):\n
print data[i][\&原料\&]\n活雌鸡或阉鸡1只,约重克,菜油(或化猪油)100克,豆瓣25克,老姜50克,大葱10克,白糖或冰糖25克,花椒、料酒、酱油、精盐、味精、八角等适量。\n燕窝(40克)、椰子(1个,750克)、味粉(15克)、鸡汤(250克)、精盐(少许)、小苏打粉(少许)\n活鳝鱼350克。虾仁50克、熟火腿20克、猪腰片50克、水发冬菇20克,水发虾米10克、熟笋片30克…虾子5克。猪肉汤750克、绍酒15克、葱15克、姜7.5克、盐5克、味精3克、白胡椒粉1.5克。\n光鸭(1只,1500克左右)、葱段(20克)、姜片(20克)、桂皮(20克)、茴香(13克)、红米(8克)、黄酒、冰糖(130克)、白酱、盐、麻油\n节瓜600克(约1斤),草菇50克(约1两半),虾仁100克(约2两半),蟹肉75克(约2两),蛋白1只,上汤400毫升,姜1片,葱1条。盐1茶匙,糖1\u002F4茶匙,粟粉、酒各1茶匙,水1汤匙,胡椒粉少许。\n嫩母鸡(约1.25公斤左右)1只,胡萝卜100克,芹菜50克,葱头10O克,精盐10克,香叶半片,胡椒6粒,鸡清汤250毫升,生菜油500(罕耗100克),奶油15克,鸡油15克,红白菜200克,酸黄瓜100克,鲜西红柿100克,纸花2个,萝卜花2个,生菜叶10克。\n水发鱿鱼(325克)、京葱花(40克)、大蒜头片(10片)、黄酒(12.5克)、醋(少许)、盐(6克)、味精(少许)、酱瓜米(少许)、菱粉(45克)、清汤(150克)。\n鲜鱿鱼肉12两(约480克),西芹一条。西芹调味料:盐1\u002F8茶匙,麻油少许。鱿鱼调味料:盐1\u002F4茶匙,胡椒粉少许。椒麻汁料:花椒粒1茶匙,姜茸2茶匙,青葱茸2汤匙,糖2\u002F3茶匙,醋,麻油各1茶匙,生抽,开水各2汤匙。\n原料:面条500克,菠菜或小白菜300克,青椒(甜)3个,榨菜25克。葱10克,蒜1头,酱油10克,香醋5克,精盐3克,味精2克,香油15克,高汤适量。\n主料扁豆150克,鸡油50克。调料料酒25克,味精5克,湿淀粉15克,鸡汤150克。\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E为了搞到食材,我们可以想办法去掉里面的一些关键词,比如多少克,少许,越重以及标点符号:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edef process_single_ingredient(line):\n
# 标点符号替换为空格\n
line = re.sub(\&[。,、\u002F…~~:;:%]\&, \& \&, line) + \& \&\n
line = re.sub(\&([^(]*)\&, \& \&, line)\n
# 阿拉伯数字替换为空格\n
line = re.sub(\&\\d+\\S* \&, \& \&, line)\n
# 汉语数字替换为空格\n
line = re.sub(\&[一二两三四五六七八九十几半]+\\S* \&, \& \&, line)\n
# 关键词替换为空格\n
for s in [\&少许\&, \&适量\&, \&或\&, \&等\&, \&重\&, \&约\&, \n
\&各\&, \&原料\&, \&调味料\&, \&主料\&, \&辅料\&, \&调料\&, \&用料\&, \&和\&, \&及\&]:\n
line = re.sub(s, \& \&, line)\n
# 字母替换为空格\n
line = re.sub(\& \\w+ \&, \& \&, line)\n
line = re.sub(\& +\&, \& \&, line).strip()\n
return line\n\nfor i in range(0, ):\n
print process_single_ingredient(data[i][\&原料\&])\n活雌鸡 阉鸡 菜油 豆瓣 老姜 大葱 白糖 冰糖 花椒 料酒 酱油 精盐 味精\n燕窝 椰子 味粉 鸡汤 精盐 小苏打粉\n活鳝鱼 虾仁 熟火腿 猪腰片 水发冬菇 水发虾米 熟笋片 虾子 猪肉汤 绍酒 葱 姜 盐 味精 白胡椒粉\n光鸭 葱段 姜片 桂皮 茴香 红米 黄酒 冰糖 白酱 盐 麻油\n节瓜 草菇 虾仁 蟹肉 蛋白 上汤 姜 葱 盐 糖 粟粉 酒 水 胡椒粉\n嫩母鸡 胡萝卜 芹菜 葱头 精盐 香叶 胡椒 鸡清汤 生菜油 奶油 鸡油 红白菜 酸黄瓜 鲜西红柿 纸花 萝卜花 生菜叶\n水发鱿鱼 京葱花 大蒜头片 黄酒 醋 盐 味精 酱瓜米 菱粉 清汤\n鲜鱿鱼肉 西芹 西芹 盐 麻油 鱿鱼 盐 胡椒粉 椒麻汁料 花椒粒 姜茸 青葱茸 糖 醋 麻油 生抽 开水\n面条 菠菜 小白菜 青椒 榨菜 葱 蒜 酱油 香醋 精盐 味精 香油 高汤\n扁豆 鸡油 料酒 味精 湿淀粉 鸡汤\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E这样结果就看起来不错的样子了,我们来做一下统计:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata_ings = map(lambda x: process_single_ingredient(x[\&原料\&]), data)\ndata_ings_all = \& \&.join(data_ings).split()\nings_cts = Counter(data_ings_all)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E不出意外的话,排在前面的原料应该是各种调味品:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efor k, v in ings_cts.items():\n
if v & 200:\n
print k, v\n酱油 1288\n花椒 252\n鸡蛋清 299\n鸡汤 399\n料酒 1048\n姜末 284\n水淀粉 254\n味精 2049\n姜 799\n麻油 351\n香油 460\n醋 434\n绍酒 808\n精盐 1520\n胡椒粉 801\n湿淀粉 619\n白糖 1140\n芝麻油 434\n葱 948\n盐 1452\n植物油 274\n油 277\n鸡蛋 506\n熟猪油 325\n淀粉 387\n葱段 237\n清汤 280\n猪油 225\n黄酒 243\n花生油 410\n糖 401\n面粉 261\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cb\u003E食材预测\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E有了食材,我们可以按照那篇英文文章的想法,用一个食材预测的任务来得到食物的Embedding向量。具体做法为:用菜谱中的每个食材,来预测菜谱中的其它食材。\u003C\u002Fp\u003E\u003Cp\u003E我们现在的食材有:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eprint len(ings_cts)\n5598\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E我们现在去除那些只出现了次数比较少的食材:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efor k in\nings_cts.keys():\n
if ings_cts[k] &= 5:\n
ings_cts.pop(k)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E剩下的有: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eprint len(ings_cts)\n737\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E然后将它们从1开始ID化: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eword_idx = {k: idx+1 for idx, k in enumerate(ings_cts)}\nidx_word = {idx+1: k for idx, k in enumerate(ings_cts)}\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E接下来将数据ID化: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata_ings_idx = map(lambda x: [word_idx.get(t, 0) for t in x.split()], \n
data_ings)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E\u003Cb\u003E模型构造\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E有了数据集,模型也就不难构造了:\u003C\u002Fp\u003E\u003Cp\u003E这里,我们使用keras来构造我们的Embedding模型:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eimport keras\nUsing TensorFlow backend.\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E因为使用的是tensorflow的后端,而且是GPU版本的,我需要设置一下GPU选项,免得我的小程序什么都没做就吃掉所有的GPU显存(坑爹的tensorflow能不能不要认为这些卡都是我一个人在用!):\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eimport keras.backend as K\n\nif K.backend() == \&tensorflow\&:\n
config = K.tf.ConfigProto()\n
config.gpu_options.allow_growth = True\n
session = K.tf.Session(config=config)\n
K.set_session(session)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E模型其实很简单,我们先构造一个N×D的Embedding矩阵,其中N是我的食材数目,D是我需要的食材向量的维度,那么N种食材就对应与这N个D维向量了,在Embedding的结果上加一个sigmoid输出的全连接层预测其它食材。输入维度为1,代表食材的种类,输出长度为N,代表这个食材与其它食材相关的概率。\u003C\u002Fp\u003E\u003Cp\u003E现在来构造这个模型:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom keras.models import Sequential\nfrom keras.layers import Embedding, Dense, Flatten\nfrom keras.regularizers import l2\n \nn_words = len(word_idx) + 1\nmodel = Sequential()\nmodel.add(Embedding(n_words, 50, input_length=1,
activity_regularizer=l2(0.01)))\nmodel.add(Flatten())\nmodel.add(Dense(n_words, activation=\&sigmoid\&, \n
activity_regularizer=l2(0.01)))\pile(optimizer=\&adam\&, loss=\&binary_crossentropy\&, metrics=[\&acc\&])\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E构造训练集: \u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata_x = []\ndata_y = []\n\nfor ings_idxs in data_ings_idx:\n
if len(ings_idxs) == 1:\n
continue\n
for idx in set(ings_idxs):\n
y = np.zeros(n_words)\n
data_x.append(idx)\n
y[list(set(ings_idxs) - set([idx]))] = 1\n
data_y.append(y)\n
\ndata_x =\nnp.array(data_x)\ndata_y =\nnp.array(data_y)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E来随机化一下数据:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Erd_idx = np.arange(len(data_x))\nnp.random.shuffle(rd_idx)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E训练模型:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Ehist = model.fit(data_x[rd_idx], data_y[rd_idx], \n
validation_split=0.1, verbose=0, epochs=5)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E训练完成,我们拿到这些Embedding的向量:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eemb = model.get_weights()[0]\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cbr\u003E\u003Cp\u003E算个距离度量,并看看一些跟食材最接近的都是什么:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom scipy.spatial import distance\n\ndist = distance.squareform(distance.pdist(emb, \&cosine\&))\nprint idx_word[np.argsort(dist[word_idx[\&盐\&]])[1]]\nprint idx_word[np.argsort(dist[word_idx[\&鸡汤\&]])[1]]\nprint idx_word[np.argsort(dist[word_idx[\&西红柿\&]])[1]]\n酱油\n鸡蛋\n高汤\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E看起来还是蛮有意思的,然而并看不出什么靠谱的结论。\u003C\u002Fp\u003E\u003Cp\u003E\u003Cb\u003E菜系预测\u003C\u002Fb\u003E\u003C\u002Fp\u003E\u003Cp\u003E我们也可以用我们的数据来进行菜系预测,比如想象成一个序列预测问题,用一个输入序列来预测最终的菜系,序列处理可以使用一个RNN,比如LSTM,GRU等。\u003C\u002Fp\u003E\u003Cp\u003E这里我们先处理一下序列,如果使用“做法”序列当输入,好像这些序列有点太长了,因为最长的序列大概有1000个字,我们退而取其次,用“原料”序列当作输入。\u003C\u002Fp\u003E\u003Cp\u003E为此,我们可以先去掉原料中没什么用的部分,比如标点符号数字字母等:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edef process_rnn(line):\n
# 标点符号\n
line = re.sub(\&[。,、\u002F…~~:;:%()]\&, \&\&, line)\n
# 阿拉伯数字替换为空格\n
line = re.sub(\&[\\d\\w]\&, \&\&, line)\n
return line\n\ndata_rnn =\n[process_rnn(i[\&原料\&]) for i in data]\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E做一下相关统计,去掉所有只出现过一次的字:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eword_cts = Counter(\&\&.join(data_rnn))\nfor k, v in\nword_cts.items():\n
if v == 1:\n
word_cts.pop(k)\n
\nprint len(word_cts)\n1105\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E将这些字和菜系都ID化,方便我们构造数据集:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eword_idx = {k: idx+1 for idx, k in enumerate(word_cts)}\nidx_word = {idx+1: k for idx, k in enumerate(word_cts)}\n\ntps_idx = {k: idx for idx, k in enumerate(tps_cts)}\nidx_tps = {idx: k for idx, k in enumerate(tps_cts)}\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E将数据ID化:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata_rnn_idx = map(lambda x: [word_idx.get(t, 0) for t in x], data_rnn)\ndata_tps_idx = np.array(map(lambda x: tps_idx[x], data_tps))\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E将RNN相关的模块导入:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom keras.layers import LSTM, GRU\nfrom keras.preprocessing.sequence import pad_sequences\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E原料序列一般是不等长的,我们用pad_sequences让它们等长,方便训练:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Edata_rnn_idx = np.array(pad_sequences(data_rnn_idx))\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E接下来就是构造模型:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003En_seq = len(data_rnn_idx[0])\nn_words = len(word_idx) + 1\nn_tps = len(tps_idx)\n \nrnn_model =\nSequential()\nrnn_model.add(Embedding(n_words,\n64,\ninput_length=n_seq))\nrnn_model.add(GRU(64))\nrnn_model.add(Dense(128, activation=\&relu\&, name=\&feat\&))\nrnn_model.add(Dense(n_tps,\nactivation=\&softmax\&))\n\pile(optimizer=\&adam\&, \n
loss=\&sparse_categorical_crossentropy\&, \n
metrics=[\&acc\&])\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E这里用的是GRU的RNN模型,并拿到序列的最后一个输出,在之后加上一层全连接和一层Softmax分类。\u003C\u002Fp\u003E\u003Cp\u003E训练这个模型:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Ehist = rnn_model.fit(data_rnn_idx, data_tps_idx, epochs=50, verbose=0)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E准确率为:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Eprint hist.history[\&acc\&][-1]\n0.47605\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E我们现在把最后一层的特征拿出来:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-text\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003Efrom keras.models import Model\n \nfeat_model = Model(inputs=rnn_model.input,\noutputs=rnn_model.get_layer(\&feat\&).output)\ndata_feat = feat_model.predict(data_rnn_idx)\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E做一个TSNE降到2维:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&kn\&\u003Efrom\u003C\u002Fspan\u003E \u003Cspan class=\&nn\&\u003Esklearn.manifold\u003C\u002Fspan\u003E \u003Cspan class=\&kn\&\u003Eimport\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ETSNE\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Edata_feat_vis\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003ETSNE\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003En_components\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E2\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Einit\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&s1\&\u003E'pca'\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Efit_transform\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Edata_feat\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cp\u003E可视化一下:\u003C\u002Fp\u003E\u003Cdiv class=\&highlight\&\u003E\u003Cpre\u003E\u003Ccode class=\&language-python\&\u003E\u003Cspan\u003E\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003E_\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eplt\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Esubplots\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Efigsize\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E15\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E12\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E))\u003C\u002Fspan\u003E\n\u003Cspan class=\&k\&\u003Efor\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etp\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eidx\u003C\u002Fspan\u003E \u003Cspan class=\&ow\&\u003Ein\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Etps_idx\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eitems\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E():\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Escatter\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Edata_feat_vis\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Edata_tps_idx\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eidx\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Edata_feat_vis\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Edata_tps_idx\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E==\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eidx\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E1\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E \n
\u003Cspan class=\&n\&\u003Ec\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ecm\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003EVega20\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Ecolors\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E[\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eidx\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E],\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Elabel\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Etp\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_xlim\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E-\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E20\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E40\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_ylim\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E-\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E20\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E,\u003C\u002Fspan\u003E \u003Cspan class=\&mi\&\u003E20\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_xticks\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E([])\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_yticks\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E([])\u003C\u002Fspan\u003E\n\n\u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Elegend\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eloc\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E\u003Cspan class=\&mi\&\u003E0\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eltext\u003C\u002Fspan\u003E \u003Cspan class=\&o\&\u003E=\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eax\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eget_legend\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eget_texts\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\n\u003Cspan class=\&k\&\u003Efor\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Et\u003C\u002Fspan\u003E \u003Cspan class=\&ow\&\u003Ein\u003C\u002Fspan\u003E \u003Cspan class=\&n\&\u003Eltext\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E:\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Et\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_font_properties\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Efont_song\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n
\u003Cspan class=\&n\&\u003Et\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eset_fontsize\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E(\u003C\u002Fspan\u003E\u003Cspan class=\&s2\&\u003E\&xx-large\&\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E)\u003C\u002Fspan\u003E\n\u003Cspan class=\&n\&\u003Eplt\u003C\u002Fspan\u003E\u003Cspan class=\&o\&\u003E.\u003C\u002Fspan\u003E\u003Cspan class=\&n\&\u003Eshow\u003C\u002Fspan\u003E\u003Cspan class=\&p\&\u003E()\u003C\u002Fspan\u003E\n\u003C\u002Fcode\u003E\u003C\u002Fpre\u003E\u003C\u002Fdiv\u003E\u003Cnoscript\u003E\u003Cimg src=\&https:\u002F\\u002Fv2-be8444f0aae40cf2232eea33fe71b429_b.png\& data-rawwidth=\&554\& data-rawheight=\&434\& class=\&origin_image zh-lightbox-thumb\& width=\&554\& data-original=\&https:\u002F\\u002Fv2-be8444f0aae40cf2232eea33fe71b429_r.png\&\u003E\u003C\u002Fnoscript\u003E\u003Cimg src=\&data:image\u002Fsvg+utf8,&svg%20xmlns='http:\u002F\u002Fwww.w3.org\u002FFsvg'%20width='554'%20height='434'&&\u002Fsvg&\& data-rawwidth=\&554\& data-rawheight=\&434\& class=\&origin_image zh-lightbox-thumb lazy\& width=\&554\& data-original=\&https:\u002F\\u002Fv2-be8444f0aae40cf2232eea33fe71b429_r.png\& data-actualsrc=\&https:\u002F\\u002Fv2-be8444f0aae40cf2232eea33fe71b429_b.png\&\u003E\u003Cbr\u003E\u003Cp\u003E一本正经地分析一下这张图:\u003C\u002Fp\u003E\u003Cul\u003E\u003Cli\u003E韩国菜明显风格跟天朝有差异\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E浙江菜的隔壁是沪菜和江苏菜,江苏菜的隔壁是鲁菜\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E微波炉菜(不知道什么鬼)混入了全部菜系之中\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E闽菜和粤菜相邻\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E粤菜的点分布的还挺开的(大概广东人什么都吃?)\u003Cbr\u003E\u003C\u002Fli\u003E\u003Cli\u003E湘菜跟川菜也挺近的\u003Cbr\u003E\u003C\u002Fli\u003E\u003C\u002Ful\u003E\u003Cbr\u003E\u003Cp\u003E剩下的请恕我老眼昏花看不清楚,从地理上看,还是有点意思的。\u003C\u002Fp\u003E\u003Cp\u003E当然了,说到底这个任务都是我硬生生造出来的,并没什么用,而且,我也根本不懂怎么做菜,权当我是胡说八道好了,毕竟:\u003Cbr\u003E\u003C\u002Fp\u003E\u003Cblockquote\u003E人生呐,就该一本正经地胡说八道。\u003Cbr\u003E\u003C\u002Fblockquote\u003E\u003Cp\u003E原文发表于微信公众号:lijin_echo\u003C\u002Fp\u003E\u003Cp\u003E微信文章链接:\u003Ca href=\&http:\u002F\\u002F?target=http%3A\u002F\u002Fmp.\u002Fs\u002Fj2Iu1cMn0lAbkOeMR-HXTA\& class=\& wrap external\& target=\&_blank\& rel=\&nofollow noreferrer\&\u003E如何科学地“学习”中餐菜谱\u003Ci class=\&icon-external\&\u003E\u003C\u002Fi\u003E\u003C\u002Fa\u003E\u003C\u002Fp\u003E&,&updated&:new Date(&T15:50:19.000Z&),&canComment&:false,&commentPermission&:&anyone&,&commentCount&:0,&collapsedCount&:0,&likeCount&:14,&state&:&published&,&isLiked&:false,&slug&:&&,&isTitleImageFullScreen&:false,&rating&:&none&,&titleImage&:&&,&links&:{&comments&:&\u002Fapi\u002Fposts\u002F2Fcomments&},&reviewers&:[],&topics&:[{&url&:&https:\u002F\\u002Ftopic\u002F&,&id&:&&,&name&:&数据分析&}],&adminClosedComment&:false,&titleImageSize&:{&width&:0,&height&:0},&href&:&\u002Fapi\u002Fposts\u002F&,&excerptTitle&:&&,&tipjarState&:&closed&,&annotationAction&:[],&sourceUrl&:&&,&pageCommentsCount&:0,&hasPublishingDraft&:false,&snapshotUrl&:&&,&publishedTime&:&T23:50:19+08:00&,&url&:&\u002Fp\u002F&,&lastestLikers&:[{&bio&:&不懂就问&,&isFollowing&:false,&hash&:&717f742eececdac475eb783&,&uid&:52,&isOrg&:false,&slug&:&young-jo&,&isFollowed&:false,&description&:&&,&name&:&Young Jo&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fyoung-jo&,&avatar&:{&id&:&594c5ae4a9b40da15279&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false},{&bio&:&从精算向程序员转型中&,&isFollowing&:false,&hash&:&2de60df4a868ccb6d3e146c3e59b617a&,&uid&:28,&isOrg&:false,&slug&:&garroud&,&isFollowed&:false,&description&:&生活好难。&,&name&:&garroud&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fgarroud&,&avatar&:{&id&:&v2-db3cfd83364e&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false},{&bio&:&&,&isFollowing&:false,&hash&:&a4a0dcae6c736e4f28a510fcef72fffc&,&uid&:84,&isOrg&:false,&slug&:&eddie.wu&,&isFollowed&:false,&description&:&生物IT狗,基因检测行业民工,美式体育迷&,&name&:&吴晓立&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Feddie.wu&,&avatar&:{&id&:&v2-c63dcb302edfb962c242&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false},{&bio&:&什么都懂一点,但就是不精,包括吹牛&,&isFollowing&:false,&hash&:&c21dfb04ccdf&,&uid&:88,&isOrg&:false,&slug&:&zhu-jing-ming-99&,&isFollowed&:false,&description&:&一起发财吼不吼啊&,&name&:&宁静明&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fzhu-jing-ming-99&,&avatar&:{&id&:&v2-6b2b407a9cd&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false},{&bio&:&会展实习生&,&isFollowing&:false,&hash&:&b964b9c505d5d350c2be82a9d32b0b3b&,&uid&:444400,&isOrg&:false,&slug&:&san-liang-42&,&isFollowed&:false,&description&:&&,&name&:&三两&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fsan-liang-42&,&avatar&:{&id&:&da8e974dc&,&template&:&https:\u002F\\u002F{id}_{size}.jpg&},&isOrgWhiteList&:false}],&summary&:&\u003Cimg src=\&http:\u002F\\u002Fv2-8b5ece1db95bdcc90eb.png\& data-rawwidth=\&335\& data-rawheight=\&233\& class=\&origin_image inline-img zh-lightbox-thumb\& data-original=\&http:\u002F\\u002Fv2-8b5ece1db95bdcc90eb3119_r.png\&\u003E大概过年的时候围观了一篇这样的文章: \u003Ca href=\&https:\u002F\u002Fjaan.io\u002Ffood2vec-augmented-cooking-machine-intelligence\u002F\& data-editable=\&true\& data-title=\&food2vec - Augmented cooking withmachine intelligence\&\u003Efood2vec - Augmented cooking with\nmachine intelligence\u003C\u002Fa\u003E,讲了一个把食物向量化的一个应用,还挺好玩的。大天朝物产丰富,在吃的方面绝对要比世界人民领先好几个档次,当然也是可以搞一搞这个的。\u003Cb\u003E数据预处理\u003C\u002Fb\u003E我先找…&,&reviewingCommentsCount&:0,&meta&:{&previous&:null,&next&:null},&annotationDetail&:null,&commentsCount&:0,&likesCount&:14,&FULLINFO&:true}},&User&:{&li-jin-33-15&:{&isFollowed&:false,&name&:&李金ECHO&,&headline&:&科学炼丹术士。微博:李小金ECHO。&,&avatarUrl&:&https:\u002F\\u002Fdc6aecf6a7e53dcf5273bfbd_s.png&,&isFollowing&:false,&type&:&people&,&slug&:&li-jin-33-15&,&bio&:&Te echo mucho de menos.&,&hash&:&2c5cea3f3bf251a09c904b5&,&uid&:52,&isOrg&:false,&description&:&科学炼丹术士。微博:李小金ECHO。&,&profileUrl&:&https:\u002F\\u002Fpeople\u002Fli-jin-33-15&,&avatar&:{&id&:&dc6aecf6a7e53dcf5273bfbd&,&template&:&https:\u002F\\u002F{id}_{size}.png&},&isOrgWhiteList&:false,&badge&:{&identity&:null,&bestAnswerer&:null}}},&Comment&:{},&favlists&:{}},&me&:{},&global&:{&experimentFeatures&:{&ge3&:&ge3_9&,&ge2&:&ge2_1&,&nwebStickySidebar&:&sticky&,&newMore&:&new&,&liveReviewBuyBar&:&live_review_buy_bar_2&,&liveStore&:&ls_a2_b2_c1_f2&,&isOffice&:&false&,&homeUi2&:&default&,&answerRelatedReadings&:&qa_recommend_with_ads_and_article&,&remixOneKeyPlayButton&:&headerButton&,&qrcodeLogin&:&qrcode&,&newBuyBar&:&livenewbuy3&,&isShowUnicomFreeEntry&:&unicom_free_entry_on&,&newMobileColumnAppheader&:&new_header&,&zcmLighting&:&zcm&,&favAct&:&default&,&appStoreRateDialog&:&close&,&mobileQaPageProxyHeifetz&:&m_qa_page_nweb&,&iOSNewestVersion&:&4.2.0&,&default&:&None&,&wechatShareModal&:&wechat_share_modal_show&,&qaStickySidebar&:&sticky_sidebar&,&androidProfilePanel&:&panel_b&}},&columns&:{&next&:{}},&columnPosts&:{},&columnSettings&:{&colomnAuthor&:[],&uploadAvatarDetails&:&&,&contributeRequests&:[],&contributeRequestsTotalCount&:0,&inviteAuthor&:&&},&postComments&:{},&postReviewComments&:{&comments&:[],&newComments&:[],&hasMore&:true},&favlistsByUser&:{},&favlistRelations&:{},&promotions&:{},&draft&:{&titleImage&:&&,&titleImageSize&:{},&isTitleImageFullScreen&:false,&canTitleImageFullScreen&:false,&title&:&&,&titleImageUploading&:false,&error&:&&,&content&:&&,&draftLoading&:false,&globalLoading&:false,&pendingVideo&:{&resource&:null,&error&:null}},&drafts&:{&draftsList&:[],&next&:{}},&config&:{&userNotBindPhoneTipString&:{}},&recommendPosts&:{&articleRecommendations&:[],&columnRecommendations&:[]},&env&:{&edition&:{},&isAppView&:false,&appViewConfig&:{&content_padding_top&:128,&content_padding_bottom&:56,&content_padding_left&:16,&content_padding_right&:16,&title_font_size&:22,&body_font_size&:16,&is_dark_theme&:false,&can_auto_load_image&:true,&app_info&:&OS=iOS&},&isApp&:false},&sys&:{&http&:function (url, options = {}) {
transformRequest.forEach(trans =& {
options = trans.call(ctx, options);
options = authHeadersTransformRequest.call(ctx, options);
return myHttp(url, options).then(r =& {
transformResponse.forEach(trans =& {
ret = trans.call(ctx, ret, r);
}},&message&:{&newCount&:0},&pushNotification&:{&newCount&:0}}}

我要回帖

更多关于 日本学生中餐 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信