AI 부스트캠프 7기 과정 중 두번째 프로젝트를 진행하는 과정에서 모델링 관련하여 고민했던 내용을 정리해보고자 한다.
이번 수도권 아파트 전세가 예측 프로젝트를 진행하면서, 데이터 샘플의 위도, 경도에 대한 공간적인 관계에 대해 종속변수인 전세가에 대한 공간적 자기 상관이 존재할 것이라는 가설을 세웠다.
즉, 거리가 가까운 이웃끼리는 전세가가 비슷할 것이라고 예상하고 이를 모델에 반영해보기 위해 공간적 가중치 행렬(Spatial Weight Matrix)을 사용해보기로 했다.
상관(Correlation)은 서로 다른 두 변수가 상관 관계를 갖고 동일한 규칙으로 변화하는 것을 말한다. 자기 상관은 시간 또는 공간적으로 연속된 일련의 관측치들 간의 상관관계를 의미한다. 따라서 공간적 자기 상관은 공간적인 근접성에 의해 관측치, 즉 종속변수들 간의 상관관계를 갖는 것을 말한다.
공간적 자기 상관은 공간적인 근접성을 전제로 하기 때문에, 공간적인 근접성을 판단할 기준이 필요하다. 나는 거리를 기준으로 공간적인 근접성을 판단하기로 했다. 여기서 문제가 된 것은, 그렇다면 모든 샘플 간의 거리를 측정해야 한다는 것이다. 그런데 데이터셋의 크기가 상당히 큰 편이기 때문에, 모든 데이터 샘플 간의 거리를 측정하는 것은 자원의 한계가 있었다.
그래서 공간 분할 알고리즘을 이용해 계산해야 하는 범주를 좁혀보기로 했다. 공간 분할 알고리즘에는 대표적으로 KD Tree와 Ball Tree가 있는데, 나는 그 중에 Ball Tree 알고리즘을 선택했다.
Ball Tree와 KD Tree는 모두 고차원 데이터에서 효율적으로 근접 이웃을 탐색하거나 거리 계산을 하기 위해 사용되는 알고리즘이다. 다만 사용 목적과 차원의 크기에 따라 적합한 알고리즘이 달라질 수 있어서 이를 비교해보기로 했다.
| 비교 항목 | Ball Tree | KD Tree |
|---|---|---|
| 작동 방식 | 중심점과 반경을 기준으로 분할 | 각 차원의 중간값을 기준으로 분할 |
| 거리 함수 | 유클리드, 하버사인 거리와 같은 다양한 거리 함수 사용 가능 | 유클리드 거리 계산에 최적화 |
| 차원의 크기에 따른 효율 | 고차원에 효과적이고, 저차원에서는 KD Tree보다 느릴 수 있음 | 저차원(2, 3차원)에 특히 효율적, 고차원일수록 차원의 저주로 인해 성능이 저하될 수 있음 |
나는 위도, 경도를 기준으로 근접 이웃을 탐색할 예정이기 때문에 고차원의 데이터는 아니지만, 위도, 경도에 따른 거리 계산에는 하버사인 거리 함수가 보다 정확하고 Ball Tree는 저차원에서도 KD Tree와 많은 성능 차이를 보이지 않기 때문에 최종적으로 Ball Tree 알고리즘을 이용하게 되었다.
from sklearn.neighbors import BallTree
data = ... # 분할할 데이터
tree = BallTree(data, metric='haversine') # metric에 사용할 거리 함수 지정
distance, indices = tree.query(data, k=n) # k : 찾고자 하는 근접 이웃 수
'''
distance : k개의 근접 이웃을 거리가 가까운 순으로 data 샘플 포인트와의 거리 반환
indices : 거리가 가까운 k개의 근접 이웃의 인덱스
'''
공간적 가중치 행렬을 전체 크기로 생성하여 사용하기에는 데이터셋의 크기가 너무 컸다. out of memory로 인해 공간적 가중치 행렬을 메모리에 올릴 수 있는 크기로 분할해서 사용할 필요가 있었고, 이를 다시 희소 행렬로 변환하여 더욱 메모리 사용량을 줄였다. 최종적으로 청크 단위로 분할한 뒤, 이를 csr_matrix를 이용해 희소 행렬로 변환하고, 이를 pkl 파일로 저장하여 필요할 때 해당하는 부분만 로드하여 사용하는 것으로 공간적 가중치 행렬을 생성했다.