決策樹學習之概念理解和代碼實現

前言:
在學習《python數據挖掘入門與實踐》的決策樹球隊預測後,爲了更好的瞭解決策樹學習,我又閱讀了李航老師的《統計學習方法》決策樹章節內容。這本書被許多大神極力推薦,我在閱讀後也發現確實不負盛名。我將在這做個小結,希望能夠起到引導作用。

什麼是決策樹?
決策樹是一種基本的分類和迴歸方法,這裏主要討論分類決策樹。舉個例子,你和一個女生能不能在一起是個分類問題,它包括能在一起與不能在一起。這裏有兩個特徵,你喜歡她,她喜歡你。這兩個特徵都有兩個值喜歡與不喜歡。
它的本質是從訓練數據集中歸納出一組分類規則。他不斷地選擇最優特徵,並根據該特徵對數據集進行分割,使得數據集在原有基礎上有一個最好的分類。
這裏寫圖片描述

決策樹學習分爲幾個步驟?
決策樹學習分爲特徵選擇,決策樹的生成和決策樹的剪枝三個步驟。算法實現主要有ID3、C4.5和CART。

一組數據集有多少決策樹?
從另一個角度看,決策樹學習是由訓練數據集估計條件概率模型,基於特徵空間劃分的類的條件概率模型有無數個。我們選擇的標準是:該決策樹對訓練數據集有很好的擬合,而且它要對未知數據有很好的預測。

怎麼選擇特徵?
特徵選擇的準則通常是考慮信息增益或信息增益比,例如上面例子,你喜歡她,她喜歡你兩個特徵哪個特徵更能決定在不在一起。信息增益或者信息增益比就是決定的度量。公式將在副文實現。

怎麼生成決策樹?
決策樹的生成算法有ID3,C4.5和CART。ID3的核心是在各個結點應用信息增益選擇特徵,遞歸的構建決策樹。而C4.5是ID3的改進,它應用信息增益比。CART算法生成決策樹就是遞歸的構建二叉決策樹的過程。

爲什麼要進行剪枝?
決策樹生成算法依賴於訓練數據集,對於訓練數據集會有很好的分類,但是對於未知的測試數據卻不盡人意,這是過擬合現象。簡而言之就是你構建的決策樹太複雜啦,細分的過分。

怎麼進行決策樹剪枝?
在決策樹學習中將已生成的樹進行簡化的過程就叫剪枝。決策樹的剪枝往往通過極小化決策樹整體的損失函數來實現。剪枝算法不盡相同,同樣我會在副文實現一部分。

代碼:
在學完《統計學習方法》決策樹部分後,我實現了書上的一些公式。當然,我希望你在實現這些代碼前要先看書瞭解內容。

'''
本文件用來算法實現,傳入參數即可計算
'''

#1.決策樹特徵選擇準則之經驗熵
from collections import defaultdict
def get_entropy(dataset):
'''
dataset是dataframe數據集
'''

lable_count = defaultdict(int)#儲存某個離散隨機變量X(類別)的頻數
num_lables = 0
for index,row in dataset.iterrows():
current_lable = row[df.columns[-1]]#取最後一列的
lable_count[current_lable] += 1
num_lables += 1
#返回熵只依賴於X的分佈,熵越大,隨機變量的不確定性越大
base_entropy = sum([-lable_count[key]/num_lables*log(lable_count[key]/num_lables,2) for key in lable_count])
return base_entropy
#2.決策樹特徵選擇準則之經驗條件熵
def get_conditional_entropy(dataset,feature,feat_value_list):
'''
feature是所選特徵
feat_value_list是該特徵的數值列表
'''

#按所取特徵的值將數據集分開,分爲各個dataset
condition_ent = 0.0
for value in feat_value_list:
copy_dataset = dataset.copy()#複製一個dataset
#下面返回feature列中其值爲value的所有行
current_dataset = copy_dataset[copy_dataset[feature].isin(value)]
prob = len(current_dataset) / float(len(dataset))#極大似然估計概率
condition_ent += prob * get_entropy(current_dataset)#條件熵計算
return condition_ent
#3.決策樹特徵選擇準則之計算信息增益
def get_information_gain(dataset,feature):
base_entropy = get_entropy(dataset)
feat_value_list = [row[feature] for row in dataset]
unique_values = set(feat_value_list)#轉換成集合消除同值
condition_entropy = get_conditional_entropy(dataset,feature,unique_values)
information_gain = base_entropy - condition_entropy
return information_gain
#4.決策樹特徵選擇準則之計算信息增益比
def get_inforgain_ratio(dataset,feature):
information_gain_radio = get_information_gain(dataset,feature) / get_entropy(dataset)
return information_gain_radio

最後:
如果你要學習怎麼用決策樹,可以閱讀《python數據挖掘入門與實踐》決策樹部分。數據集在上篇博客以下是示例代碼:

import pandas as pd
import numpy as np
import os
filename = 'D:\\Python\\PythonProject\\nba_decisiontree_test\\matches.csv'
dataset = pd.read_csv(filename)
#數據清洗
del dataset['Unnamed: 0']
del dataset['1']
del dataset['8']
dataset.columns = ['Visitor Team','VisitorPts','Home Team','HomePts','Ccore Type','OT?','Notes']
#構造新特徵
dataset['HomeWin'] = dataset['VisitorPts'] < dataset['HomePts']
y_true = dataset['HomeWin'].values#y_true列表存儲賽況結果(輸贏類別)
from collections import defaultdict
won_last = defaultdict(int)#創建默認字典,默認值爲0,即失敗
#dataframe增加新列
dataset['HomeLastWin'] = ''
dataset['VisitorLastWin'] = ''
for index,row in dataset.iterrows():
home_team = row['Home Team']
visitor_team = row['Visitor Team']
row['HomeLastWin'] = won_last[home_team]
row['VisitorLastWin'] = won_last[visitor_team]#先儲存爲0
dataset.ix[index] = row#立馬更新進dataframe
won_last[home_team] = row['HomeWin']#在字典內存儲這一次循環到的賽況,下一次循環再更新
won_last[visitor_team] = not row['HomeWin']
#使用決策樹
from sklearn.tree import DecisionTreeClassifier
from sklearn.cross_validation import cross_val_score
clf = DecisionTreeClassifier(random_state=14)
X_previouswins = dataset[['HomeLastWin','VisitorLastWin']].values
scores = cross_val_score(clf,X_previouswins,y_true,scoring='accuracy')
print('Accuracy:{0:.1f}%'.format(np.mean(scores)*100))
#創建不同的特徵
data_folder = 'D:\\Python\\PythonProject\\nba_decisiontree_test'
standing_filename = os.path.join(data_folder,'standing.csv')
standings = pd.read_csv(standing_filename)
standings.columns = ['Rk','Team','Overall','Home','Road','E','W','A','C','SE','NW','P',
'SW','Pre','Post','≤3','≥10','Oct','Nov','Dec','Jan','Feb','Mar','Apr']
dataset['HomeTeamRanksHigher'] = 0
for index,row in dataset.iterrows():
home_team = row['Home Team']
visitor_team = row['Visitor Team']
if home_team == 'New Orleans Pelicans':
home_team = 'New Orleans Hornets'
if visitor_team == 'New Orleans Pelicans':
visitor_team = 'New Orleans Hornets'
#standings[standings['Team'] == home_team]返回home_team在standings的行
home_rank = standings[standings['Team'] == home_team]['Rk'].values
visitor_rank = standings[standings['Team'] == visitor_team]['Rk'].values
row['HomeTeamRanksHigher'] = int(home_rank > visitor_rank)
dataset.ix[index] = row
X_homehigher = dataset[['HomeLastWin','VisitorLastWin','HomeTeamRanksHigher']].values
clf = DecisionTreeClassifier(random_state=14)
scores = cross_val_score(clf,X_homehigher,y_true,scoring='accuracy')
print('Accuracy:{0:.1f}%'.format(np.mean(scores)*100))
#再次增加新特徵(上一場對戰勝負)
last_match_winner = defaultdict(int)
dataset['HomeTeamWinLast'] = 0
for index,row in dataset.iterrows():
home_team = row['Home Team']
visitor_team = row['Visitor Team']
teams = tuple(sorted([home_team,visitor_team]))#排序,確保兩支球隊無論主客場作戰,都使用相同的鍵
row['HomeTeamWinLast'] = 1 if last_match_winner[teams] == row['Home Team'] else 0
dataset.ix[index] = row
winner = row['Home Team'] if row['HomeWin'] else row['Visitor Team']
last_match_winner[teams] = winner
X_lastwinner = dataset[['HomeTeamRanksHigher','HomeTeamWinLast']].values
clf = DecisionTreeClassifier(random_state=14)
scores = cross_val_score(clf,X_lastwinner,y_true,scoring='accuracy')
print('Accuracy:{0:.1f}%'.format(np.mean(scores)*100))

———關注我的公衆號,一起學數據挖掘————
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章