因為工作的關係又碰到了 Robot Framework,之前用它寫 test case 時比較隨性,這一次因為要將其導入並介紹給團隊,花了些時間看了官方文件跟一些 best practices,也有些實作經驗可分享。

什麼是 Robot Framework, 它能做什麼

Robot Framework 簡單來說就是一個讓你撰寫 keyword driven script 的 framework. 根據你想做的事情引入不同的 library 之後,就能使用各種 keyword 去兜出你想完成的工作。所以理論上它能夠做到 Python 可以做到的任何事情,反正如果沒有現成的 library 或 keyword 就自己寫即可。例如我們寫 Python 時經常用 requests 與 server 溝通:

import requests

url = 'http://yourhost.com'
payload = {'uname': 'user', 'pwd': 'password'}
resp = requests.post(url, data=payload)
print resp.status_code  # 200

如果改用 RobotFramework 來寫的話,就引入 RequestsLibrary 即可:

*** Settings ***
Library  RequestsLibrary

*** Test Cases ***
Post request
  Create Session  my_session  http://yourhost.com
  &{params}=  Create Dictionary  uname=user  pwd=password
  ${resp}=  Post Request  alias=my_session   uri=/  data=&{params}
  Log  ${resp.status_code}

我們可以看到 Create SessionPost Request 等 keywords 就是在做 requests 的 requests.post(),而事實上 RequestsLibrary 也的確是 requests 的 wrapper, 把 requests 能做到的事情打包成 keywords 讓你在 Robot Framework 裡面使用。再看一個 webdriver 的例子,用 Python 驅動 browser 去點擊或輸入網頁是這樣寫:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('http://yourhost.com')
element = driver.find_element_by_id('THE_ID')
element.send_keys('VALUE')
element = driver.find_element_by_xpath('THE_XPATH')
element.click()

在 Robot Framework 中則是引入 Selenium2Library:

*** Settings ***
Library  Selenium2Library 

*** Test Cases ***
Open browser and run
  Open Browser  http://yourhost.com  chrome
  Wait Until Element Is Visible  id=THE_ID
  Input Text  id=THE_ID  VALUE
  Wait Until Element Is Visible   xpath=THE_XPATH
  Click Element  xpath=THE_XPATH

同樣地,Open Browser, Wait Until Element Is Visible, Click Element 等都是 Selenium2Library 提供的 Keywords。當然,你也可以用 Keywords 組成自己的 Keyword (Wait And Click, Wait And Input):

*** Settings ***
Library  Selenium2Library 

*** Test Cases ***
Open browser and run
  Open Browser  http://yourhost.com  chrome
  Wait And Input  id=THE_ID  VALUE
  Wait And Click  xpath=THE_XPATH

*** Keywords ***
Wait And Input
  [Arguments]  ${locator}  ${text}
  Wait Until Element Is Visible  ${locator}
  Input Text  ${locator}  ${text}
  
Wait And Click
  [Arguments]  ${locator}
  Wait Until Element Is Visible   ${locator}
  Click Element  ${locator}

如果沒有現成的 Keywords 可用,自己寫一個也很方便,例如這個做 Base64 編碼的 class:

import base64

class Base64Library:
    def base64_encode(self, text):
        return base64.b64encode(text)

只要路徑正確,就能在 test script 內引用自己定義的 keyword (Base64 Encode):

*** Settings ***
Library  Base64Library.py

*** Test Cases ***
Self-defined Keywords
  ${encoded}=  Base64 Encode  abc123  
  Log  ${encoded}  # YWJjMTIz

當然常見的變數宣告、參數、If-else、迴圈等,也都可以使用。

為什麼要用 Robot Framework

雖然 Robot Framework 可以做到幾乎任何 Python 能做的事情,但看到這邊你一定有個疑問:為何我還要為了這個 framework 去查各種 library 與 keyword 的用法,直接寫 Python code 不是快得多嗎?沒錯,如果只是要翻譯 Python code,根本不必用到這個 framework,這個 framework 是用在自動化測試,尤其是自動化驗收測試 (acceptance testing) 上的。使用 Robot Framework 做自動化測試的好處有:

  • Keyword Abstration. 從前面的例子可以看到,雖然我們能夠直接寫 Python code, 但是 Robot Framework 有可能已經幫我們把好幾行程式碼濃縮成一個 keyword,例如使用 webdriver 時我們常常在等某個 DOM element 出現,在 python 裡面可能要寫個 try block 之類的去處理,但用 Robot Framework + Selenium2Library 一個關鍵字就搞定了 (Wait Until Page Contains / Wait Until Element Is Visible等);另外 keyword driven script 對於程式經驗較少的人來說也會比 Python 或 Java 程式碼容易上手;最後,自訂關鍵字的架構更可以把操作步驟一路抽象到自然語言層級,達到 “Test case 即註解” / “Test case 即文件” 的地步。這部分後面會再說明。

  • Test Report and Jenkins Integration. 它的報表與 Jenkins 整合功能大概是很多人選擇它的原因。Test script 執行之後會自動產生 HTML log,若 test case fail 會顯示停在哪一步,若是可以抓圖的話也會幫你把畫面抓下來,如下圖。當然它也支援一些測試相關功能,如 tag, test setup/teardown 等,Jenkins 也有 plugin 能顯示報表內容。

2016-07-28-rbfk

  • Human Readable Acceptance Test. 把 test case 的步驟用自然語言描述,讓不寫程式的人 (工讀生/PM/老闆) 都能看懂,是 Robot Framework 官方文件的建議寫法,但很多人往往只著重在把程式邏輯翻譯成 test script,這樣固然可以享受到 Robot Framework 的測試報表及 CI 整合等好處,但沒有利用到它全部的優點,比較可惜。以下分享一些 best practices.

Robotframework 的 Do’s and Dont’s: 怎麼寫易維護的 Test Case

剛開始寫 Robot Framework test script 的人,往往著重在把測試程式的邏輯翻譯成 keyword 的形式,這個起手式沒錯,例如上面的 webdriver 例子,直接等待並操作 DOM elements:

*** Settings ***
Library  Selenium2Library 

*** Test Cases ***
Open browser and run
  Open Browser  http://yourhost.com  chrome
  Wait Until Element Is Visible  id=THE_ID
  Input Text  id=THE_ID  VALUE
  Wait Until Element Is Visible   xpath=THE_XPATH
  Click Element  xpath=THE_XPATH  
  ...

用了一段時間之後,你可能會將測資設為變數,增加使用彈性,也可能把常用的實作細節包裝成自訂 keyword, 例如:

*** Settings ***
Library  Selenium2Library 

*** Variables ***
${HOST}  http://yourhost.com
${BROWSER}  chrome
${TEST_VALUE}

*** Test Cases ***
Open browser and run
  Open Browser  ${HOST}  ${BROWSER}  
  Wait And Input  id=THE_ID  {TEST_VALUE}
  Wait And Click  xpath=THE_XPATH
  ...

*** Keywords ***
Wait And Input
  ...

Wait And Click
  ...

做到這一步其實已經有一定的彈性,但還是有一些缺點,最明顯的就是只看得出 test case 怎麼做 (How),但看不出它在做什麼 (What)。你要測試的 test requirement (system responsibility),與實作細節 (按鈕的 Xpath 或 id) 顯然無關。另外,如果其他 test script 也要用相同的自定義 keywords 怎麼辦?或日後 test case 一多,該如何降低維護成本?要比較好地處理這些問題,我們要回到驗收測試的基本精神:驗收系統功能,在不知道系統的介面及實作細節的前提下,利害關係人一樣知道系統該做什麼。因此,把系統功能步驟以自然語言的描述方式留在 test case 層級,實作細節留在 keyword / library,並把常用的實作細節抽出來方便重複引用,就是官方推薦的使用方式。例如若要驗收從瀏覽器登入的功能,以下是一個可能的寫法:

*** Settings ***
Library  Selenium2Library

Resource  resource.txt  # 有 Wait And Click, Wait And Input 等
                        # 其他 test script 也會用到的 keywords
			
# 每個 test case 開始前與結束後需要的步驟可寫在 Setup 與 Teardown
# 或是整個 test suite 所需的步驟可以寫在 Suite Setup/Teardown

Test Setup  Proceed With Login Page
Test Teardown  Close All Browsers

*** Variables ***
${HOST}  http://yourhost.com
${BROWSER}  chrome
${USERNAME}  user
${PASSWORD}  pass
${EMPTY_USERNAME}  ${EMPTY}
${EMPTY_PASSWORD}  ${EMPTY}

*** Test Cases ***
Valid Login
  Login With Valid Credentials
  Dashboard Should Be Presented

Invalid Login
  Should Reject Invalid Credentials  ${USERNAME}  ${EMPTY_PASSWORD}
  Should Reject Invalid Credentials  ${EMPTY_USERNAME}  ${PASSWORD}

*** Keywords ***
Proceed With Login Page
  Open Browser  ${HOST}  ${BROWSER}
  Wait Until Page Contains  Welcome

Login With Valid Credentials
  Login With Credentials  ${USERNAME}  ${PASSWORD}
  
Login With Credentials
  [Arguments]  ${uname}  ${pwd}
  Wait And Input  id=username  ${uname}
  Wait And Input  id=password  ${pwd}
  Wait And Click  id=submit

Dashboard Should Be Presented
  Wait Until Page Contains  dashboard

Should Reject Invalid Credentials
  [Arguments]  ${uname}  ${pwd}
  Login With Credentials  ${uname}  ${pwd}
  Wait Until Page Contains  Invalid username or password

這樣寫有什麼好處呢?第一個是把 test requirement 與實作細節分開,如果只看 test case,任何人都能輕易了解第一個是在測合法登入,登入後要看到 dashboard;第二個是在測非法登入,並且分成空的密碼與空的使用者名稱兩種,只關心功能的人完全不需要知道怎麼實作。另外,盡量抽出重複的實作,如果實作細節改變了 (例如登入鈕的 id / xath 改了),就能把修改成本降到最低。很多公司完全沒有導入自動化測試,因為維護 test case 是需要成本的,而成本主要來自兩個地方:需求變動與實作細節變動。把這兩個地方拆分有助於降低維護成本。你可以想像若直接把程式邏輯翻譯在 test case 層級,當需求變動時,我們必須花時間去看這一段邏輯是在做什麼事情;若實作細節改變了,就得大改一堆 test case。所有花在了解 test case 的時間,都在消耗工程師的生產力。

這份文件這份投影片建議了 Robot Framework 的 Do’s and Dont’s,我摘錄如下:

  • Test case 的命名: Tell what, not how
  • 使用變數取代 hard coding
  • 適當的抽象化
  • 用等的 (Wait Until…) 而不是睡的 (Sleep)
  • 讓 test case 自我描述,非必要不使用 document/comment
  • 盡量不要讓 test cases 有相依性
  • 盡量不要在 test case 層級有 variable assignment;複雜的邏輯如迴圈等盡量放在 library

這份文件在講如何寫易維護的 test case,原則如上所述,也可以看看。

Robot Framework 與 Jenkins 的整合

與 Jenkins 的整合似乎就沒有什麼好講的了,就該裝的 plugin (robotframework, virtualenv) 裝一裝,該設定的 dependency 設一設。我目前做的事情是把一些手動測項改寫成 script,導入 Robot Framework 由 Jenkins 驅動。每當待測程式有新版的 build, 就從 git server 上把 script 拉下來, 建一個 virtualenv, 把最新版 build deploy 到機器上做 regression testing. 瀏覽器的部分在寫 script 時是用 Chrome webdriver, Jenkins 上是用 PhantomJS 跑 headless.

雖然說是自動化測試,但目前在業界還是手工藝,只能把一些簡單或常規的測項寫好之後讓它重複跑,省去 regression testing 的時間,讓 test engineer 能夠把心力放在複雜的測試上。至於真正的全自動化測試,目前還是在學術研究的階段,必須搭配自然語言處理與機器學習的進展,也是我的研究興趣。


如果你曾在網路上看過程式設計師最常回答的20句話,你可能有印象其中好幾句都跟程式執行結果的不穩定性有關,例如”程式昨天還好好的”、”之前不會這樣”等等,而第一名:

“It works on my machine.”

除了讓人會心一笑之外,也點出了在軟體測試在實務上的問題:需要測試的環境組態太多,且輕微的組態差異就可能造成不同的程式行為或結果(註)。Google Testing Blog 最近的文章: Flaky Tests at Google and How We Mitigate Them 就提到了 Google 內部的情況以及他們的處理方式。這篇文章將 flaky tests 定義為 “在一樣的待測程式、待測環境及測試程式碼下,測試結果有時候 pass, 有時候 fail 的那些 test cases”,中文姑且稱之為不穩定的測試個案。不穩定的測試個案會造成什麼影響?可能會大幅降低 programmer 的生產力:

  1. 對於 falied test 要花時間去看錯在哪裡, 花時間 debug
  2. 一時之間找不到 bug, 再花時間重跑 test 看看, 結果竟然過了?!
  3. 若此情況發生多次, developer 對於 test 的效力就會失去信心, 以後看到 failed test 可能就直接略過 (忽略了真正的 bug), 或是多跑幾次看會不會運氣好 pass (又是時間的浪費)

因此, flaky tests 對於軟體品質跟工程師的生產力傷害甚鉅。你可能會好奇為什麼同樣的環境下測試為什麼有時候會過有時候不過?文章中提到了幾個 flaky test 的成因,例如:程式本身的行為就是不確定的 (Nondeterministic)(例如程式內會根據隨機產生的值有相對應的行為)、所用的 third party code 不穩、環境問題等等。ICSE’15 的這篇論文也提到了影響 System GUI Testing 可重複性的幾個因素:

  1. 執行環境,例如不同 OS,不同 browser,不同的 Java 版本,甚至只是 Oracle Java 與 OpenJDK 的不同也會有差
  2. 程式啟始組態與輸入檔
  3. 自動測試工具的設定 (以 GUI 測試來說最常見的就是每個動作的間隔時間)
  4. 其他無法控制的因素,例如以程式啟動的時間日期做 random seed 等

論文中也提到:就算把前三個變因都控制到一模一樣,還是無法避免程式在 code coverage 或 GUI 畫面上會出現不同的測試結果。那 flaky tests 在 Google 內部出現的情況如何?文章中提到兩個統計數據:

  1. 全部的測試中有 1.5% 是 flaky tests
  2. 在程式提交後的自動測試 (post-submit testing), CI (Continuous Integration) 系統找出的由 passed 變成 failed 的 tests 中, 有 84% 含有 flaky tests

比例不算低,而 Google 用了一些方法去對應 flaky tests:

  1. test 連續 fail 三次才標記為 fail (降低是 flaky test 的可能性, 但就多了執行時間)
  2. 對於 test 可以標記其 flakiness (我猜是人工標註), 自動把高 flakiness 的 test 放到隔離區, 日後處理, 以免影響整體測試.
  3. 目前正在試著從 code 或 execution traces 裡找出與 flakiness 有高度相關的 features

而上面提到的論文也建議了一些讓 System GUI Testing 可重複的一些建議步驟:

  1. 確保執行環境是有紀錄的,且保持一致
  2. 同一個 test case 跑多次再確定結果
  3. 注意 application specific 的要求 (例如用到執行時間做 rand seed, file/network permissions, memory 要求等)

其實可以看到目前還沒有什麼好的解決方式。

註:專門探討如何系統化測試程式的各種參數或環境組合的研究叫做 Combinatorial Testing, 這篇論文有廣泛的回顧


PyConTW 是 Python 社群的年會,可以看看各地的 Python 使用者做了什麼有趣好玩的專案。每個人平常可能都專注在手頭上的工作,所以參加社群聚會是一個啟發創意思考,學習新知的好機會,也可以認識新朋友或找工作,現場有贊助商擺攤。參加後的心得簡言之如下:

  1. Keynote 都很有水準,沒讓人失望
  2. Talk 部分,每個人的背景、興趣不同,因此不是每一場演講都有收穫,有些太淺,有些因背景知識不足引不起興趣,但是都可以參考參考。(深深覺得我也應該投稿的…)
  3. 只聽演講其實沒有辦法學到多少東西,因為演講只是一閃而過的訊息,要學會還是要讀文件跟實作,所以就是看看別人在你有興趣的領域上,是怎麼解決問題,用什麼套件等。
  4. 可以看看社群在溝通協作上都用什麼工具,像共筆採用 hackfoldr + hackmd,就令我耳目一新;另外還有 sli.do 可以接收聽眾問題,gitter 公共聊天室,speakerdeck, slides.com 放投影片等。

我印象比較深刻的講題(與個人興趣、背景高度相關,僅供參考):

  • 唐鳳的 Keynote - 明日之後的世界: 講他推廣公民網路參與公共議題,形成共識的經驗
  • Mosky - Boost Maintainability: 講節省開發及除錯時間的程式設計原則
  • jserv 的 Keynote - Python 導入系統軟體教學: 講他在學校教書的經驗跟最近參加的本地大型專案。jserv 的名氣就不用提了,聽過好幾次他的演講後,我只想說原來程式大神跟嘴砲大神可以存在在同一個人身上 XD
  • 迪士尼資深工程師 Paul 的 Keynote - Inside the Hat: Python @ Walt Disney Animation Studios: 講動畫電影製造過程,Python 在其中的角色,他們對於商業軟體的看法與使用方式
  • PF - 用Numpy做一個自己的股票分析系統: 這大概每個有在買股票的工程師都想過要做,包括我自己 XD 他有提到用 Numpy 加速計算,跟前端 UI 可用 Amcharts.js
  • 柯維然 - 用Google Cloud Platform玩交通資料分析: 單純只是很驚訝泛公務人員體系的臥虎藏龍,之前也有叢培侃這位資安專家 (雖然他後來也離開了),這些人是我離開之前沒有預料過會遇見的
  • 施晨揚 - 如何打造關鍵字精靈: 談他用 Pixnet data 建詞彙關聯的結果,基本上就是在講 Word2Vec 及斷詞,對我而言技術已知,但 data 只有他有,所以可以看看他的實證結果;另外他也提供了好幾個我不知道的斷詞用字典來源
  • Andy Dai - Analyzing Chinese Lyrics with Python: 一樣是技術已知,但結果有趣;也講了很多計算與呈現結果可以使用的套件 (pandas, counter.most_common(), matplotlib, wordcloud)
  • PTVS 作者 Steve 的 Keynote - Intentional Communication: 很令人意外地沒有講他做 PTVS 的技術細節 (大概留在收費的 tutorial 了),而是在講如何有效溝通與溝通工具(說、寫、教)的效果,很有渲染力,他怎麼得到目前這份工作的過程也很值得一聽

全部議程共筆在這。


距離總處事求人開放資料版網站上線已經超過一年半了,期間經歷了各種奇怪的阻礙,例如:

  • 時不時就抓不到資料 (當天沒資料的話網站只能開天窗)
  • 突然改變資料開放的方式,從可以直接 GET 變成要從網頁 POST (後來又改回來了)
  • 總處主機突然擋起了國外 ip (我也想架在台灣但 AWS 在台灣沒有主機呀)
  • 除了我以外,也看到其他人要求總處增加開放資料的頻率,從每日更新一次到每日兩次等,不做就是不做,還把每日新增職缺貼在總處的 fb 頁面上,我是不太懂為什麼他們寧願人工張貼資料,也不願意讓機器自動從資料庫重新產製開放資料就好… (2016-06-02 更新: 現在資料改成每日產製兩次囉! 幫總處同仁按個讚!)

透過民意信箱跟總處打了多次交道,雖然官僚難免,但總的來說服務還是滿周到的,反應的問題大部分都有解決。

開始收集每天的開缺資料也已經超過一年了,為了慶祝即將上任的副人事長是資訊背景,人事資訊化將大有可為(?),花了兩天增修了網站的一些統計功能:

  • 新增各機關開缺數查詢:先點選機關,再點選職系,最後可看到開缺細節。所有表格皆可搜尋及自由排序欄位
  • 修改各職系開缺數查詢:改以表格呈現,並可看到該職系開缺機關,可搜尋及自由排序欄位
  • 職缺特殊條件新增「✔同意開放簡歷」,對應原總處「請注意:本職缺啟用現職應徵人員調閱簡歷功能,現職應徵者需同意開放簡歷給徵才機關調閱」條件

有了職系開缺數查詢,如果你想轉職系,或是朋友在選考公職職系時,可以來看看該職系是否常常開缺,最常開缺的機關是那些,從而了解是否容易調動;至於各機關開缺數查詢的使用時機更廣,例如:

  • 你很想調到某機關,想知道他們有沒有在事求人開過缺 (例如央行從不開外補)
  • 你看到某機關開缺了,想知道該機關是否一天到晚在找人

這邊要注意的是很多機關的缺是掛在上級機關下 (例如北市國中小人事室主任的缺都是北市府人事處開的),因此要找此類職缺必須先從上級機關 (例如北市府人事處) 找起,職缺列表的工作地址會註明真正的工作機關,並請善用關鍵字搜尋,如下圖。

opencpa-1

職缺列表的順序是從開缺日期最近的缺開始,但所有表格的每個欄位都可以自由排序。

總處的開放資料內容其實滿亂的,因為不是每個張貼職缺的人都會依照格式輸入,我只用了一些簡單的規則去判斷職缺結構,爬梳結果難免有不完整的地方 (例如職等判斷錯誤或留下了非公務人員的職缺職系等),不過就先頂著用吧。另有關本站目前的匿名留言功能,我一開始是希望有身分認證,然後讓大家可以私密地交換有意義的資訊,不過我早期測試的結果顯示很少人想要曝光,而且 fb 的封閉社團或 line 群組就已經可以實現這個想法,所以就不做了。網站未來增修的方向:

  1. 把考試缺資訊一起整合進來,機關用人的全貌會更完整 (之前有收到一位朋友來信,似乎正在做這部分的功能)
  2. 附上 Ptt 針對某機關某職系的討論文章

不過實作日大概也是遙遙無期吧。


用自然語言處理與機器學習標註景點主題

很多人喜歡旅遊,但是對於一個旅遊景點,每個人關心的主題是不同的:有的人特別喜歡購物,有些人愛吃美食,喜歡看風景的人也有人文景點或自然景點的偏好,或者你的興趣是攝影,特別關心哪邊有好的取景點。因此,若事先知道這個景點與哪些主題較相關,就能夠依照個人喜好安排自己的旅遊行程。要怎麼知道一個詞彙(景點、地名或商店名稱)與哪些主題相關?人工標註當然很容易,但要怎麼讓機器做到呢?一個直觀的想法是:如果出現這個詞的文章都是在討論某個主題,那這個詞屬於這個主題的機率就很高。例如有”一蘭拉麵”出現的文章大部分都是食記類文章,則可合理推斷”一蘭拉麵”與”美食”這個主題相關。當然,如果有一篇文章在講攝影,然後提到”拍完照後大家都餓了,就前往有名的一蘭拉麵”,則”一蘭拉麵”也會被標註上”攝影”這個無關的主題,但只要文章數量夠多,我們就能用與該詞彙有關的各主題的機率去做判斷,畢竟直覺上一個美食的詞彙出現在美食類文章的數量會比出現在攝影類文章大得多。所以”標註景點主題”的問題就轉變成了”標註文章主題”的問題,而我試著用自然語言處理跟機器學習來解,做法是:

  1. 先決定幾個預設的主題,取一小部分的文章做 training data, 手動標註這些文章的主題
  2. 將 training data 的每一篇文章斷詞後做 Topic modeling, 也就是用這些文章建立 dictionary, language model, 將文章表示成 latent vector space 中的向量
  3. 將剩下的所有文章(testing data),用已經建立好的字典跟模型投射到同一個 latent space 中,看這個向量(這篇文章)與 training data 中的哪一個向量(哪一篇文章)最相似(計算 Cosine similarity),最相似文章的主題就是這篇未知文章的主題。

測試結果

為了驗證,我找了 PTT Japan_Travel 板上標題有”東京”的食記、遊記及住宿類文章大概 5000 篇,接著手動標註了今年1-2月份的文章大約 250 篇(5%),用這 5% 的資料建模,讓機器去標註剩下 95%的文章,有了文章主題後再計算字彙的主題。以下是一些字彙的標註結果:(程式語言是 Python, Topic modeling 用 gensim, 斷詞用 jieba)

迪士尼樂園

  • 景點 0.5294
  • 購物 0.1548
  • 美食 0.0991

嗯,看起來還滿準的

六厘舎

  • 美食 0.4444
  • 景點 0.3333
  • 購物 0.1667

吃沾麵的地方,也正確

昭和記念公園

  • 景點 0.3913
  • 攝影 0.2174
  • 美食 0.1739

搜尋了一下,很多人在這邊拍銀杏跟櫻花

不過除此之外,也有很多不準的,例如:

羽田機場

  • 景點 0.356
  • 購物 0.2042
  • 美食 0.1832
  • 機場 0.0236

一蘭拉麵

  • 景點 0.3477
  • 購物 0.2865
  • 美食 0.1836

標註錯誤的原因有很多:

  1. 該詞彙不是景點,但出現在大量的遊記中,例如很多篇遊記都在羽田機場下機,都去吃一蘭拉麵
  2. 也因為絕大部分的文章都有”景點”這個主題,所以”景點”幾乎 dominate 了所有詞彙的主題排行第一名
  3. 主題切分不夠細,training data 太少,斷詞處理得不好,沒有處理同義字…等

不過就算有更多 training data, 或花更多時間調整精細度,統計式或機率式的自然語言處理都有其極限,所以現在才有很多人改用 deep learning 去試,而中文的處理更難,關鍵還是在斷詞,如果斷詞用的字典不夠大,效果就不可能好,而斷詞用的字典幾乎只能靠人工建立.

首次參加黑客松心得

因為朋友相約參加黑客松,才騰出時間做了上面的實驗。我們參加的是經濟部工業局辦的一個“Big Data X Maker”黑客松,然後其實我們做的成品不只這樣,而是一個東京旅遊推薦系統:依照個人喜好、旅遊天數、預算高低自動產生景點與行程規劃。除了上述部分外,其他朋友負責網站前端、後端、行程排程演算法等,最後的成品如圖:

hackathon-1 hackathon-2

很可惜的是最後沒有得獎。之前就有耳聞,但這次確實觀察到了有關黑客松的一些有趣現象:

  • 大概有一半的隊伍沒有任何成品,只有簡報,而且其中有好幾隊都抱走了獎項(所以是簡報松?美工松?創意松?)
  • 有好幾隊在簡報裡面都說:我們的 App/網站長這樣,讓使用者可以 blablabla,看到最後才發現都是概念圖或改圖的…
  • 撇開沒有成品不說,確實有看到一些新的 idea, 也看到好幾組做特殊領域的 chatting bot, 看來 bot 的趨勢有傳播到國內

平心而論檢討我們的成品,沒有得獎的因素可能如下:

  • 旅遊相關的主題,評審大概看多了,覺得不夠有創意,簡報的方式也可以再改進
  • 資料來源只有 PTT Japan_Travel 板,其他部分都是串 API 得到的,可能不夠多,可以再介接一些 facebook 打卡熱點,或是從 blog 或 fb post and photos 自動學習使用者的興趣等

不過總而言之有學到東西,也有團隊合作,是一次很有趣的經驗!