XGBoost는 결측치를 처리하기 위해 고유한 방법을 사용합니다. 이 알고리즘은 결측치가 있는 데이터 포인트를 어떻게 처리할지를 학습하는 과정을 포함합니다. 결정 트리를 구축할 때, 각 분할에서 결측치를 가진 데이터 포인트들이 어느 방향(왼쪽 또는 오른쪽 자식 노드)으로 이동해야 하는지 결정합니다. 이는 결측치를 가진 데이터 포인트들이 분할 규칙을 사용할 수 없을 때 적용됩니다. 구체적으로, XGBoost는 다음과 같은 단계를 따릅니다.
- 결측치 방향 학습: XGBoost는 트리의 각 노드에서 결측치를 가진 샘플들이 가장 이득(gain)이 높은 방향으로 이동하도록 학습합니다. 이는 결측치를 가진 데이터 포인트들이 해당 노드에서 어떤 자식 노드로 이동할 때 분류 또는 회귀 성능을 최대화하는지를 결정하는 과정입니다.
- 결측치 처리 기준 설정: 각 노드에서 결측치를 가진 샘플들이 이동할 방향을 결정한 후, 이 정보는 트리가 성장함에 따라 반영됩니다. 이 방식으로, XGBoost는 결측치가 있는 데이터를 명시적으로 분리할 필요 없이 효율적으로 처리할 수 있습니다.
- 최적화된 분할 찾기: 결측치를 처리하는 방식은 트리의 각 분할에서 최적의 분할을 찾는 과정에 자연스럽게 통합됩니다. XGBoost는 결측치를 가진 데이터 포인트들이 특정 분할에서 어떻게 처리되어야 할지를 고려하여, 전체 모델의 성능을 최적화합니다.
실제 적용
이 접근법의 장점은 데이터 전처리 단계에서 결측치를 제거하거나 대체하는 복잡한 방법들을 적용할 필요가 없다는 것입니다. XGBoost는 결측치를 자동으로 핸들링하여, 모델 학습 과정에서 최적의 방향을 찾습니다.
XGBoost의 결측치 처리 메커니즘을 슈도코드로 표현하기 전에, 이 과정이 실제 XGBoost 구현에서는 매우 최적화되어 있고 복잡한 내부 메커니즘을 포함한다는 점을 이해하는 것이 중요합니다.
XGBoost에서 결측치 처리는 주로 결정 트리를 구축하는 과정에서 일어납니다. 각 노드에서 최적의 분할을 결정할 때, 결측치를 가진 데이터 포인트들이 어느 쪽으로 이동해야 하는지를 학습합니다. 이를 위해, XGBoost는 결측치를 가진 데이터 포인트들에 대해 추가적인 경로를 고려하여, 각 노드에서 이들이 왼쪽 또는 오른쪽 자식 노드로 이동할지를 결정합니다.
코드 구현 : XGBoost 결측치 처리
function build_tree(data, depth):
if stopping_condition_met(data, depth):
return make_leaf(data)
# 최적의 분할을 찾기 위한 반복 과정
best_split = None
for feature in data.features:
for split_value in possible_split_values(feature):
left_data, right_data, missing_data = split_data(data, feature, split_value)
# 결측치를 포함하지 않는 데이터로 기본 이득 계산
gain = calculate_gain(left_data, right_data)
# 결측치를 가진 데이터를 처리하기 위한 추가적인 로직
# 결측치를 왼쪽 또는 오른쪽으로 할당해보고, 이득이 최대화되는 방향을 선택
for direction in ['left', 'right']:
if direction == 'left':
gain_with_missing = calculate_gain_with_missing(left_data + missing_data, right_data)
else:
gain_with_missing = calculate_gain_with_missing(left_data, right_data + missing_data)
# 이득이 더 큰 경우, 해당 방향으로 결측치 처리 업데이트
if gain_with_missing > gain:
gain = gain_with_missing
best_split = (feature, split_value, direction)
if best_split is None:
return make_leaf(data)
# 결측치 처리 방향에 따라 데이터 분할
left_data, right_data, missing_data = split_data(data, best_split[0], best_split[1])
if best_split[2] == 'left':
left_data += missing_data
else:
right_data += missing_data
# 재귀적으로 트리 구축
left_child = build_tree(left_data, depth + 1)
right_child = build_tree(right_data, depth + 1)
return make_node(left_child, right_child, best_split)
function split_data(data, feature, split_value):
# 데이터를 분할 값 기준으로 왼쪽, 오른쪽, 결측치를 포함하는 그룹으로 나눔
left_data = [x for x in data if x[feature] < split_value]
right_data = [x for x in data if x[feature] >= split_value]
missing_data = [x for x in data if x[feature] is missing]
return left_data, right_data, missing_data
결측치를 가진 데이터를 어느 자식 노드로 이동시킬지 결정하는 과정에서, 결측치가 포함된 데이터가 최종 모델의 성능에 긍정적인 영향을 미칠 수 있도록 최적의 방향을 학습한다는 걸 보여줍니다.
'트리 모형' 카테고리의 다른 글
깊이 우선 성장 (0) | 2024.02.15 |
---|---|
XGBoost란? (0) | 2024.02.15 |
그래디언트 부스팅의 최적화 과정 뜯어보기 (0) | 2024.02.12 |
그래디언트 부스팅의 간단한 파이썬 구현 (0) | 2024.02.12 |
그래디언트 부스팅이란? (0) | 2024.02.12 |