我的 Line Bot 很認真的幫我們服務了數個月,舉凡提醒下班,休息,中午吃飯到提醒我們高尚的會計小姐該作些什麼事,又或方便資訊快速獲取,方便至極。今天我打錯命令關鍵字(key word),他就只會問我有事嗎?>.<|| 的確是沒什麼事.
為了讓他有趣一點,可以給一些驚喜的對答,把塵封己久的 TF-IDF (term frequency–inverse document frequency)技藝再度擦亮。如果只是要計算文件間的距離或是分類,可以使用 scikit learn 或是 mahout 來實作,不用自己來實作這部份,可以把時間節省下來給美好的人生。這裡我打算自行實作這三個數字,也因為我想建立一個自己的小而美輕量可操作模型,並且控制 Bot 的回應時間能在最短時間回覆。
** 資料 **
- 各大網站,百度娘查詢
** 資訊技術 **
- python - jieba, line-bot-sdk-python
- 資料庫及模型儲存 - MySQL
** 進化後的 Line Bot 機器人 **
我隨意找了兩部小說,一部是關於穿越時空,一部是關於愛情的,合計對話句子有48,084句,未來應該會讓 Bot 再學個三國誌相關帶有歷史色彩的小說來讓飽讀詩書。
先來問問他的狀況:
再來介紹我自己:
這個回答蠻有趣的,看來還是得回頭檢視分詞。
抱怨一下:
** 實作細節 **
- 獲取來源文檔,並粹取對話句子,在這裡因為來源為簡體小說,所以為了使機器人能明瞭,使用了 Linux 下的 iconv 來轉換,常遇到這個錯誤
illegal input sequence at position
可以利用 -c 這個參數忽略該錯誤,如下的命令轉換,:
iconv -f utf8 -t gb2312 -c words-cn.txt \
| iconv -f gb2312 -t big5 -c \
| iconv -f big5 -t utf8 -c > words-big5.txt
如果是要繁轉簡則將 -f 與 -t 反之轉換
- 分詞,則是相當重要的環節,分詞出來的結果會導致 TF 與 IDF 的計算準確度,以往我都會把含有頻率較多詞的句子一一看過,並使用自訂分詞的功能來將結果修正。而關於分詞的工具,可以參考這篇非常詳細的介紹:11 款开放中文分词引擎大比拼。目前我較常使用為結巴分詞,因其直接支持 Python及繁體,另外就是自訂詞。在分詞時可視應用需要把不必要的詞過濾(stop words),在這我把少於兩個字跟數字還有在我所定義的 stop_words[] 都過濾掉,其分詞如下:
import jieba
jieba.load_userdict("user-dict.txt") #自訂義詞
seglist = jieba.cut(line_word) #結巴分詞
for s in seglist:
#忽略詞長度小於 2
if len(s) < 2:
continue
#忽略數字
if re.match('(\d+)', s):
continue
if s in stop_words:
continue
if s in words_hash:
words_hash[s] += 1
else:
words_hash[s] = 1
- 計算 TF 與 IDF:
-
TF
該詞在該文章中出現的次數與所有詞的比例,所以出現愈多該數字就愈高;
-
IDF
IDF 則為所有文章數與該詞在有出現文章數的比例再取對數,所以出現愈多則值會愈小,在 SQL 的計算裡,利用分母加1的方式避免掉分母為0的錯誤
-
TF
log((select count(1) from articles f where f.fid_id = %s)/(1+count(c.sentence))) as IDF
-
TF-IDF
TF-IDF為將 TF * IDF 以修正得到一個權重數,因而該權重過濾掉常見的詞,保留重要的詞以識別該文章。
詳細的介紹可以參考維基百科的介紹:維基百科: TF-IDF
在這為了將 Bot 回答模型建置在 MySQL,直接透過 Update-Select 的方式來大量整批計算以控制時間讓4萬筆的語句在2分內處理完畢。
- Bot 機器人
在這將 Line 得到的語句分詞後(記住,分詞相當重要 ),一一比對儲存在資料庫的詞語,再將其權重加總取得最相關詞句回覆給主人。晚安,期待下次分享有趣的生活應用。