前言

本系列部落格文章將分享我在 Coursera 上台灣大學林軒田教授所教授的機器學習基石(Machine Learning Foundations)課程整理成的心得,並對照林教授的投影片作說明。若還沒有閱讀過 第二講 的碼農們,我建議可以先回頭去讀一下再回來喔!

第三講的內容偏向介紹各種機器學習方法,以前念論文的時候看到這些名詞都會覺得高深莫測,但其實這各式各樣的機器學習方法其實都是從最基礎的核心變化而來,所以不要被嚇到。了解各種機器學習方法的輸入輸出對於日後面對一些問題的時候,我們才能夠知道要挑選什麼機器學習方法來解決問題。

範例原始碼:FukuML - 簡單易用的機器學習套件

我在分享機器學習基石課程時,也跟著把每個介紹過的機器學習演算法都實作了一遍,原始碼都放在 GitHub 上了,所以大家可以去參考看看每個演算法的實作細節,看完原始碼會對課程中的數學式更容易理解。

如果大家對實作沒有興趣,只想知道怎麼使用機器學習演算法,那 FukuML 絕對會比起其他機器學習套件簡單易用,且方法及變數都會跟林軒田教授的課程類似,有看過課程的話,說不定連文件都不用看就會使用 FukuML 了。不過我還是有寫 Tutorial 啦,之後會不定期更新,讓大家可以容易上手比較重要!

熱身回顧一下

我們先來回顧一下上一講的內容,在上一講我們知道了如何使用 PLA 讓機器學會回答是非題這樣的兩類問題(Binary Classificaction),套到機器學習的那句名句,我們可以清楚的了解,PLA 這個演算法 A 觀察了線性可分(linear separable)的 D 及感知假設集合 H 去得到一個最好的假設 g,這一句話就可以概括到上一講的內容了。

從輸出 y 的角度看機器學習,y 只有兩個答案選一個,就叫 Binary Classification

接下來我們來了解一下各式各樣的學習方法,從輸出 y 的角度看機器學習,y 只有兩個答案選一個,就叫 Binary Classification,像是之前的是否發信用卡的例子就是 Binary Classification。

從輸出 y 的角度看機器學習,y 有多個答案選一個,就叫 Multiclass Classification

從輸出 y 的角度看機器學習,y 有多個答案選一個,就叫 Multiclass Classification,像是使用投飲機辨識錢幣的問題就是一個 Multiclass Classification 的問題,所以我們可以將分類問題推廣到分成 K 類,這樣 Binary Classificatin 就是一個 K=2 的分類問題。

從輸出 y 的角度看機器學習,y 為一個實數,就叫 Regression

從輸出 y 的角度看機器學習,y 為一個實數,就叫 Regression,像是要預估病人再過幾天病會好,這就需要用到 Regression,這也會用到許多統計學相關的工具。

從輸出 y 的角度看機器學習,y 為一個結構序列,就叫 Structured Learning

從輸出 y 的角度看機器學習,y 為一個結構序列,就叫 Structured Learning,比如一個句子的詞性分析,會需要考慮到句子中的前後文,而句子的組合可能有無限多種,因此不能單純用 Multiclass Classification 來做到,這就需要用到 Structured Learning 相關的機器學習方法。

從輸出 y 的角度看機器學習,做個小結

從輸出 y 的角度看機器學習,如果 y 是兩類,那就是 Binary Classification;如果 y 是 k 類,那就是 Multiclass Classification;如果 y 是一個實數,那就是 Regression;如果 y 是一種結構關係,那就是 Structured Learning。當然還有其他變化,不過基礎上就是 Binary Classification 及 Regression,我們可以透過這兩個基礎核心來延伸出其他機器學習方法。

從輸入的資料 Yn 的角度看機器學習,如果每個 Xn 都有明確對應的 Yn,這就叫監督式學習(Supervised Learning)

從輸入的資料 Yn 的角度看機器學習,如果每個 Xn 都有明確對應的 Yn,這就叫監督式學習(Supervised Learning),比如在訓練投飲機辨識錢幣的時候,我們很完整個告訴他什麼大小、什麼重量就是什麼幣值的錢幣,這樣就是一種監督式學習方法。

從輸入的資料 Yn 的角度看機器學習,如果每個 Xn 都沒有標示 Yn,這就叫非監督式學習(Unsupervised Learning)

從輸入的資料 Yn 的角度看機器學習,如果每個 Xn 都沒有標示 Yn,這就叫非監督式學習(Unsupervised Learning)。比如在訓練投飲機辨識錢幣的時候,我們只告訴投飲機錢幣的大小及重量,但不告訴他什麼大小及重量個錢幣是哪個幣值的錢幣,讓機器自己去觀察特徵將這些錢幣分成一群一群,這又叫做分群,這就是一種非監督式學習方法。

從輸入的資料 Yn 的角度看機器學習,如果 Xn 只有部分有標示 Yn,這就叫半監督式學習(Semi-supervised Learning)

從輸入的資料 Yn 的角度看機器學習,如果 Xn 只有部分有標示 Yn,這就叫半監督式學習(Semi-supervised Learning),有些資料較難取得的狀況下,我們會使用到半監度式學習,比如在預測藥物是否對病人有效時,由於做人體實驗成本高且可能要等一段時間來看藥效,這樣的情況下標示藥物有效或沒效的成本很高,所以就可能需要用到半監度式學習。

從輸入的資料 Yn 的角度看機器學習,如果 Yn 是很難確知描述的,只能在機器作出反應時使用處罰及獎勵的方式讓機器知道對或錯,這就叫增強式學習(Reinforcement Learning)

從輸入的資料 Yn 的角度看機器學習,如果 Yn 是很難確知描述的,只能在機器作出反應時使用處罰及獎勵的方式讓機器知道對或錯,這就叫增強式學習(Reinforcement Learning)。這樣的機器學習方式,比較像自然界生物的學習方式,就像你要教一隻狗坐下,你很難直接告訴他怎麼做,而是用獎勵或處罰的方式讓狗狗漸漸知道坐下是什麼。增強式學習也就是這樣的機器學習方法,透過一次一次經驗的累積讓機器能夠學習到一個技能。比如像是教機器學習下棋,我們也可以透過勝負讓機器漸漸學習到如何下棋會下得更好。

從輸入的資料 Yn 的角度看機器學習,做個小結

從輸入的資料 Yn 的角度看機器學習,如果明確告知每個 Yn,那就是監督式學習;如果沒有告知任何 Yn,那就是非監督式學習;如果只有部份 Yn 的資料,那就是半監督式學習;如果是用獎勵、處罰的方式來告知 Yn,那就是增強式學習。當然還有其他種機器學習方法,其中最重要的核心就是監督式學習方法。

從餵資料給機器的角度看機器學習,一次餵進全部資料,這就叫 Batch Learning

從餵資料給機器的角度看機器學習,一次餵進全部資料,這就叫 Batch Learning。監督式學習方法,可能也會常使用 Batch Learning 的方式為資料。

從餵資料給機器的角度看機器學習,可以再慢慢餵進新資料,這就叫 Online Learning

從餵資料給機器的角度看機器學習,可以再慢慢餵進新資料,這就叫 Online Learning。Batch Learging 訓練好的機器,就無法調整他的技巧,可能會有越來越不準的情況,所以 Online Learning 可以再慢慢調整、增進技巧。PLA 算法可以很容易應用在 Online Learning 上,增強式學習方法也常常是使用 Online Learning 的方式餵資料。

從餵資料給機器的角度看機器學習,機器可以問問題,然後從問題的答案再餵進資料,這就叫 Active Learning

從餵資料給機器的角度看機器學習,機器可以問問題,然後從問題的答案再餵進資料,這就叫 Active Learning。這樣的學習方法是要希望讓機器可以用一些策略問問題,然後慢慢學習、改善技巧。

從餵資料給機器的角度看機器學習,做個小結

從餵資料給機器的角度看機器學習,如果一次餵進所有資料,就叫 Batch Learning;如果後續可以再慢慢餵進資料,就叫 Online Learning;如果機器可以問問題來餵進資料,就叫 Active Learning。當然還有其他種機器學習方法,其中最重要的核心就是 Batch Learning。

從輸入 X 的角度看機器學習,如果 X 的特徵很明確定義,這就叫 Concrete Feature

從輸入 X 的角度看機器學習,如果 X 的特徵很明確定義,這就叫 Concrete Feature。Concrete Featrue 的取得通常需要人去介入,比如為何發不發信用卡要看申請者的年收入,這就是因為人們覺得年收入對於付不得付出卡費有關係。

從輸入 X 的角度看機器學習,如果 X 的特徵是用最基礎未人為整理過的,這就叫 Raw Feature

從輸入 X 的角度看機器學習,如果 X 的特徵是用最基礎未人為整理過的,這就叫 Raw Feature。比如聲音訊號的頻率,圖片的像素,這都是 Raw Feature。

從輸入 X 的角度看機器學習,如果 X 的特徵是抽象的像是編號這樣的資料,這就叫 Abstract Feature

從輸入 X 的角度看機器學習,如果 X 的特徵是抽象的像是編號這樣的資料,這就叫 Abstract Feature。這通常就需要有人去抽取出更具象的特徵資料出來,這些特徵可能包含 Concrete Feature 或 Raw Feature。

從輸入 X 的角度看機器學習,做個小結

從輸入 X 的角度看機器學習,如果 X 是明確定義的,那就是 Concrete Feature;如果 X 是未經人為定義過的,那就是 Raw Feature;如果 X 是抽象的編號,那就是 Abstract Feature。當然還有其他種特徵,其中最重要的核心就是 Concrete Feature。

總結

從輸出 y 的角度看機器學習、從輸入的資料 Yn 的角度看機器學習、從餵資料給機器的角度看機器學習、從輸入 X 的角度看機器學習都會有許多不同的機器學習方法,但重要的是了解哪些是核心,其他機器學習方法也都是從這些核心發展而來。

前言

本系列部落格文章將分享我在 Coursera 上台灣大學林軒田教授所教授的機器學習基石(Machine Learning Foundations)課程整理成的心得,並對照林教授的投影片作說明。若還沒有閱讀過 第一講 的碼農們,我建議可以先回頭去讀一下再回來喔!

範例原始碼:FukuML - 簡單易用的機器學習套件

我在分享機器學習基石課程時,也跟著把每個介紹過的機器學習演算法都實作了一遍,原始碼都放在 GitHub 上了,所以大家可以去參考看看每個演算法的實作細節,看完原始碼會對課程中的數學式更容易理解。

如果大家對實作沒有興趣,只想知道怎麼使用機器學習演算法,那 FukuML 絕對會比起其他機器學習套件簡單易用,且方法及變數都會跟林軒田教授的課程類似,有看過課程的話,說不定連文件都不用看就會使用 FukuML 了。不過我還是有寫 Tutorial 啦,之後會不定期更新,讓大家可以容易上手比較重要!

熱身回顧一下

在前一章我們基本上可以了解機器學習的架構大致上就是 *A takes D and H to get g*,也就是說我們會使用演算法來基於資料與假設集合計算出一個符合資料呈現結果的方程式 g,在這邊我們就會看到 H 會長什麼樣子,然後介紹 Perceptron Learning Algorithm(PLA)來讓機器學習如何回答是非題,比如讓機器回答銀行是否要發信用卡給申請人這樣的問題。

再看一次是否要發信用卡這個問題

是否要發信用卡這個問題我們可以想成它是一個方程式 f,而申請者的資料集合 X 丟進去就可以得到 Y 這些是否核發信用卡的記錄,我們現在不知道 f,將歷史資料 D 拿來當成訓練資料,其中每個 xi 就是申請者的資料,它會一個多維相向,比如第一個維度是年齡,第二個維度是性別…等等,然後我們會將這些資料 D 及假設集合 H 丟到機器學習演算法 A,最後算出一個最像 f 的 g,這個 g 其實就是從假設集合 H 挑出一個最好的假設的結果。

簡單的假設集合:感知器

要回答是否核發信用卡,可以用這樣簡單的想法來實現,現在我們知道申請者有很多基本資料,這些資料可以關係到是否核發信用卡,學術上就稱為是「特徵值」,這些特徵值有的重要、有的不重要,我們可以為這些特徵值依照重要性配上一個權重分數 wi,所以當這些分數加總起來之後,如果超過一個界線 threshold 時,我們就可以就可以決定核發信用卡,否則就不核發。這些 wi 及 threshold 就是所謂的假設集合,可以表示成如投影片中的線性方程式。

將假設集合的線性方程式整理一下

Threshold 我們也可以視為是一種加權分數,所以就可以將假設集合的線性方程式整理得更簡潔,整個線性方程式就變成了很簡易的兩個向量內積而已。

用二維空間來看看這個例子

假如現在申請者的只有兩個特徵值,那就可以用一個二維空間來標出每個申請者的位置,而是否核發信用卡,則用藍色圈圈來代表核發,紅色叉叉代表不核發,而假設 h 就是在這空間的一條線的法向量,可以將藍色圈圈跟紅色叉叉完美的分開來,這在機器學習上就是所謂的「分類」,Perceptrons 就是一種線性分類器。

怎麼從所有的假設中得到最好的假設 g

我們希望 g 可以跟 f 一樣完美的分類信用卡的核發與否,只要從 H 這個假設集合中挑到可以完美分類信用卡核發與否的線,我們就可以得到 g 了,但這很難,因為平面中可以有無限多條線,這樣算不完。所以我們改變想法,我們先隨便切一條線,然後如果有錯的地方,就修正這條線。

Perceptron Learning Algorithm 感知學習模型

剛剛這樣有錯就去修正的想法,就是感知學習模型(Perceptron Learning Algorithm)的核心思想,實際上我們怎麼修正呢?我們來仔細看一下。假設現在有一個點 x 分錯了,它實際是核發的點,但卻被分在不核發的那一邊,這就代表 wt 向量與 x 之間的夾角太大,那就要讓它們之間的夾角變小,我們可以很簡單的用向量相加的方式來做到。如果現在 x 分錯了,它實際是不核發,那就代表 wt 向量與 x 向量之間的夾角太小,那就要讓他們之間的夾角變大,我們可以用 wt 向量減掉 x 向量來做到。這樣的計算很容易可以用程式做到。PLA 也是一個最簡易的神經網路算法。

看看 PLA 演算法修正 h 的過程

PLA 的一些問題

PLA 這個演算法會一直修正 h 直到對所有的 D 都沒有錯誤時,就會停止。但真實世界的資料不會這麼完美,PLA 可能會有不會停止的情況發生,所以我們只能修正 PLA,只算出夠好的 h 就可以了。

什麼時候 PLA 不會停止

什麼時候 PLA 會停止,什麼時候不會停止?當資料集合 D 為線性可分的時候,PLA 就會停止,但如果不是線性可分的時候就不會停止。

處理雜訊

其實真實世界的資料就是這樣,充滿了雜訊,這些雜訊也有可能本身就是錯誤的資料,比如銀行一開始核發就是錯的,這也就是為何我們只要得到一個接近 f 的 g 就可以了,而不一定要得到完美的 f。

找出犯最少錯的線

既然真實世界的資料有雜訊,那我們就用程式找出犯最少錯的線吧!說起來簡單,做起來很難,這個問題其實是個 NP-hard 的問題。

Pocket Algorithm

所以折衷的方式就是找到夠好的線就好,我們修改一下 PLA,讓他每次計算時,如果得到更好的線,就先暫時存下來,然後算個幾百輪,我們就可以假設目前得到的線就是一個不錯的 h 了。

演算法原始碼

以上就是第二講的內容,這邊我找到了有人實作這兩個演算法的原始碼,讓大家可以參考一下。

Naive PLA

from numpy import *

def naive_pla(datas):
    w = datas[0][0]
    iteration = 0
    while True:
        iteration += 1
        false_data = 0

        for data in datas:
            t = dot(w, data[0])
            if sign(data[1]) != sign(t):
                error = data[1]
                false_data += 1
                w += error * data[0]
        print 'iter%d (%d / %d)' % (iteration, false_data, len(datas))
        if not false_data:
            break
    return w

Pocket PLA

import numpy as np

def pocket_pla(datas, limit):
    ###############
    def _calc_false(vec):
        res = 0
        for data in datas:
            t = np.dot(vec, data[0])
            if np.sign(data[1]) != np.sign(t):
                res += 1
        return res
    ###############
    w = np.random.rand(5)
    least_false = _calc_false(w)
    res = w

    for i in xrange(limit):
        data = random.choice(datas)
        t = np.dot(w, data[0])
        if np.sign(data[1]) != np.sign(t):
            t = w + data[1] * data[0]
            t_false = _calc_false(t)

            w = t

            if t_false <= least_false:
                least_false = t_false
                res = t
    return res, least_false

前言

機器學習(Machine Learning)是一門很深的課程,要直接跳進來學習其實並不容易,因此系統性由淺而深的學習過程還是必須的。這一系列部落格文章我將分享我在 Coursera 上臺灣大學林軒田教授所教授的機器學習基石(Machine Learning Foundations)課程整理成的心得,並對照林教授的投影片作說明,希望對有心學習 Machine Learning 的碼農們有些幫助。

範例原始碼:FukuML - 簡單易用的機器學習套件

我在分享機器學習基石課程時,也跟著把每個介紹過的機器學習演算法都實作了一遍,原始碼都放在 GitHub 上了,所以大家可以去參考看看每個演算法的實作細節,看完原始碼會對課程中的數學式更容易理解。

如果大家對實作沒有興趣,只想知道怎麼使用機器學習演算法,那 FukuML 絕對會比起其他機器學習套件簡單易用,且方法及變數都會跟林軒田教授的課程類似,有看過課程的話,說不定連文件都不用看就會使用 FukuML 了。不過我還是有寫 Tutorial 啦,之後會不定期更新,讓大家可以容易上手比較重要!

如何有效學習機器學習

從基礎來由淺入深,包含理論及實作技術用說故事的方式包裝,比如何時可以使用機器學習、為何機器可以學習、機器怎麼學習、如何讓機器學得更好,讓我們可以記得並加以應用。

從人的學習轉換到機器學習

人學習是為了習得一種技能,比如學習辨認男生或女生,而我們可以從觀察中累積經驗而學會辨認男生或女生,這就是人學習的過程,觀察 -> 累積經驗、學習 -> 習得技能;而機器怎麼學習呢?其實有點相似,機器為了學習一種技能,比如一樣是學習辨認男生或女生,電腦可以從觀察資料計算累積模型而學會辨認男生或女生,這就是機器學習的過程,資料 -> 計算、學習出模型 -> 習得技能。

再定義一下什麼是技能

「師爺,翻譯翻譯什麼是他媽的技能」「技能不就是技能嗎」在機器學習上,技能就是透過計算所搜集到的資料來提升一些可量測的性能,比如預測得更準確,實例上像是我們可以搜集股票的交易資料,然後透過機器學習的計算及預測後,是否可以得到更多的投資報酬。如果可以增加預測的準確度,那麼我們就可以說電腦透過機器學習得到了預測股票買賣的技能了。

舉個例子

各位勞苦功高的碼農們,現在老闆心血來潮要你寫一個可以辨識樹的圖片的程式,你會怎麼寫呢?你可能寫一個程式檢查圖片中有沒有綠綠的或是有沒有像葉子的形狀的部份等等,然後寫了幾百條規則來完成辨識樹的圖片的功能,現在功能上線了,好死不死現在來了一張樹的圖片上面剛好都沒有葉子,你寫的幾百條規則都沒用了,辨識樹的圖片的功能只能以失敗收場。機器學習可以解決這樣的問題,透過觀察資料的方式來讓電腦自己辨識樹的圖片,可能會比寫幾百條判斷規則更有效。這有點像是教電腦學會釣魚(透過觀察資料學習),而不是直接給電腦魚吃(直接寫規則給電腦)。

那麼什麼時候可以使用機器學習呢

從上個例子我們可以大概了解使用機器學習的使用時機,大致上如果觀察到現在你想要解決的問題有以下三個現象,應該就是機器學習上場的時刻了:

  1. 存在某種潛在規則
  2. 但沒有很辦法很簡單地用程式直接定義來作邏輯判斷(if else 就可以做到,就不用機器學習)
  3. 這些潛在規則有很多資料可以作為觀察、學習的來源

舉個實際的機器學習例子 1

Netflix 現在出了一個問題,如果你能讓使用者對電影喜好程度星級預測準確率提升 10%,那就可以獲得 100 萬美金,馬上讓你從碼農無產階級晉升到天龍人資產階級,而這個問題是這樣的:他們給了你大量使用者對一些電影的星級評分資料,你必須要讓電腦學到一個技能,這個技能可以預測到使用者對他還沒看過的電影評分會是多少星級,如果電腦能準確預測的話,那某種程度它就有了可以知道使用者會不會喜歡這些電影的技能,進而可以推薦使用者他們會喜歡的電影,讓他們從口袋裡拿錢過來~

舉個實際的機器學習例子 2

這邊偷偷告訴大家一個很常見的機器學習方法的模型,我們再來整理一下,其實這個問題可以轉化成這樣,使用者有很多個會喜歡這部電影的因素,比如電影中有沒有爆破場景、有沒有養眼畫面、有沒有外星人等等,這個我們就稱之為使用者的特徵值(feature),而電影本身也有很多因素,比如電影中有出現炸彈、是很有魅力的史嘉蕾·喬韓森所主演、片名是 ET 第二集等等,這個我們就稱之為電影的特徵值,我們把這兩個特徵值表示成向量(vector),如此如果使用者與電影特徵值有對應的特徵越多,那就代表使用者很有可能喜歡這部電影,而這可以很快地用向量內積的方式計算出來。也就是說,機器學習在這個問題上,只要能學習出這些會影響使用者喜好的因素也就是機器學習所說的特徵值會是什麼,那這樣當一部新的電影出來,我們只要叫電腦對一下這部新電影與使用者的特徵值的對應起來的向量內積值高不高就可以知道使用者會不會喜歡這部電影了~

將剛剛的問題用數學式來描述

我們在用銀行核發信用卡的例子來描述機器學習,我們可以把信用卡申請者的資料想成是 x,而 y 是銀行是否核發信用卡。所以這就是一個函式,它有一個潛在規則,可以讓 x 對應到 y,機器學習就是要算出這個 f 函式是什麼。現在我們有大量的信用卡對申請者核發信用卡的資料,就是 D,我們可以從資料觀察中得到一些假設,然後讓電腦去學習這些假設是對的還是錯的,慢慢習得技能,最後電腦可能會算出一個 g 函式,雖然不是完全跟 f 一樣,但跟 f 很像,所以能夠做出還蠻精確的預測。

機器學習流程

所以機器學習銀行是否核發信用卡的流程就像這樣,我們想要找到 target function,可以完整預測銀行對申請者是否要核發信用卡才會賺錢,這時我們會餵給電腦大量的資料,然後透過學習演算法找出重要的特徵值,這些重要的特徵值就可以組成函式 g,雖然跟 f 不一樣,但很接近。

機器學習的 Model

從上面的學習流程,我們可以知道最後電腦會學習出 g 可以辨認資料中較重要的特徵值,這些特徵值可能是我們一開始觀察資料所整理出來的假設,所以我們餵資料給電腦做學習演算法做計算時,也會餵一些假設進去,以銀行核發信用卡的例子就是這個申請者年薪是否有 80 萬、負債是否有 10 萬、工作是否小於兩年等等假設,這些假設就是 H,學習演算法再去計算實際資料與假設是否吻合,這個演算法就是 A,最後演算法會挑出最好的假設集合是哪些。 H 與 A 我們就稱為是機器學習 Model

機器學習的基本定義

機器學習的基本定義可以用這個圖來概括,用一句話來說的話就是「use data to compute hypothesis g that approximates target f」,你如果問我為何要用英文寫下這句話,其實只是因為這樣看起來比較像是一個偉人大學者寫的啊!拿來唬人用的!

前言

我們之前曾經介紹過 如何使用 CSS3 Animation,也不小心在該篇文章中說要另文跟大家介紹如何使用 CSS3 Transition,拖稿了近一年,今天終於要來實現諾言了~雖然大家可能根本就不在意,但哥就是真性情的人他媽的當真了啊!

在這個浮誇的時代,如果網頁上沒有酷炫的功能或特效,似乎就遜掉了(幹!開場跟如何使用 CSS3 Animation 這篇文章一模一樣,可以再混一點啊),好啦,不說廢話,總之就是網頁有使用到 CSS3 Transition 馬上就會讓你的網站帥十倍啦!很爽吧!(請注意:本人並不會因此帥十倍)

就讓我們一起來看看 CSS3 Transition 大法怎麼練吧!

CSS3 Transition 第一級

第一級讓我們先由簡單的範例從做中學,現在讓我們想像一個情境,我們希望滑鼠 hover 至某個 div 元素時,讓這個 div 元素改變背景色,若沒有用轉場(Transition)效果,我們就會看到 div 元素硬生生的改變顏色,一點都不溫柔,這樣橫衝直撞會讓 TA 很不舒服,所以我們才會需要 CSS3 Transition 來讓 TA 舒服一點。

div.example-no-transition {
    width: 580px;
    padding: 9px 15px;
    background-color: #FF5050;
    color: white;
    margin-bottom: 20px;
    margin-top: 20px;
    border-radius: 5px;
}
div.example-no-transition:hover {
    background-color: #6666FF;
}

這段 CSS 語法就是代表當滑鼠 hover 至 div.example-no-transition 元素時,背景顏色會變成 #6666FF,但就是很生硬的變過去,但當我們加入 transition 那就不一樣了。

div.example-with-transition {
    width: 580px;
    padding: 9px 15px;
    background-color: #FF5050;
    color: white;
    border-radius: 5px;
    -webkit-transition: background-color 1s;
    -moz-transition: background-color 1s;
    -o-transition: background-color 1s;
    -ms-transition: background-color 1s;
    transition: background-color 1s;
}
div.example-with-transition:hover {
    background-color: #6666FF;
}

這段 CSS 語法 transition 的部分就是說 div 元素要如何轉場,background-color 1s 的意思就是說 background-color 會在 1 秒的時間變化成 hover 所指定的背景色。

就是這麼簡單!

特別注意有 -webkit- 這個前綴的 CSS 語法是為了支援 webkit 核心的瀏覽器,例如:Chrome、Safari、Opera 等等。

CSS3 Transition 第一級展示

CSS3 Transition 第二級

CSS3 Transition 第一級使用的只是預設的轉場效果,總感覺缺少了點什麼,通常龜毛的人不會滿足於預設的效果,所以在 CSS3 Transition 第二級我們會學到如何調整 CSS3 Transition 的轉場效果。

<div id="example-transition">
  <div class="ease">ease</div>
  <div class="linear">linear</div>
  <div class="easein">ease-in</div>
  <div class="easeout">ease-out</div>
  <div class="easeinout">ease-in-out</div>
</div>
#example-transition {
  width: 520px;
}
#example-transition div {
  width: 100px;
  margin: 5px 0;
  padding: 5px;
  color: white;
  background-color: #FF5050;
  text-align: right;
  border-radius: 5px;
}
#example-transition:hover div {
  width: 500px;
}
#example-transition div.ease {
  -webkit-transition: 3s ease;
  -moz-transition: 3s ease;
  -o-transition: 3s ease;
  -ms-transition: 3s ease;
  transition: 3s ease;
}
#example-transition div.linear {
  -webkit-transition: 3s linear;
  -moz-transition: 3s linear;
  -o-transition: 3s linear;
  -ms-transition: 3s linear;
  transition: 3s linear;
}
#example-transition div.easein {
  -webkit-transition: 3s ease-in;
  -moz-transition: 3s ease-in;
  -o-transition: 3s ease-in;
  -ms-transition: 3s ease-in;
  transition: 3s ease-in;
}
#example-transition div.easeout {
  -webkit-transition: 3s ease-out;
  -moz-transition: 3s ease-out;
  -o-transition: 3s ease-out;
  -ms-transition: 3s ease-out;
  transition: 3s ease-out;
}
#example-transition div.easeinout {
  -webkit-transition: 3s ease-in-out;
  -moz-transition: 3s ease-in-out;
  -o-transition: 3s ease-in-out;
  -ms-transition: 3s ease-in-out;
  transition: 3s ease-in-out;
}

CSS3 Transition 讓我們可以使用 timing function 這個參數來調整轉場效果,我們在例子中將所以的 timing function easelinearease-inease-outease-in-out 一字排開,讓大家可以看清楚各種 timing function 有何異同,至於要使用哪個 timing function 就要看各位施主的 sense 了~

其中請特別注意,我們在這個例子中並沒有在 transition 裡說明哪個 CSS property 要做轉場效果,所以會使用預設模式來做轉場效果,預設模式其實就是 all,也就是說所有可以做轉場效果的 property 都會一起做變化,很方便吧!

CSS3 Transition 第二級展示

CSS3 Transition 第三級

CSS3 Transition 還有一個 delay 的參數可以調整,第三級裡面我們將介紹如何使用 CSS3 Transition 的 delay,這樣可以讓我們的轉場效果有更多的變化。

<div id="example-transition">
  <div class="ease">ease</div>
  <div class="linear">linear</div>
  <div class="easein">ease-in</div>
  <div class="easeout">ease-out</div>
  <div class="easeinout">ease-in-out</div>
</div>
#example-transition {
  width: 520px;
}
#example-transition div {
  width: 100px;
  margin: 5px 0;
  padding: 5px;
  color: white;
  background-color: #FF5050;
  text-align: right;
  border-radius: 5px;
}
#example-transition:hover div {
  width: 500px;
}
#example-transition div.ease {
  -webkit-transition: 1s ease;
  -moz-transition: 1s ease;
  -o-transition: 1s ease;
  -ms-transition: 1s ease;
  transition: 1s ease;
}
#example-transition div.linear {
  -webkit-transition: 1s linear 1s;
  -moz-transition: 1s linear 1s;
  -o-transition: 1s linear 1s;
  -ms-transition: 1s linear 1s;
  transition: 1s linear 1s;
}
#example-transition div.easein {
  -webkit-transition: 1s ease-in 2s;
  -moz-transition: 1s ease-in 2s;
  -o-transition: 1s ease-in 2s;
  -ms-transition: 1s ease-in 2s;
  transition: 1s ease-in 2s;
}
#example-transition div.easeout {
  -webkit-transition: 1s ease-out 3s;
  -moz-transition: 1s ease-out 3s;
  -o-transition: 1s ease-out 3s;
  -ms-transition: 1s ease-out 3s;
  transition: 1s ease-out 3s;
}
#example-transition div.easeinout {
  -webkit-transition: 1s ease-in-out 4s;
  -moz-transition: 1s ease-in-out 4s;
  -o-transition: 1s ease-in-out 4s;
  -ms-transition: 1s ease-in-out 4s;
  transition: 1s ease-in-out 4s;
}

其實我們就只是在 timing function 後面加了一個 delay 秒數而已,就可以做到一層一層的轉場變化效果,學會 CSS3 Transition 第三級之後我們就可以隱約看出 CSS3 Transition 的語法:

transition: property duration timing-function delay;

第一個值是指定哪個 property 要變化,可以使用 all,第二個值 duration 是說轉場效果會多久完成,第三個值 timing-function 是說要使用什麼轉場效果有 easelinearease-inease-outease-in-out 五種,第四個值 delay 是說明要延遲多久才開始轉場效果。

CSS3 Transition 第三級展示

CSS3 Transition 第四級

剛剛有說到 CSS3 Transition 可以指定 all property 進行轉場變化,其實並不是所有的 property 都可以進行轉場變化,可以進行轉場變化的 property 我們列成下表供大家參考。

Property Name Type
background-color color
background-image only gradients
background-position percentage, length
border-bottom-color color
border-bottom-width length
border-color color
border-left-color color
border-left-width length
border-right-color color
border-right-width length
border-spacing length
border-top-color color
border-top-width length
border-width length
bottom length, percentage
color color
crop rectangle
font-size length, percentage
font-weight number
grid-* various
height length, percentage
left length, percentage
letter-spacing length
line-height number, length, percentage
margin-bottom length
margin-left length
margin-right length
margin-top length
max-height length, percentage
max-width length, percentage
min-height length, percentage
min-width length, percentage
opacity number
outline-color color
outline-offset integer
outline-width length
padding-bottom length
padding-left length
padding-right length
padding-top length
right length, percentage
text-indent length, percentage
text-shadow shadow
top length, percentage
vertical-align keywords, length, percentage
visibility visibility
width length, percentage
word-spacing length, percentage
z-index integer
zoom number

比如我們現在希望 width 跟 backgournd-color 都可以進行轉場變化,就可以這樣寫:

<div id="example-transition">
  <div class="ease">ease</div>
  <div class="linear">linear</div>
  <div class="easein">ease-in</div>
  <div class="easeout">ease-out</div>
  <div class="easeinout">ease-in-out</div>
</div>
#example-transition {
  width: 520px;
}
#example-transition div {
  width: 100px;
  margin: 5px 0;
  padding: 5px;
  color: white;
  background-color: #FF5050;
  text-align: right;
  border-radius: 5px;
}
#example-transition:hover div {
  width: 500px;
  background-color: #000000;
}
#example-transition div.ease {
  -webkit-transition: 3s ease;
  -moz-transition: 3s ease;
  -o-transition: 3s ease;
  -ms-transition: 3s ease;
  transition: 3s ease;
}
#example-transition div.linear {
  -webkit-transition: 3s linear;
  -moz-transition: 3s linear;
  -o-transition: 3s linear;
  -ms-transition: 3s linear;
  transition: 3s linear;
}
#example-transition div.easein {
  -webkit-transition: 3s ease-in;
  -moz-transition: 3s ease-in;
  -o-transition: 3s ease-in;
  -ms-transition: 3s ease-in;
  transition: 3s ease-in;
}
#example-transition div.easeout {
  -webkit-transition: 3s ease-out;
  -moz-transition: 3s ease-out;
  -o-transition: 3s ease-out;
  -ms-transition: 3s ease-out;
  transition: 3s ease-out;
}
#example-transition div.easeinout {
  -webkit-transition: 3s ease-in-out;
  -moz-transition: 3s ease-in-out;
  -o-transition: 3s ease-in-out;
  -ms-transition: 3s ease-in-out;
  transition: 3s ease-in-out;
}

我們在 hover 時有兩個 property 不一樣,一個是 width: 500px;、一個是 background-color: #000000;,這兩個 property 都是屬於可以進行轉場效果的,因此這樣寫就會一起變化,很簡單吧!

CSS3 Transition 第四級展示

結語

我們已經練完了 CSS3 Transition 大法的前四級,其實只要學會這些技巧,大概就能做出不錯的特效,只是動畫如何安排才會吸引人就要看個人的 Sense 了,像我就沒有什麼 Sense~

或許可以去請教對動畫最有 Sense 的 Rice Tseng 公主!

結果跟 CSS3 Animation 那篇文章完全一模一樣!真的好混啊!哈哈哈!!!

當有一個程序需要不斷的偵測請求,我們通常需要背景執行一個程序,且不能讓程序關閉,比較正規的做法當然就是直接開一個伺服器服務來執行這個程序,但有時我們會不希望為了一個小程序而去開服務,這時可以用以下這個指令來讓系統背後執行一個程序:

$ nohup node server.js &

以上例子就會讓系統背後執行 node.js 的預設 server,即使關閉 terminal 也會持續執行,若想關閉,就需要用 kill 的方式來將程序關閉。

開服務時有時難免會遇到 Port 被占用的情況,這時就需要找出哪些 Process 占用了這個 Port,並強制關閉 Process,如此才能夠再度使用這個 Port。

假設現在 1337 Port 被占用了,我們可以使用以下指令找出占用 Port 的 Process:

$ lsof -i tcp:1337

// 輸出結果
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
php     26267 root    5u  IPv4 4542269      0t0  TCP *:1337 (LISTEN)
php     26267 root    7u  IPv4 4542295      0t0  TCP
php     26267 root    8u  IPv4 4542296      0t0  TCP

然後我們就可以使用 PID 來關閉 Process:

$ kill -9 26267

前言

自然語言處理的其中一個重要環節就是中文斷詞的處理,比起英文斷詞,中文斷詞在先天上就比較難處理,比如電腦要怎麼知道「全台大停電」要斷詞成「全台 / 大 / 停電」呢?如果是英文「Power outage all over Taiwan」,就可以直接用空白斷成「Power / outage / all / over / Taiwan」,可見中文斷詞真的是一個大問題啊~

這樣的問題其實已經有很多解法,比如中研院也有提供「中文斷詞系統」,但就是很難用,不僅 API Call 的次數有限制,還很難串,Server 也常常掛掉,真不曉得為何中研院不將核心開源出來,讓大家可以一起來改善這種現象,總之我要棄中研院的斷詞系統而去了。

近來玩了一下 jieba 結巴這個 Python Based 的開源中文斷詞程式,感覺大好,順手發了一些 pull request,今天早上就成為 contributor 了! 感覺真爽!每次發 pull request 總是有種莫名的爽感,既期待被 merge 又怕被 reject,就跟告白的感覺類似啊~

這麼好用的開源中文斷詞系統,當然要介紹給大家用啊!

背後演算法

jieba 中文斷詞所使用的演算法是基於 Trie Tree 結構去生成句子中中文字所有可能成詞的情況,然後使用動態規劃(Dynamic programming)算法來找出最大機率的路徑,這個路徑就是基於詞頻的最大斷詞結果。對於辨識新詞(字典詞庫中不存在的詞)則使用了 HMM 模型(Hidden Markov Model)及 Viterbi 算法來辨識出來。基本上這樣就可以完成具有斷詞功能的程式了,或許我之後可以找個時間寫幾篇部落格來介紹這幾個演算法。

如何安裝

推薦用 pip 安裝 jieba 套件,或者使用 Virtualenv 安裝(未來可能會介紹如何使用 Virtualevn,這樣就可以同時在一台機器上跑不同的 Python 環境):

pip install jieba

基本斷詞用法,使用預設詞庫

Sample Code:

jieba-default-mode.py

#encoding=utf-8
import jieba

sentence = "獨立音樂需要大家一起來推廣,歡迎加入我們的行列!"
print "Input:", sentence
words = jieba.cut(sentence, cut_all=False)
print "Output 精確模式 Full Mode:"
for word in words:
    print word

sentence = "独立音乐需要大家一起来推广,欢迎加入我们的行列!"
print "Input:", sentence
words = jieba.cut(sentence, cut_all=False)
print "Output 精確模式 Full Mode:"
for word in words:
    print word

得到的斷詞結果會是:

獨立 / 音樂 / 需要 / 大家 / 一起 / 來 / 推廣 / , / 歡迎 / 加入 / 我們 / 的 / 行列

独立 / 音乐 / 需要 / 大家 / 一 / 起来 / 推广 / , / 欢迎 / 加入 / 我们 / 的 / 行列

據原作者的說法,使用預設詞庫的話,繁體中文的斷詞結果應該會比較差,畢竟原來的詞庫是簡體中文,但在這個例子中,我感覺是繁體中文的斷詞結果比較好,這應該只是特例,我們接下來試試看中文歌詞的斷詞結果如何。

中文歌詞斷詞,使用預設詞庫

現在我們使用 回聲樂團 - 座右銘 的歌詞作為中文斷詞測試範例,歌詞我們先做成一個純文字檔,內容如下:

lyric.txt

我沒有心
我沒有真實的自我
我只有消瘦的臉孔
所謂軟弱
所謂的順從一向是我
的座右銘

而我
沒有那海洋的寬闊
我只要熱情的撫摸
所謂空洞
所謂不安全感是我
的墓誌銘

而你
是否和我一般怯懦
是否和我一般矯作
和我一般囉唆

而你
是否和我一般退縮
是否和我一般肌迫
一般地困惑

我沒有力
我沒有滿腔的熱火
我只有滿肚的如果
所謂勇氣
所謂的認同感是我
隨便說說

而你
是否和我一般怯懦
是否和我一般矯作
是否對你來說
只是一場遊戲
雖然沒有把握

而你
是否和我一般退縮
是否和我一般肌迫
是否對你來說
只是逼不得已
雖然沒有藉口

Sample Code:

jieba_cut_lyric.py

#encoding=utf-8
import jieba

content = open('lyric.txt', 'rb').read()

print "Input:", content

words = jieba.cut(content, cut_all=False)

print "Output 精確模式 Full Mode:"
for word in words:
    print word

得到的斷詞結果會是:

我 / 沒 / 有心 / 我 / 沒 / 有 / 真實 / 的 / 自我 / 我 / 只有 / 消瘦 / 的 / 臉孔 / 所謂 / 軟弱 / 所謂 / 的 / 順 / 從 / 一向 / 是 / 我 / 的 / 座 / 右銘 / 而 / 我 / 沒有 / 那 / 海洋 / 的 / 寬闊 / 我 / 只要 / 熱情 / 的 / 撫 / 摸 / 所謂 / 空洞 / / 所謂 / 不安全感 / 是 / 我 / 的 / 墓誌 / 銘 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 和 / 我 / 一般 / 囉 / 唆 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 一般 / 地 / 困惑 / 我 / 沒 / 有力 / 我 / 沒 / 有 / 滿腔 / 的 / 熱火 / 我 / 只有 / 滿肚 / 的 / 如果 / 所謂 / 勇氣 / 所謂 / 的 / 認 / 同感 / 是 / 我 / 隨便 / 說 / 說 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 是否 / 對 / 你 / 來 / 說 / 只是 / 一場 / 遊戲 / 雖然 / 沒 / 有把握 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 是否 / 對 / 你 / 來 / 說 / 只是 / 逼不得已 / 雖然 / 沒有 / 藉口

我們可以從結果看出斷詞已經開始出了一些問題,比如「座右銘」被斷成了「座 / 右銘」「墓誌銘」被斷成了「墓誌 / 銘」,這應該就是因為預設詞庫是簡體中文所造成,因此繁體中文的斷詞結果會比較差,還好 jieba 也提供了可以切換詞庫的功能,並提供了一個繁體中文詞庫,所以我們可以使用切換詞庫的功能來改善斷詞結果。

中文歌詞斷詞,使用繁體詞庫

Sample Code:

jieba_cut_lyric_zh.py

#encoding=utf-8
import jieba

jieba.set_dictionary('dict.txt.big')

content = open('lyric.txt', 'rb').read()

print "Input:", content

words = jieba.cut(content, cut_all=False)

print "Output 精確模式 Full Mode:"
for word in words:
    print word

我們在程式中多加一行 jieba.set_dictionary(‘dict.txt.big’),這樣就可以將斷詞詞庫切換到 dic.txt.big 這個檔案。

得到的斷詞結果會是:

我 / 沒有 / 心 / 我 / 沒有 / 真實 / 的 / 自我 / 我 / 只有 / 消瘦 / 的 / 臉孔 / 所謂 / 軟弱 / 所謂 / 的 / 順從 / 一向 / 是 / 我 / 的 / 座右銘 / 而 / 我 / 沒有 / 那 / 海洋 / 的 / 寬闊 / 我 / 只要 / 熱情 / 的 / 撫摸 / 所謂 / 空洞 / 所謂 / 不安全感 / 是 / 我 / 的 / 墓誌銘 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 和 / 我 / 一般 / 囉唆 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 一般 / 地 / 困惑 / 我 / 沒有 / 力 / 我 / 沒有 / 滿腔 / 的 / 熱火 / 我 / 只有 / 滿肚 / 的 / 如果 / 所謂 / 勇氣 / 所謂 / 的 / 認同感 / 是 / 我 / 隨便說說 / 而 / 你 / 是否 / 和 / 我 / 一般 / 怯懦 / 是否 / 和 / 我 / 一般 / 矯作 / 是否 / 對 / 你 / 來說 / 只是 / 一場 / 遊戲 / 雖然 / 沒有 / 把握 / 而 / 你 / 是否 / 和 / 我 / 一般 / 退縮 / 是否 / 和 / 我 / 一般 / 肌迫 / 是否 / 對 / 你 / 來說 / 只是 / 逼不得已 / 雖然 / 沒有 / 藉口

我們可以看到「座右銘」成功斷成「座右銘」了!「墓誌銘」也成功斷成「墓誌銘」了!果然切換成繁體中文詞庫還是有用的!

台語歌詞斷詞,使用繁體詞庫

既然中文歌詞斷詞能夠得到不錯的斷詞結果了,那我們來試試看台語歌詞斷詞會是如何?在這邊我們使用 滅火器 - 島嶼天光 的歌詞作為台語斷詞測試範例,歌詞我們先做成一個純文字檔,內容如下:

lyric_tw.txt

親愛的媽媽
請你毋通煩惱我
原諒我
行袂開跤
我欲去對抗袂當原諒的人

歹勢啦
愛人啊
袂當陪你去看電影
原諒我
行袂開跤
我欲去對抗欺負咱的人

天色漸漸光
遮有一陣人
為了守護咱的夢
成做更加勇敢的人

天色漸漸光
已經不再驚惶
現在就是彼一工
換阮做守護恁的人

已經袂記
是第幾工
請毋通煩惱我
因為阮知道
無行過寒冬
袂有花開的一工

天色漸漸光
天色漸漸光
已經是更加勇敢的人

天色漸漸光
咱就大聲來唱著歌
一直到希望的光線
照光島嶼每一個人

天色漸漸光
咱就大聲來唱著歌
日頭一爬上山
就會使轉去啦
現在是彼一工
勇敢的台灣人

Sample Code:

jieba_cut_lyric_zh_tw.py

#encoding=utf-8
import jieba

jieba.set_dictionary('dict.txt.big')

content = open('lyric_tw.txt', 'rb').read()

print "Input:", content

words = jieba.cut(content, cut_all=False)

print "Output 精確模式 Full Mode:"
for word in words:
    print word

得到的斷詞結果會是:

親愛 / 的 / 媽媽 / 請 / 你 / 毋通 / 煩惱 / 我 / 原諒 / 我 / 行袂 / 開跤 / 我 / 欲 / 去 / 對抗 / 袂 / 當 / 原諒 / 的 / 人 / 歹勢 / 啦 / 愛人 / 啊 / 袂 / 當 / 陪你去 / 看 / 電影 / 原諒 / 我 / 行袂 / 開跤 / 我 / 欲 / 去 / 對抗 / 欺負 / 咱 / 的 / 人 / 天色 / 漸漸 / 光 / 遮有 / 一陣 / 人 / 為 / 了 / 守護 / 咱 / 的 / 夢 / 成 / 做 / 更加 / 勇敢的人 / 天色 / 漸漸 / 光 / 已經 / 不再 / 驚惶 / 現在 / 就是 / 彼一工 / 換阮 / 做 / 守護 / 恁 / 的 / 人 / 已經 / 袂 / 記 / 是 / 第幾 / 工 / 請 / 毋通 / 煩惱 / 我 / 因為 / 阮 / 知道 / 無行過 / 寒冬 / 袂 / 有 / 花開 / 的 / 一工 / 天色 / 漸漸 / 光 / 天色 / 漸漸 / 光 / 已經 / 是 / 更加 / 勇敢的人 / 天色 / 漸漸 / 光 / 咱 / 就 / 大聲 / 來 / 唱 / 著歌 / 一直 / 到 / 希望 / 的 / 光線 / 照光 / 島嶼 / 每 / 一個 / 人 / 天色 / 漸漸 / 光 / 咱 / 就 / 大聲 / 來 / 唱 / 著歌 / 日頭 / 一爬 / 上山 / 就 / 會 / 使 / 轉去 / 啦 / 現在 / 是 / 彼 / 一工 / 勇敢 / 的 / 台灣 / 人

原本猜想結果應該會蠻差的,畢竟詞庫中沒有台語的用詞,但是因為 HMM 的關係猜出了一些新詞,讓我們還是得到不錯的結果,「袂當」斷成了「袂」「當」「袂記」斷成了「袂」「記」「袂有」斷成了「袂」「有」等等,我們要如何改善這些結果呢?

jieba 提供了一個功能讓使用者可以增加自定義詞庫,這種無法用 HMM 判斷出來的新詞就可以得到改善,我們就來試試看吧!

台語歌詞斷詞,使用繁體詞庫加自定義詞庫

首先我們新增一個純文字檔建立自定義詞庫,格式如下:

userdict.txt

行袂開跤 2 v
袂當 4 d
袂記 4 v
袂有 4 d
唱著 4 v
每一個 4 m
會使 70 d

其中每一行代表一筆語料資料,首先填上自定義詞如:「袂當」「袂記」,然後填上權重,權重值可以依照斷詞結果做自己想做的調整,最後填上詞性,但詞性非必要填寫,詞性列表可以參考 词性对照说明.中科院版本

Sample Code:

jieba_cut_lyric_zh_tw_custom.py

#encoding=utf-8
import jieba

jieba.set_dictionary('dict.txt.big')
jieba.load_userdict("userdict.txt")

content = open('lyric_tw.txt', 'rb').read()

print "Input:", content

words = jieba.cut(content, cut_all=False)

print "Output 精確模式 Full Mode:"
for word in words:
    print word

我們在程式中多加一行 jieba.load_userdict(“userdict.txt”),這樣就可以將自定義詞庫加進來了,超級簡單的。

得到的斷詞結果會是:

親愛 / 的 / 媽媽 / 請 / 你 / 毋通 / 煩惱 / 我 / 原諒 / 我 / 行袂開跤 / 我 / 欲 / 去 / 對抗 / 袂當 / 原諒 / 的 / 人 / 歹勢 / 啦 / 愛人 / 啊 / 袂當 / 陪你去 / 看 / 電影 / 原諒 / 我 / 行袂開跤 / 我 / 欲 / 去 / 對抗 / 欺負 / 咱 / 的 / 人 / 天色 / 漸漸 / 光 / 遮有 / 一陣 / 人 / 為 / 了 / 守護 / 咱 / 的 / 夢 / 成 / 做 / 更加 / 勇敢的人 / 天色 / 漸漸 / 光 / 已經 / 不再 / 驚惶 / 現在 / 就是 / 彼一工 / 換阮 / 做 / 守護 / 恁 / 的 / 人 / 已經 / 袂記 / 是 / 第幾 / 工 / 請 / 毋通 / 煩惱 / 我 / 因為 / 阮 / 知道 / 無行過 / 寒冬 / 袂有 / 花開 / 的 / 一工 / 天色 / 漸漸 / 光 / 天色 / 漸漸 / 光 / 已經 / 是 / 更加 / 勇敢的人 / 天色 / 漸漸 / 光 / 咱 / 就 / 大聲 / 來 / 唱著 / 歌 / 一直 / 到 / 希望 / 的 / 光線 / 照光 / 島嶼 / 每 / 一個 / 人 / 天色 / 漸漸 / 光 / 咱 / 就 / 大聲 / 來 / 唱著 / 歌 / 日頭 / 一爬 / 上山 / 就 / 會使 / 轉去 / 啦 / 現在 / 是 / 彼 / 一工 / 勇敢 / 的 / 台灣 / 人

完美!

取出斷詞詞性

大部份的斷詞系統都可以列出斷詞的詞性,jieba 也有這個功能,但結果可能不是那麼好,這其實是跟所使用的語料庫有關係,不過既然是 Open Source,希望未來能有語言學家可以加入,讓 jieba 可以得到更好的效果。

Sample Code:

jieba_cut_lyric_zh_flag.py

#encoding=utf-8
import jieba
import jieba.posseg as pseg

jieba.set_dictionary('dict.txt.big')

content = open('lyric.txt', 'rb').read()

print "Input:", content

words = pseg.cut(content)

print "Output 精確模式 Full Mode:"
for word in words:
    print word.word, word.flag

得到的結果會是:

我 r
沒有 x
心 n

我 r
沒有 x
真實 x
的 uj
自我 r

...

取出斷詞位置

有時我們會需要得到斷詞在文章中的位置:

Sample Code:

jieba_cut_lyric_zh_tokenize.py

#encoding=utf-8
import jieba

jieba.set_dictionary('dict.txt.big')

content = open('lyric.txt', 'rb').read()

print "Input:", content

words = jieba.tokenize(unicode(content, 'utf-8'))

print "Output 精確模式 Full Mode:"
for tk in words:
    print "word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2])

得到的結果會是:

word 我 start: 0 end:1
word 沒有 start: 1 end:3
word 心 start: 3 end:4
word start: 4 end:5
word 我 start: 5 end:6
word 沒有 start: 6 end:8
word 真實 start: 8 end:10
word 的 start: 10 end:11
word 自我 start: 11 end:13

...

取出文章中的關鍵詞

jieba 使用了 tf-idf 方法來實作萃取出文章中關鍵詞的功能:

Sample Code:

jieba_cut_lyric_zh_keyword.py

#encoding=utf-8
import jieba
import jieba.analyse

jieba.set_dictionary('dict.txt.big')

content = open('lyric.txt', 'rb').read()

print "Input:", content

tags = jieba.analyse.extract_tags(content, 10)

print "Output:"
print ",".join(tags)

程式中的 jieba.analyse.extract_tags(content, 10),就是告訴 jieba 我們要從這個文章中取出前 10 個 tf-idf 值最大的關鍵詞。

得到的結果會是:

沒有,所謂,是否,一般,雖然,退縮,肌迫,矯作,來說,怯懦

一開始使用這個功能的時候,會不知道 jieba 的 idf 值是從哪裡來的,看了一下 souce code 才知道原來 jieba 有提供一個 idf 的語料庫,但在實務上每個人所使用的語料庫可能會不太一樣,有時我們會想要使用自己的idf 語料庫,stop words 的語料庫也可能會想換成自己的,比如目前的結果中,最重要的「座右銘」並沒有出現在關鍵詞裡,我就會想要將「座右銘」加到 idf 語料庫,並讓 idf 值高一點,而「沒有」這個關鍵詞對我來說是沒有用的,我就會想把它加到 stop words 語料庫,這樣「沒有」就不會出現在關鍵詞裡。

可惜目前 pip 安裝的 jieba 版本並不能切換 idf 及 stop words 語料庫,所以我才會修改了一下 jieba,讓它可以支援 idf 及 stop words 語料庫的切換,目前在 github 上的版本已經可以支援 idf 及 stop words 切換的功能了!

結語

使用了 jieba 之後,其實有蠻深的感嘆,其實中研院的斷詞核心必非不好,想要收費也不是問題,但是 API 做得這麼差,根本就沒人有信心敢花錢下去使用這樣不可靠的系統,目前又有 jieba 這樣的 open source project,中研院的斷詞系統前途堪慮啊!

後記 2017/07/18

我後來有好幾次受邀演講關於中文斷詞的講題,相關的投影片都有分享在網路上了,大家也可以交叉參考:中文斷詞:斷句不要悲劇 / Head first Chinese text segmentation 投影片範例程式碼

Fukuball

我是林志傑,網路上常用的名字是 Fukuball。我使用 PHP 及 Python,對機器學習及區塊鏈技術感到興趣。 https://www.fukuball.com

Co-Founder / Head of Engineering at OurSong

Taipei, Taiwan