人工智慧演算法—決策樹
文/騰訊soso林世飛
決策樹方法最早產生於上世紀60年代,到70年代末。由J Ross Quinlan提出了ID3演算法,此演算法的目的在於減少樹的深度。但是忽略了葉子數目的研究。C4.5演算法在ID3演算法的基礎上進行了改進,對於預測變數的缺值處理、剪枝技術、派生規則等方面作了較大改進,既適合於分類問題,又適合於迴歸問題
這裡 介紹其基本原理 和一個實驗例子。
先介紹2個演算法:
演算法一:熵(entropy)
熵(entropy)指的是體系的混亂的程度,當我們嘗試把混合集合A={B1,B2,C1,C2…..} (其中Bx表示一個類別的元素,Cx
理解該公式:p(xi) 越平均,系統約混亂,如果系統只有2個元素x1、x2,x1出現概率是0.5,x2出現概率也是0.5,即p(x1) =0.5p(x2) =0.5 ,這時公式計算結果為1; p(xi)如果比較不平均,比如p(x2) =1,那就是系統很確定,一點都不混亂,肯定是x2構成,這時熵計算結果就是0.
這個規律剛剛好是 log 函式特點 過(1,0)這個點(見下圖),我想這個就是
用python 實現就是 :
def entropy(l):
from math import log
#函式程式設計語法,定義一個函式
log2=lambda x:log(x)/log(2)
total=len(l)
counts={}
#統計每個型別出現格式
for item in l:
counts.setdefault(item,0)
counts[item]+=1
ent=0
for i in counts:
p=float(counts[i])/total #
ent-=p*log2(p)#熵計算
return ent
演算法二:除了 熵,還有一個衡量一個集合是否混亂的方法叫 Gini Impurity (基尼不純度)方法。
公式如下:
公式基本上也符合以上 熵的 規律: 集合越純值越小,如果只有2個元素時候,每個元素出現概率就是0.5,這時 I = 0.5*0.5 +0.5*0.5 =0.5
0.5*0.5 # 我的理解是 K1(出現概率0.5) 被當做 其他Kx的概率(出現概率0.5)
Python 實現如下:
# 去重 統計每個出現次數
def uniquecounts(rows):
results={}
for row in rows:
# The result is the last column
r=row[len(row)-1]
if r not in results: results[r]=0
results[r]+=1
return results
def giniimpurity(rows):
total=len(rows)
counts=uniquecounts(rows)
imp=0
for k1 in counts:
# k1 的概率
p1=float(counts[k1])/total
for k2 in counts:
if k1==k2: continue
# k2 的概率
p2=float(counts[k2])/total
# 我的理解是 K1 被當做 其他Kx的概率
imp+=p1*p2
return imp
現在開始介紹決策樹:
決策樹樹節點定義:
class decisionnode:
def __init__(self,col=-1,value=None,results=None,tb=None,fb=None):
self.col=col #第幾個列 即因子
self.value=value #判斷值
self.results=results #結果集合
self.tb=tb #左右樹
self.fb=fb
#構建決策樹的過程,scoref 就是前面衡量 集合混亂 程度的2個演算法的函式之一
def buildtree(rows,scoref=entropy):
if len(rows)==0: return decisionnode()
current_score=scoref(rows)
# 最佳劃分
best_gain=0.0
best_criteria=None
best_sets=None
#列數
column_count=len(rows[0])-1
for col in range(0,column_count):
column_values={}
# 統計每一列可能的值
for row in rows:
column_values[row[col]]=1
#嘗試每一列 每一種值 作為劃分集合
for value in column_values.keys():
(set1,set2)=divideset(rows,col,value)
# Information gain 資訊增益??我的理解是加權計算目前的得分,即純度、混亂度
p=float(len(set1))/len(rows)
gain=current_score-p*scoref(set1)-(1-p)*scoref(set2)
if gain>best_gain and len(set1)>0 and len(set2)>0:
best_gain=gain
best_criteria=(col,value)
best_sets=(set1,set2)
# 建立子分支
if best_gain>0:
trueBranch=buildtree(best_sets[0])
falseBranch=buildtree(best_sets[1])
return decisionnode(col=best_criteria[0],value=best_criteria[1],
tb=trueBranch,fb=falseBranch)
else:
# 如果是葉子節點則統計這個分支的 個數
return decisionnode(results=uniquecounts(rows))
#根據某列值 劃分rows 為 2個 集合
# or nominal values
def divideset(rows,column,value):
# Make a function that tells us if a row is in
# the first group (true) or the second group (false)
split_function=None
if isinstance(value,int) or isinstance(value,float):
split_function=lambda row:row[column]>=value
else:
split_function=lambda row:row[column]==value
# Divide the rows into two sets and return them
set1=[row for row in rows if split_function(row)]
set2=[row for row in rows if not split_function(row)]
return (set1,set2)
#利用一個已知樹 決策過程
def classify(observation,tree):
if tree.results!=None:
return tree.results
else:
v=observation[tree.col]
branch=None
if isinstance(v,int) or isinstance(v,float):
if v>=tree.value: branch=tree.tb
else: branch=tree.fb
else:
if v==tree.value: branch=tree.tb
else: branch=tree.fb
return classify(observation,branch)
時間抽取是 web 頁面 分類、抽取時候一個很重要的 課題。通常一個頁面將包含多個可能代表 該頁面 發表時間的 字串,如果判斷一個 包含數字的字串是否是一個時間串 ,往往要考慮很多因素,比如 ,整個過程會比較繁瑣。
這裡嘗試利用1099 頁面 分析處理得到的162個時間串的各個屬性 ,利用決策樹進行學習,最終生成一個決策樹 ,該決策樹可以新的 時間串,根據其屬性進行 判斷。
以下是實驗效果:
其中每一列代表 其屬性值,比如第一列含義是該字串是否出現在 連結中,是為ture。
生成決策樹:
>>> datas=[ line.split('|')[1:] for line in file('result3') ]
>>> tree= treepredict.buildtree(datas)
對某個時間 2010-05-27 00:00:00 提取的各個特徵通過這個決策樹 判斷是否是時間
2010-05-27 00:00:00|false|false|false|false|true|false|false|false|8825|0.971809|2|8|0|false|false|0
結論是:不是時間
>>> treepredict.classify(['false', 'false', 'false', 'false', 'true', 'false', '
false', 'false', 'false', 'false', 'false', 'false', 'false', '0', '7754','249',
'0.967919', '0.031082', '0', '0', '0', '0', '0', '2', '-1', '0', '8', '0', '0',
'0'],tree)
{'0/n': 30}
我們可以檢視下 這個機器學習 產生的 決策樹:
區域性:
從上圖可以看到 8 、10、11 列 值對於該問題決策—該串是否是時間串 起著關鍵作用,雖然我們可能考慮很多因素、但以下幾列起著關鍵作用,具體含義是 塊開始 、 正文的位置關係 、字串長度等。
這個從實驗資料集來看也比較正常,因為這個資料集是我的實驗資料,很多列值沒有精確計算,基本雷同,變化不大。換句話說,對最後決策其作用都是那些 變化比較大的列項。
以上是關於決策樹原理實現和工程利用的一個例子的學習筆記,對於時間抽取是否適合利用決策樹來處理,目前還沒有定論和應用,這裡只是利用他來幫助我們理解 在眾多因素參與決策時候,哪些因素關鍵些,較好解釋了我們決策過程,每個因子起到作用,比如有的因子其實不起作用,至少在我們的資料集中。
決策樹在工程實際利用時候,可能 還要面臨 樹裁剪 (DecisionTree Pruning)、資料項某些維度資料缺少的問題。
什麼時候使用決策樹 ,本身就是一個問題。
更多內容參考