python實現連續變量最優分箱詳解--CART算法

今天小編就爲大家分享一篇python實現連續變量最優分箱詳解–CART算法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
關於變量分箱主要分爲兩大類:有監督型和無監督型

對應的分箱方法:

A. 無監督:(1) 等寬 (2) 等頻 (3) 聚類

B. 有監督:(1) 卡方分箱法(ChiMerge) (2) ID3、C4.5、CART等單變量決策樹算法 (3) 信用評分建模的IV最大化分箱 等

本篇使用python,基於CART算法對連續變量進行最優分箱

由於CART是決策樹分類算法,所以相當於是單變量決策樹分類。

簡單介紹下理論:

CART是二叉樹,每次僅進行二元分類,對於連續性變量,方法是依次計算相鄰兩元素值的中位數,將數據集一分爲二,計算該點作爲切割點時的基尼值較分割前的基尼值下降程度,每次切分時,選擇基尼下降程度最大的點爲最優切分點,再將切分後的數據集按同樣原則切分,直至終止條件爲止。

關於CART分類的終止條件:視實際情況而定,我的案例設置爲 a.每個葉子節點的樣本量>=總樣本量的5% b.內部節點再劃分所需的最小樣本數>=總樣本量的10%

python代碼實現:

import pandas as pd
import numpy as np
  
#讀取數據集,至少包含變量和target兩列
sample_set = pd.read_excel('/數據樣本.xlsx')
  
def calc_score_median(sample_set, var):
  '''
  計算相鄰評分的中位數,以便進行決策樹二元切分
  param sample_set: 待切分樣本
  param var: 分割變量名稱
  '''
  var_list = list(np.unique(sample_set[var]))
  var_median_list = []
  for i in range(len(var_list) -1):
    var_median = (var_list[i] + var_list[i+1]) / 2
    var_median_list.append(var_median)
  return var_median_list

var表示需要進行分箱的變量名,返回一個樣本變量中位數的list

def choose_best_split(sample_set, var, min_sample):
  '''
  使用CART分類決策樹選擇最好的樣本切分點
  返回切分點
  param sample_set: 待切分樣本
  param var: 分割變量名稱
  param min_sample: 待切分樣本的最小樣本量(限制條件)
  '''
  # 根據樣本評分計算相鄰不同分數的中間值
  score_median_list = calc_score_median(sample_set, var)
  median_len = len(score_median_list)
  sample_cnt = sample_set.shape[0]
  sample1_cnt = sum(sample_set['target'])
  sample0_cnt = sample_cnt- sample1_cnt
  Gini = 1 - np.square(sample1_cnt / sample_cnt) - np.square(sample0_cnt / sample_cnt)
   
  bestGini = 0.0; bestSplit_point = 0.0; bestSplit_position = 0.0
  for i in range(median_len):
    left = sample_set[sample_set[var] < score_median_list[i]]
    right = sample_set[sample_set[var] > score_median_list[i]]
     
    left_cnt = left.shape[0]; right_cnt = right.shape[0]
    left1_cnt = sum(left['target']); right1_cnt = sum(right['target'])
    left0_cnt = left_cnt - left1_cnt; right0_cnt = right_cnt - right1_cnt
    left_ratio = left_cnt / sample_cnt; right_ratio = right_cnt / sample_cnt
     
    if left_cnt < min_sample or right_cnt < min_sample:
      continue
     
    Gini_left = 1 - np.square(left1_cnt / left_cnt) - np.square(left0_cnt / left_cnt)
    Gini_right = 1 - np.square(right1_cnt / right_cnt) - np.square(right0_cnt / right_cnt)
    Gini_temp = Gini - (left_ratio * Gini_left + right_ratio * Gini_right)
    if Gini_temp > bestGini:
      bestGini = Gini_temp; bestSplit_point = score_median_list[i]
      if median_len > 1:
        bestSplit_position = i / (median_len - 1)
      else:
        bestSplit_position = i / median_len
    else:
      continue
         
  Gini = Gini - bestGini
  return bestSplit_point, bestSplit_position

min_sample 參數爲最小葉子節點的樣本閾值,如果小於該閾值則不進行切分,如前面所述設置爲整體樣本量的5%

返回的結果我這裏只返回了最優分割點,如果需要返回其他的比如GINI值,可以自行添加。

def bining_data_split(sample_set, var, min_sample, split_list):
  '''
  劃分數據找到最優分割點list
  param sample_set: 待切分樣本
  param var: 分割變量名稱
  param min_sample: 待切分樣本的最小樣本量(限制條件)
  param split_list: 最優分割點list
  '''
  split, position = choose_best_split(sample_set, var, min_sample)
  if split != 0.0:
    split_list.append(split)
  # 根據分割點劃分數據集,繼續進行劃分
  sample_set_left = sample_set[sample_set[var] < split]
  sample_set_right = sample_set[sample_set[var] > split]
  # 如果左子樹樣本量超過2倍最小樣本量,且分割點不是第一個分割點,則切分左子樹
  if len(sample_set_left) >= min_sample * 2 and position not in [0.0, 1.0]:
    bining_data_split(sample_set_left, var, min_sample, split_list)
  else:
    None
  # 如果右子樹樣本量超過2倍最小樣本量,且分割點不是最後一個分割點,則切分右子樹
  if len(sample_set_right) >= min_sample * 2 and position not in [0.0, 1.0]:
    bining_data_split(sample_set_right, var, min_sample, split_list)
  else:
    None

split_list 參數是用來保存返回的切分點,每次切分後返回的切分點存入該list

在這裏判斷切分點分割的左子樹和右子樹是否滿足“內部節點再劃分所需的最小樣本數>=總樣本量的10%”的條件,如果滿足則進行遞歸調用。

def get_bestsplit_list(sample_set, var):
  '''
  根據分箱得到最優分割點list
  param sample_set: 待切分樣本
  param var: 分割變量名稱
  '''
  # 計算最小樣本閾值(終止條件)
  min_df = sample_set.shape[0] * 0.05
  split_list = []
  # 計算第一個和最後一個分割點
  bining_data_split(sample_set, var, min_df, split_list)
  return split_list

非常感謝你的閱讀
大學的時候選擇了自學python,工作了發現吃了計算機基礎不好的虧,學歷不行這是

沒辦法的事,只能後天彌補,於是在編碼之外開啓了自己的逆襲之路,不斷的學習python核心知識,深

入的研習計算機基礎知識,整理好了,我放在我們的Python學習扣qun:250933691,如果你也不甘平庸

,那就與我一起在編碼之外,不斷成長吧!

其實這裏不僅有技術,更有那些技術之外的東西,比如,如

何做一個精緻的程序員,而不是“屌絲”,程序員本身就是高貴的一種存在啊,難道不是嗎?[點擊加入

]想做你自己想成爲高尚人,加油!
@本文來源於公衆號:csdn2299,喜歡可以關注公衆號 程序員學府

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