EZTABLE IDEAS 是 EZTABLE 成員揮灑熱情和大家分享專業及創意的網誌。 EZTABLE 讓消費者 24 小時都可以在網路訂位全台灣最優質的餐廳,同時提供餐廳經營者 e 化的訂位管理系統 (雲端、iPad、智慧型手機)

寶貝,晚餐想吃什麼?讓我們去有帥哥氣氛又好的餐廳吧~

七月 05 2016 Published by under Engineering

1511a2f4-651c-45d4-8abe-000947e56bf4.1511a2f4-6514-4f57-b9ee-a78ca10c5da5.png.cf

建議點這裡 Markdown 好讀版

有一對情侶正為晚餐不知道要吃什麼而煩惱…

  • 男:寶貝,晚餐想吃什麼?
  • 女:都可以呀!
  • 男:我們去吃久久神鍋好不好?
  • 女:很熱欸~
  • 男:那去轉角吃涼麵怎麼樣?
  • 女:那又沒有冷氣吹~
  • 男:找一家有帥哥店員的好不好?
  • 女:好!讓我們去有帥哥氣氛又好的餐廳吧~
  • 男:😂😂😂

男友不禁想問,為什麼找一家餐廳會這麼困難呢?氣氛要好又要有帥哥店員的餐廳到底在哪裡?換個角度想,炎炎夏日,為什麼找不到一家主打充滿陽光、沙灘、比基尼這種夏日風情的餐廳?我們常常在餐廳享受的不只是食物,而是享受餐廳營造的氣氛,餐廳營造的可以是一個人與食物的寧靜對話,可以是三五好友歡聚的燒烤派對,當然也可以是家人一同聚餐的溫馨。

這是一篇關於如何透過情境搜尋餐廳的文章可以直接往下看結果

專案緣起

不知道大家最近有沒有看到一篇 PTT 上的文章?作者對約 X 信進行語義分析,內容專業到讓人無法直視,看的當下就覺得:哇!原來語意分析還有這種應用的方式!程式語言是用來幫忙解決問題的好工具,能把它應用到生活大小事上真的很棒!這篇文章燃起了我心中對文字探勘的熱情,剛好最近有個比賽會需要這方面的技術(才不是因為 PIXNET HACKTHON 的比賽能不能順利參加而抱著不服輸的心態呢!)

由於本身對資料分析很有興趣,尤其是圖像分析和語意分析,因為他們能夠應用的範疇很廣,而且已經不知不覺地影響著這個世界的運行,例如無人車駕駛、Alphago、SkyRec、IBM Waston 等等。這個領域的知識又深又廣,既然要朝這個方向持續邁進,平常就要有所累積。公司正在朝著將情境與餐廳建立連結轉型,正好和我有興趣的領域有所重疊,所以對於這個專案我也有比平常玩玩還認真的使命感,於是便花了星期六和星期日的上午把做了一些有趣的東西。

 

工具介紹

大多數的公司使用 Solr, Elasticsearch 建置搜尋引擎,有些還會直接嵌入 Google 搜尋列,前者運用的方法是 TF-IDF,後者就是借助 Google 強大的搜尋演算法。但是沒有一種方法是完美的,如果今天下的關鍵字比較多,想要透過「酒館」和「義式」搜尋餐廳,就會發現沒有我要的結果,但是這兩個關鍵字如果分開來就都能得到結果,事實上,這兩個關鍵應該是有著相關性的,但是透過 TF-IDF 卻無法知道。如果可以將這兩個關鍵字的特性相加之後得到一個新的特性,再用新的特性去尋找最相近的餐廳就太棒了!

這就是本篇文章會運用到的概念,這個概念的基礎是 Word2Vec,它很適合用來對文字、圖像、聲音進行模糊搜尋,由於運作原理一言難盡(死線要到啦),我就直接說重點:透過訓練將詞會投影到高維度的向量空間,相近的詞彙有相近的詞向量。

而詞向量有個特性是可以透過相加減獲得有趣的結果,例如:國王 - 男人 + 女人 ~= 皇后

 

操作流程

1. 收集連結:收集公司合作餐廳的食記連結,並且把餐廳資訊與餐廳食記連結輸出成文字檔,檔案內沒有提供連結。

執行 python getUrl.py

2. 爬網站 & 擷取資訊:過濾非 Pixnet 連結透過 requests 結合 multiprocessing 爬網站的 Html。使用 PyQuery 擷取網站標題與內容,並且存到 Sqlite。

執行 python getBlog.py

3. 斷詞:使用 Jieba 對文字進行預處理,轉換成 Word2Vec 能夠訓練的格式。

執行python cut.py

4. 訓練:透過在 gensim 中實作的 Word2Vec,設定參數對資料進行訓練,產生詞向量與模型。(直接使用 52nlp 提供的檔案)

執行 python train_word2vec_model.py training_sentence.txt model_name.model vector_name.vector

 

注意事項

在專案中主要遇到兩個困難:

    • 處理中文字遇到的編碼問題:Unicode、UTF-8 與 ASCII 之間錯綜複雜的關係,不同套件的輸入的接口要求的編碼可能不一樣。
    • 使用 multiprocess 要小心:原因還沒有弄清楚,只要在 the_function 裡面加入了 pyquery 或是 sqlite 的 function 就會 crash,但是放 requests 就沒事。


from multiprocessing import Pool
p = Pool(5)
results = p.map(the_fucntion, inputs)

 

專案成果

1. 先載入 gensim 套件與剛剛訓練好的 model

import gensim
# print result
def ps(result):
if result:
for e in result:
print e[0], e[1]
# load fresh model
model = gensim.models.Word2Vec.load("articles_rname.model")


>>> result = model.most_similar(u"夏天 海灘 餐廳".split(" "), topn=5)
>>> ps(result)
'皮椅' 0.694285988808
'LOUNGE' 0.688326239586
'HALEAKALA' 0.68235886097
'仿舊' 0.674678146839
'小徑' 0.662850260735

我們想要的結果是根據情境找到符合的餐廳,但是得出的結果只有2家餐廳,2個名詞,1個形容詞。因此我們必須建立涵蓋訓練集餐廳的 list,把這個 list 的詞向量拿出來與我們想要搜尋的情境詞向量進行相似度的計算。特別感謝 jimgoo 提供的 most_similar_in_list function,讓我可以直接使用。


>>> print(rname_list[:5])
[u'Follow', u'Bellini', u'TABLE', u'Taverna', u'90']
>>> print(mapping(rname_list[:5]))
[u'Follow Lady 法蕾蒂', u'Bellini Pasta Pasta', u'TABLE JOE 喬桌子廚房', u'Taverna De Medici 梅帝騎小酒館', u'90 a la sante 酒食歐風朝']

>>> result = model.most_similar_in_list(u"夏天 海灘".split(" “), topn=5, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘VG Cafe & Bistro’ 0.650945961475
‘HALEAKALA 夏威夷酒吧餐廳’ 0.615895032883
‘Eslite Tea Room’ 0.599678635597
‘URBAN331-台北慕軒飯店’ 0.579266548157
‘Destino 妳是我的命運’ 0.57857131958

>>> result = model.most_similar_in_list(u"消暑 下午 茶".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Caldo Cafe咖朵咖啡’ 0.47723197937
‘Eslite Tea Room’ 0.468698769808
‘H-Bar’ 0.460396289825

>>> result = model.most_similar_in_list(u"正妹 店員".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘etage15-高雄Hotel dua’ 0.468320250511
‘Sunny Cafe’ 0.447554886341
‘Kevin Coffee’ 0.418976008892

>>> result = model.most_similar_in_list(u"音樂 悠閒".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Mammoth lounge’ 0.670462846756
‘HALEAKALA 夏威夷酒吧餐廳’ 0.626639544964
‘RUBY CAFE’ 0.6229159832

>>> result = model.most_similar_in_list(u"工程師".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘American Steakhouse’ 0.802481234074
‘i sweet’ 0.785791814327
‘Silk Road Feast 絲路宴餐廳’ 0.776082456112

>>> result = model.most_similar_in_list(u"求婚 紀念".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘Ton Up Cafe’ 0.62010884285
‘TABLE JOE 喬桌子廚房’ 0.608335494995
‘URBAN331-台北慕軒飯店’ 0.606325864792

>>> result = model.most_similar_in_list(u"酒 餐廳 美式 跨年".split(" “), topn=3, restrict_vocab=rname_list)
>>> ps([[mapping(rname[0]), rname[1]] for rname in result])
‘bar & restaurant a³ 新義式餐廳’ 0.665651142597
‘MW 時尚義法料理&酒品’ 0.665459275246
‘Le Bar 吧 戶外餐廳’ 0.644170224667

這些結果很有趣,有空再來分析~

 

心得 & 未來展望

  • 餐廳的食記數量不夠多,或是數量不平均,會影響到訓練結果
  • 改成收集評論可能會更精準
  • 將多為向量壓到二維,可以拿來做 clustering
  • 文字處理不容易但是很重要
  • 多國語言搜尋也能配合 Word2Vec

 

 

特別感謝 & 參考資源

Python 有很多好用的套件,像是中文斷詞有 jieba,word2vec 有 gensim,用起來上手很快,而且還有熱心的大大們不吝分享與教學。


Related Posts Plugin for WordPress, Blogger...

No responses yet

發表迴響