파 이 썬 이 회귀 트 리 모델 을 어떻게 실현 하 는 지 배 워 드릴 게 요.

이른바 회귀 트 리 모델 이란 트 리 모델 로 회귀 문 제 를 해결 하 는 것 이다.트 리 모델 중에서 가장 전형 적 인 자연 은 결정 트 리 모델 이 고 거의 모든 트 리 모델 의 기초 이기 도 한다.기본 구 조 는 모두 의사 결정 트 리 를 사용 하지만 예측 방법 에 따라 두 가지 로 나 눌 수 있다.첫 번 째,나무의 잎 노드 는 하나의 예측 치 와 분류 나무 에 대응 하 는데 이 방법 을 회귀 나무 라 고 한다.두 번 째,나무의 잎 노드 는 하나의 선형 모델 에 대응 하고 마지막 결 과 는 선형 모델 에 의 해 제 시 됩 니 다.이 방법 을 모형 나무 라 고 부른다.
오늘 우 리 는 먼저 그 중의 회귀 나 무 를 보 자.
회귀 트 리 모형
CART 알고리즘 의 핵심 정 수 는 우리 가 특징 을 선택 하여 데 이 터 를 분할 할 때마다 데이터 세트 를 영원히 2 점 으로 나 누 는 것 이다.분 산 된 특징 이 든 연속 적 인 특징 이 든 차별 하지 않 는 다.CART 는 또 하나의 특징 은 정보 이득 이나 정보 이득 비례 가 아 닌 GINI 지 수 를 사용 하여 분할 을 선택 하 는 것 이지 만 회귀 문제 에 서 는 이 를 사용 할 수 없다 는 것 이다.회귀 문제 의 손실 함 수 는 교차 엔트로피 가 아니 라 평균 분산 이기 때문에 엔트로피 로 연속 값 의 정확 도 를 평가 하기 어렵다.
분류 트 리 에서 우리 의 한 잎 노드 는 하나의 유형의 예측 치 를 대표 한다.이 유형의 수 치 는 이 잎 노드 에 떨 어 진 훈련 견본 의 유형 중 수,즉 빈도 가 가장 높 은 유형 이다.회귀 나무 에서 잎 노드 에 대응 하 는 자연 은 연속 값 이다.이 연속 치 는 이 노드 에 떨 어 진 훈련 견본 의 평균 값 으로 그의 오 차 는 바로 이 견본 들 의 평균 분산 이다.
또한 이전에 우 리 는 특징의 구분 한도 값 을 선택 할 때 한도 값 의 선택 을 최적화 시 켰 고 예측 유형 변 화 를 일 으 킬 수 있 는 한도 값 만 선택 했다.그러나 회귀 문제 에서 예측 치 는 부동 소수점 이기 때문에 이 최적화 도 존재 하지 않 는 다.전체적으로 회귀 트 리 의 실현 난이 도 는 분류 트 리 보다 낮다.
실전
우 리 는 먼저 데 이 터 를 불 러 옵 니 다.우 리 는 이번에 scikit-learn 라 이브 러 리 에서 전형 적 인 보스턴 집 값 예측 데 이 터 를 사 용 했 습 니 다.집 값 예측 에 대해 카 글 에는 house-prices-advanced-regression-techniques 라 는 비슷 한 경기 도 있다.그러나 제 시 된 특징 이 더 많 고 부족 한 상황 이 존재 하기 때문에 우 리 는 대량의 특징 공 사 를 해 야 한다.흥미 있 는 학우 들 은 스스로 연구 해 볼 수 있다.
우선,우 리 는 데 이 터 를 얻 습 니 다.sklearn 라 이브 러 리 에 데이터 가 있 기 때문에 api 를 직접 호출 하여 얻 을 수 있 습 니 다.매우 간단 합 니 다.

import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
boston = load_boston()

X, y = boston.data, boston.target
우 리 는 출력 하기 전에 몇 개의 데 이 터 를 살 펴 보 았 다.

이 데이터 의 질 이 매우 높 습 니 다.sklearn 라 이브 러 리 는 이미 우 리 를 위해 데이터 선별 과 특징 공 사 를 마 쳤 습 니 다.직접 가 져 와 서 사용 하면 됩 니 다.우리 가 데 이 터 를 전달 하 는 것 을 편리 하 게 하기 위해 서 우 리 는 X 와 y 를 합 쳤 다.y 는 1 차원 의 배열 형식 으로 2 차원 의 X 와 합병 할 수 없 기 때문에 우 리 는 먼저 y 에 대해 reshape 를 한 후에 합병 해 야 한다.

y = y.reshape(-1, 1)
X = np.hstack((X, y))
hstack 함 수 는 두 np 의 array 를 가로로 연결 할 수 있 습 니 다.이에 대응 하 는 것 은 vstack 입 니 다.두 개의 array 를 세로 로 연결 하 는 것 도 일반적인 작업 입 니 다.합병 후 Y 는 새로운 열 로 X 뒤에 추가 되 었 습 니 다.데이터 가 해결 되 었 으 니 이제 모델 을 실현 할 차례 다.
결정 트 리 의 주체 부분 을 실현 하기 전에 우 리 는 먼저 두 개의 보조 함 수 를 실현 한다.첫 번 째 보조 함 수 는 샘플 의 분산 과 두 번 째 보조 함 수 는 샘플 의 평균 값,즉 서브 노드 의 예측 값 을 계산 하 는 것 이다.

def node_mean(X):
 return np.mean(X[:, -1])


def node_variance(X):
 return np.var(X[:, -1]) * X.shape[0]
이것 이 끝 난 후에 우 리 는 한도 값 에 따라 데 이 터 를 나 누 는 함 수 를 계속 실현 했다.이것 도 이전의 코드 를 다시 사용 할 수 있 습 니 다.

from collections import defaultdict
def split_dataset(X, idx, thred):
 split_data = defaultdict(list)
 for x in X:
  split_data[x[idx] < thred].append(x)
 return list(split_data.values()), list(split_data.keys())
다음은 두 개의 중요 한 함수 입 니 다.각각 get 입 니 다.thresholds 와 splitvariance。말 그대로 첫 번 째 함 수 는 한도 값 을 얻 는 데 사용 된다.앞에서 말 했 듯 이 우리 가 하 는 것 은 회귀 모델 이기 때문에 이론 적 으로 특징의 모든 수 치 는 절 분 된 근거 로 할 수 있다.그러나 여러 데이터 의 특징 값 이 같은 상황 이 존재 할 수 있 음 을 배제 하지 않 기 때문에 우 리 는 그것 을 중시 합 니 다.두 번 째 함 수 는 한도 값 에 따라 데 이 터 를 분할 하고 분할 후의 분산 과 를 되 돌려 주 는 것 이다.

def get_thresholds(X, i):
 return set(X[:, i].tolist())

#            
MINIMUM_IMPROVE = 2.0
#            
MINIMUM_SAMPLES = 10

def split_variance(dataset, idx, threshold):
 left, right = [], []
 n = dataset.shape[0]
 for data in dataset:
  if data[idx] < threshold:
   left.append(data)
  else:
   right.append(data)
 left, right = np.array(left), np.array(right)
 #    
 #            ,   None,     
 if len(left) < MINIMUM_SAMPLES or len(right) < MINIMUM_SAMPLES:
  return None
 #                           
 #             ,      
 return node_variance(left) + node_variance(right)
여기 저희 가 MINIMUM 을 썼어 요.SAMPLES 라 는 매개 변 수 는 가 지 를 미리 자 르 는 데 사 용 됩 니 다.우 리 는 회귀 모델 이기 때문에 결정 나무의 성장 에 제한 을 두 지 않 으 면 결정 나무의 잎 노드 와 훈련 견본 의 수량 이 똑 같이 많 을 수 있다.이것 은 분명히 과 의합 에 빠 졌 고 모델 의 효과 에 해 롭 고 무익 하 다.그래서 우 리 는 모든 노드 의 견본 수량 을 제한 해 야 한다.이것 은 하나의 매개 변수 이 고 우 리 는 수요 에 따라 스스로 조정 할 수 있다.
다음은 특징 과 한도 값 선별 함수 입 니 다.우 리 는 분리 할 수 있 는 모든 특징 과 한도 값 을 옮 겨 다 니 며 데 이 터 를 분리 하고 모든 특징 에서 가장 좋 은 분할 가능성 을 찾 을 수 있 는 함 수 를 개발 해 야 한다.

def choose_feature_to_split(dataset):
 n = len(dataset[0])-1
 m = len(dataset)
 #       ,     
 var_ = node_variance(dataset)
 bestVar = float('inf')
 feature = -1
 thred = None
 for i in range(n):
  threds = get_thresholds(dataset, i)
  for t in threds:
   #        ,       variance
   v = split_variance(dataset, i, t)
   #   v  None,        ,  
   if v is None:
    continue
   if v < bestVar:
    bestVar, feature, thred = v, i, t
 #               ,      ,       
 if var_ - bestVar < MINIMUM_IMPROVE:
  return None, None
 return feature, thred
위 와 마찬가지 로 이 함수 에 도 미리 가 지 를 자 르 는 인자 MINIMUM 이 사용 되 었 습 니 다.IMPROVE 는 서브 트 리 를 만 들 때마다 가 져 오 는 수익 을 평가한다.어떤 생 성 서브 트 리 가 가 져 온 수익 이 특정한 가치 보다 적 을 때 수익 이 매우 적 고 수지 가 맞지 않 는 다 는 것 을 설명 하기 때문에 우 리 는 이번 서브 트 리 의 생 성 을 포기 합 니 다.이것 도 예비 가지치기 의 일종 이다.
이것들 이 모두 해결 되면 나 무 를 세 울 수 있 을 것 이다.트 리 를 만 드 는 과정 은 이전 과 유사 합 니 다.다만 이번 데이터 에는 특징 이 없 는 name 이기 때문에 특징 이름 에 관 한 논 리 를 제거 합 니 다.

def create_decision_tree(dataset):
 dataset = np.array(dataset)
 
 #         10,          
 if dataset.shape[0] < MINIMUM_SAMPLES:
  return node_mean(dataset)
 
 #             
 fidx, th = choose_feature_to_split(dataset)
 if fidx is None:
  return th
 
 node = {}
 node['feature'] = fidx
 node['threshold'] = th
 
 #     
 split_data, vals = split_dataset(dataset, fidx, th)
 for data, val in zip(split_data, vals):
  node[val] = create_decision_tree(data)
 return node
우 리 는 나 무 를 만 드 는 것 을 완전 하 게 테스트 해 보 자.우선 우 리 는 원시 데 이 터 를 분리 해 야 한다.원본 데 이 터 를 훈련 데이터 와 테스트 데이터 로 나 누 면 우리 의 장면 이 비교적 간단 하기 때문에 검증 데 이 터 를 설정 하지 않 습 니 다.
분할 데 이 터 는 우리 가 실현 하지 않 아 도 됩 니 다.sklearn 에서 해당 하 는 도 구 를 제공 합 니 다.우 리 는 직접 호출 하면 됩 니 다.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=23)
우리 가 일반적으로 사용 하 는 매개 변 수 는 두 개 입 니 다.하 나 는 test 입 니 다.size,그것 은 정수 일 수도 있 고 부동 소수점 일 수도 있 습 니 다.정수 라면 테스트 집의 견본 수량 을 대표 한다.0-1.0 의 부동 소수점 이 라면 테스트 집합 이 차지 하 는 비례 를 나타 낸다.random_state 는 무 작위 수 를 만 들 때 사용 하 는 무 작위 피 드 입 니 다.

우 리 는 생 성 된 나 무 를 출력 합 니 다.데이터 의 양 이 비교적 많 기 때문에 거대 한 나무 구 조 를 볼 수 있 습 니 다.나 무 를 세 우 는 부분 이 이 루어 진 후에 마지막 으로 남 은 것 은 예측 하 는 부분 이다.
예측 부분의 코드 는 이전 분류 트 리 와 차이 가 크 지 않 고 전체적인 논리 가 똑 같 으 며 feature 만 제거 되 었 습 니 다.names 의 관련 논리.

def classify(node, data):
 key = node['feature']
 pred = None
 thred = node['threshold']

 if isinstance(node[data[key] < thred], dict):
  pred = classify(node[data[key] < thred], data)
 else:
  pred = node[data[key] < thred]
   
 #   pred  ,            
 if pred is None:
  for key in node:
   if not isinstance(node[key], dict):
    pred = node[key]
    break
 return pred
이 함 수 는 한 번 에 하나의 데이터 만 받 아들 일 수 있 기 때문에 우리 가 대량으로 예측 하려 면 아직 안 되 기 때문에 가장 좋 은 것 은 대량으로 예측 하 는 predict 함 수 를 실현 하 는 것 이 좋 습 니 다.

def predict(node, X):
 y_pred = []
 for x in X:
  y = classify(node, x)
  y_pred.append(y)
 return np.array(y_pred)
뒷가지치기
뒷 가지치기 의 영문 원문 은 post-prune 이지 만 번역 이 성사 되면 가지치기 도 이상 하 다.anyway,우 리 는 뒷 가지치기 라 는 단 어 를 사용 하면 된다.
회귀 수 에서 우리 가 이용 하 는 사상 은 매우 소박 하고 나 무 를 지 을 때 가능 한 한 복잡 하고 방대 한 나 무 를 세 웠 다.그 다음 에 테스트 집합 을 통 해 이 나 무 를 다 듬 었 습 니 다.다 듬 는 논리 도 매우 간단 합 니 다.우 리 는 한 그루 의 나무 에 갈 라 지 는 것 과 갈 라 지지 않 은 것 이 따로 잎 노드 가 될 때의 오차 가 있다 고 판단 합 니 다.다 듬 은 후에 오차 가 더 적 으 면 우 리 는 이 나 무 를 빼 겠 습 니 다.
전체 가지치기 과정 은 나 무 를 만 드 는 과정 과 마찬가지 로 위 에서 아래로 순환 하여 집행 한다.
전체 논 리 는 이해 하기 쉽 습 니 다.우 리 는 코드 를 직접 보 겠 습 니 다.

def is_dict(node):
 return isinstance(node, dict)


def prune(node, testData):
 testData = np.array(testData)
 if testData.shape[0] == 0:
  return node
 
 #     
 split_data, _ = split_dataset(testData, node['feature'], node['threshold'])
 #          
 if is_dict(node[0]):
  node[0] = prune(node[0], split_data[0])
 if is_dict(node[1]) and len(split_data) > 1:
  node[1] = prune(node[1], split_data[1])

 #           ,              
 if len(split_data) > 1 and not is_dict(node[0]) and not is_dict(node[1]):
  #          
  baseError = np.sum(np.power(np.array(split_data[0])[:, -1] - node[0], 2)) + np.sum(np.power(np.array(split_data[1])[:, -1] - node[1], 2))
  #          
  meanVal = (node[0] + node[1]) / 2
  mergeError = np.sum(np.power(meanVal - testData[:, -1], 2))
  if mergeError < baseError:
   return meanVal
  else:
   return node
 return node
마지막 으로 우 리 는 다 듬 은 후의 효과 에 대해 검증 을 한다.

그림 에서 보 듯 이 자 르 기 전에 테스트 데이터 의 평균 방 차 는 19.65 이 고 자 른 후에 19.48 로 낮 아 졌 다.수치 적 으로 볼 때 효과 가 있 습 니 다.다만 우리 의 훈련 데이터 가 비교적 적 고 예비 가지치기 도 실시 하여 뒷 가지치기 효과 에 영향 을 주 었 습 니 다.그러나 실제 기계 학습 공정 에 있어 한 가지 방법 은 명확 한 효과 가 있 으 면 대가 가 감당 할 수 있 는 범위 내 에서 가치 가 있 기 때문에 향상 이 뚜렷 하지 않다 고 생각 하고 한 가지 방법 을 함부로 부정 해 서 는 안 된다.
여기 서 평균 방 차 를 계산 할 때 sklearn 의 라 이브 러 리 함수 mean 을 사 용 했 습 니 다.square_error,이름 에서 도 그 용 도 를 알 수 있 습 니 다.그것 은 두 Numpy 의 array 를 모두 분산 시 킬 수 있 습 니 다.
총결산
회귀 트 리 모델 에 관 한 내용 은 여기까지 입 니 다.우 리 는 직접 모델 을 실 현 했 을 뿐만 아니 라 실제 데이터 세트 에서 도 실험 을 했 습 니 다.만약 당신 이 직접 실현 한 모델 의 코드 라면,당신 은 반드시 많은 수확 을 얻 을 것 이 라 고 믿 습 니 다.
실제 운용 으로 볼 때 우 리 는 나무 모형 을 사용 하여 회귀 임 무 를 거의 하지 않 지만 회귀 나무 모형 자체 가 매우 의미 가 있다.이 를 바탕 으로 우 리 는 더 좋 은 효 과 를 가 진 모델 을 많이 발 전 했 기 때문이다.예 를 들 어 유명한 GBDT 등 이다.따라서 회귀 트 리 를 이해 하 는 것 은 우리 의 후속 진급 학습 에 매우 중요 하 다.깊이 있 는 학습 이 보급 되 기 전에 사실은 대부분 효과 가 높 은 모델 은 나무 모델 을 바탕 으로 한다.예 를 들 어 랜 덤 숲,GBDT,Adaboost 등 이다.나무 모형 이 기계 학습 의 반 시 대 를 버 텼 다 고 할 수 있 습 니 다.그 중요성 을 이해 할 수 있 을 거 라 고 믿 습 니 다.
오늘 의 글 은 여기까지 입 니 다.만약 에 본문 을 좋아한다 면 관심 을 가지 고 저 에 게 격려 를 해 주 십시오.그리고 더 많은 글 을 얻 을 수 있 습 니 다.
이상 은 Python 이 회귀 트 리 모델 을 어떻게 실현 하 는 지 배 우 는 상세 한 내용 입 니 다.Python 이 회귀 트 리 모델 을 실현 하 는 것 에 관 한 자 료 는 우리 의 다른 관련 글 에 주목 하 세 요!

좋은 웹페이지 즐겨찾기