데이터 분석에서 거리 계산은 중요한 역할을 합니다. 특히, 지리적 위치를 기반으로 한 분석에서는 정확한 거리 계산이 필수적입니다. 이 글에서는 거리 기반 데이터 병합 방법에 대해 알아봅니다.
주요내용
- 📊 데이터 분석의 필수 요소인 거리 계산에 대해 배웁니다.
- 🌐 지리적 위치 데이터를 활용한 병합 기법을 소개합니다.
- 🛠️ pandas, scipy 등의 라이브러리 사용법을 익힙니다.
이 코드는 필요한 라이브러리를 불러오고, 경고 메시지를 숨기며, 현재 작업 경로를 파일 로드 경로로 설정하는 과정을 담고 있습니다. os
와 pandas
라이브러리를 임포트하여 파일 시스템 작업과 데이터 처리 기능을 사용할 수 있게 합니다. warnings.filterwarnings(action = 'ignore')
를 사용하여 불필요한 경고 메시지가 표시되지 않도록 설정합니다. 마지막으로, %pwd
매직 커맨드를 사용하여 현재 작업 경로를 얻고, os.chdir()
함수를 사용하여 이 경로를 파일 로드 경로로 설정합니다.
1
2
3
4
5
6
7
8
9
import os
import pandas as pd
# 불필요한 경고 표시를 생략합니다.
import warnings
warnings.filterwarnings(action = 'ignore')
a=%pwd # 현재 작업 경로를 변수 a에 할당합니다.
os.chdir(a) # 현재 작업 경로를 파일 로드 경로로 설정합니다.
-
아파트 가격 예측 등 ‘지역’이 포함되는 데이터 분석에서 주소나 위치 변수 등을 기준으로 거리가 가까운 레코드 및 관련 통계치를 통합해야 하는 경우가 있다.
-
이를 통합하는 방법은 보통 3단계를 거친다.
1) 각 데이터에 포함된 레코드 간 거리를 나타내는 거리 행렬을 생성
2) 거리 행렬의 행 or 열 기준 최소 값을 가지는 인덱스를 바탕으로 이웃한 데이터 탐색
3) 탐색한 이웃 데이터를 기존 데이터에 부착
-
서로 다른 주소값을 가진 2개의 데이터 테이블이 있다. (원본데이터의 주소값= A, B, C)
-
이때 각각 주소 A, B, C에 대응하는 주소 X, Y, Z간의 거리를 계산하는
거리행렬
을 생성한다. -
각각의 주소 A, B, C와 가장 인접한
이웃 데이터
를 탐색한 뒤, 해당 데이터를 원본데이터에 붙여넣는다.
관련 문법 1 : scipy.spatial.distance.cdist
-
두 개의 행렬을 바탕으로
거리행렬
을 반환하는 함수 -
일반적인 머신러닝 모델을 만들 때, 오픈소스로 된 데이터를 쓰지 않고 실용적인 데이터를 만들 때 많이 사용된다.(특히 KNN)
-
데이터가 scipy 함수에 사용할 수 있는
연속형 변수
이어야만 사용할 수 있다.
주요 파라미터
-
XA : 거리 행렬 계산 대상인 행렬 (ndarray / DataFrame),
함수의 출력 행
이다. -
XB : 거리 행렬 계산 대상인 행렬 (ndarray / DataFrame),
함수의 출력 열
이다. -
metric : 거리 척도 방식 선택 (‘cityblock’, ‘correlation’, ‘cosine’, ‘euclidean’, ‘jaccard’, ‘matching’ 등)
관련 문법 2 : ndarray.argsort
-
작은 값부터 순서대로 데이터의
위치(index)를 반환하는 함수
입니다. 즉, 각 순위를 매기고 최소값을 갖게 만든 index가 무엇인지 찾게 해주는 함수입니다. -
주로
이웃을 찾을 때
많이 활용됩니다. -
axis = 0이면
열 별 위치
, axis = 1이면행 별 위치
를 반환합니다. -
Tip. 하나의 값만을 찾는 것이 목적이라면 DataFrame의 idxmax(), idxmin() 함수를 사용하는 것이 더 유용합니다.
-
arr1 (1차원)의 경우 axis 파라미터가 적용되지 않습니다.
-
arr2 (2차원)의 경우 axis=0일 때, 첫 번째 열인 10, 7, 12를 예시로 보면 세 개의 수를 정렬하면 7 < 10 < 12가 됩니다.
-
기존 7의 인덱스 값은 1이 argsort(axis=0)의 결과로 출력됩니다.
-
나머지도 동일한 방식으로 적용되어 우측의 결과값으로 나타납니다.
거리기반 데이터 병합 실습
단계별로 생각해 봅시다.
2019년 서울 아파트 거래가 & 주소 데이터에 지하철 역 별 위도 / 경도 데이터를 활용해서 가장 가까운 역이 어디인지
파악
Pandas 라이브러리의 read_csv
함수를 사용하여 2019년 서울 아파트 매매 실거래가와 서울시 아파트 주소 데이터를 불러옵니다. 한글 데이터의 경우 글자가 깨지는 것을 방지하기 위해 encoding
파라미터에 "cp949"
를 지정합니다. 이 과정을 통해 두 개의 데이터프레임 df1
과 df2
가 생성됩니다.
1
2
3
4
# 아파트 관련 데이터 불러오기
# 한글 자료이므로, 글씨 깨짐 방지위해 cp949로 인코딩한다.
df1 = pd.read_csv("2019년_서울_아파트매매_실거래가.csv", encoding = "cp949")
df2 = pd.read_csv("2019년_서울시_아파트주소.csv", encoding = "cp949")
df1.head()
함수는 데이터프레임 df1
에서 상위 5개 행을 반환합니다. 이 함수는 데이터의 구조를 빠르게 파악하고자 할 때 유용하게 사용됩니다.
1
df1.head() # 데이터프레임 df1의 상위 5개 행을 출력합니다.
df2.head()
함수는 데이터프레임에서 처음 5개의 행을 반환합니다. 이 함수는 데이터의 구조를 빠르게 확인하고자 할 때 유용하게 사용됩니다.
1
df2.head() # 데이터프레임의 처음 5개 행을 보여줍니다.
step1. 두 개의 데이터를 이어 붙인다.
단계별로 생각해 봅시다.
이 코드는 두 데이터프레임 df1
과 df2
를 병합하는 과정을 보여줍니다. pd.merge()
함수를 사용하여, df1
의 ‘법정동’, ‘도로명’, ‘아파트’ 컬럼과 df2
의 ‘읍면동명’, ‘도로명’, ‘건물명’ 컬럼을 기준으로 데이터를 병합합니다. 이때, 병합될 컬럼의 순서와 이름이 서로 일치해야 합니다. 결과적으로, 이 과정은 두 데이터셋에서 관련된 정보를 결합하여 새로운 데이터프레임 df
를 생성합니다.
1
2
3
4
5
6
# 데이터 병합
# 병합될 컬럼의 순서가 일치해야 merge() 함수가 적용된다.
# '법정동'은 '읍면동명'으로, '도로명'은 동일하게, '아파트'는 '건물명'으로 각각 매칭하여 병합한다.
df = pd.merge(df1, df2, left_on = ['법정동', '도로명', '아파트'], right_on = ['읍면동명', '도로명', '건물명'])
df
문제 상황인 가장 가까운 지하철역
을 찾기 위해 위치 계산을 할 대상 데이터를 불러온다.
이 함수는 pandas
라이브러리의 read_excel
메서드를 사용하여 ‘지하철역_위경도.xlsx’ 파일을 읽고, 이를 DataFrame
객체로 변환합니다. 이 과정을 통해, 지하철역의 위도와 경도 정보가 포함된 엑셀 파일의 데이터를 분석 및 처리할 수 있는 형태로 불러옵니다.
1
df3 = pd.read_excel("지하철역_위경도.xlsx") # '지하철역_위경도.xlsx' 파일을 읽어서 DataFrame으로 변환합니다.
df3.head()
함수는 데이터프레임 df3
에서 상위 5개 행을 반환합니다. 이 함수는 데이터의 초기 부분을 빠르게 검토할 때 유용하며, 기본적으로 처음 5개의 행을 출력하지만, 괄호 안에 다른 숫자를 지정하여 출력할 행의 수를 조정할 수 있습니다.
1
df3.head() # 데이터프레임 df3의 상위 5개 행을 출력합니다.
df.info()
함수는 데이터프레임의 기본 정보를 출력합니다. 이 함수는 데이터프레임에 포함된 열의 수, 각 열의 데이터 타입, 비어 있지 않은 값의 수, 그리고 메모리 사용량을 포함한 정보를 제공합니다. 이는 데이터 분석을 시작하기 전 데이터의 구조를 이해하는 데 유용합니다.
1
df.info() # 데이터프레임의 기본 정보를 출력합니다.
df3.info()
함수는 DataFrame df3
의 요약 정보를 출력합니다. 이 함수는 데이터의 각 열에 대한 정보를 포함하여, 열의 이름, 비어 있지 않은 값의 개수, 각 열의 데이터 타입 등을 보여줍니다. 또한, 메모리 사용량에 대한 정보도 제공합니다.
1
df3.info() # DataFrame 'df3'의 정보를 출력합니다.
step2. 거리 행렬 계산 (scipy.spatial.distance import cdist)
단계별로 생각해 봅시다.
이 문서는 위경도 좌표를 사용하여 두 지점 간의 거리를 계산하기 위한 haversine
모듈의 설치 방법을 설명합니다. 사용자는 필요에 따라 이 모듈을 설치할 수 있으며, 설치 후에는 지리적 좌표를 기반으로 한 거리 계산을 수행할 수 있습니다.
1
# 위경도 거리 계산을 위한 모듈 설치(필요시 설치)
본 코드는 데이터프레임에서 경도와 위도 컬럼을 추출하여 거리 행렬을 생성하기 위한 준비 작업을 수행합니다. 두 개의 데이터프레임 df
와 df3
에서 각각 ‘경도’와 ‘위도’ 컬럼을 선택하여 새로운 데이터프레임 df_location
과 df3_location
을 생성합니다. 이후, 지구상의 두 지점 간 거리를 계산할 때는 유클리드 거리나 맨해튼 거리 대신 haversine 거리를 사용하는 것이 일반적임을 언급합니다. 이는 haversine 공식이 지구의 곡률을 고려하여 두 지점 간의 거리를 보다 정확하게 계산하기 때문입니다.
1
2
3
4
5
6
7
# 거리 행렬 생성을 위한 컬럼 추출
df_location = df[['경도', '위도']]
df3_location = df3[['경도', '위도']]
# 지구상의 위경도 거리를 구할 때는 유클리드 거리나 맨해튼 거리 사용보다는 haversine 거리를 사용하는 것이 일반적입니다.
이 문서는 scipy.spatial.distance.cdist
함수와 haversine
라이브러리를 사용하여 두 위치 집합 간의 거리 행렬을 계산하는 방법을 설명합니다. cdist
함수는 두 배열 간의 거리를 계산하며, metric
파라미터를 통해 다양한 거리 측정 방법을 지정할 수 있습니다. 여기서는 haversine
메트릭을 사용하여 지구상의 두 지점 간의 거리를 계산합니다. 이는 특히 위도와 경도를 기반으로 한 위치 데이터에 유용합니다.
1
2
3
4
5
6
7
8
9
# 거리 행렬 생성
from scipy.spatial.distance import cdist
from haversine import haversine
# cdist(행, 열) 함수를 사용해 거리를 계산합니다.
# metric= 에 들어갈 수 있는 것들: ['euclidean', 'cityblock', 'jaccard'] (기본적으로 내장된 것들)
# 또는 haversine처럼 외부 패키지를 설치하고 사용할 수도 있습니다.
dist_mat = cdist(df_location, df3_location, metric = haversine)
1
step3. argsort()를 적용해 이웃 지역 탐색 후 병합
이 코드는 데이터프레임 df
에 가장 가까운 지하철 역과 그 거리를 새로운 컬럼으로 추가합니다. 먼저 dist_mat.argsort()[:, 0]
를 사용하여 각 위치에서 가장 가까운 지하철 역의 인덱스를 찾습니다. 이 인덱스를 사용하여 df3
에서 해당 역의 이름을 가져와 df
의 ‘가까운역’ 컬럼에 할당합니다. 마지막으로, 각 위치에서 가장 가까운 지하철 역까지의 거리를 df
의 ‘가까운역까지_거리’ 컬럼에 할당합니다. 이 과정에서 .values
를 사용하여 df3.iloc[...]
의 결과로부터 값 배열을 직접 추출함으로써 인덱스 충돌을 방지합니다.
1
2
3
4
5
close_subway_index = dist_mat.argsort()[:, 0] # axis = 0에 따라 정렬
df['가까운역'] = df3.iloc[close_subway_index]['역명'].values # '가까운역' 컬럼에 가장 가까운 역명 할당
df['가까운역까지_거리'] = dist_mat[close_subway_index][:, 0] # '가까운역까지_거리' 컬럼에 거리 할당
이 함수는 DataFrame
에서 특정 행을 선택하는 데 사용됩니다. 여기서 df3.iloc[close_subway_index]
는 df3
DataFrame
에서 close_subway_index
에 해당하는 행을 선택합니다. iloc
메서드는 위치 기반 인덱싱을 사용하여 데이터를 선택할 때 사용됩니다.
1
2
# df3.iloc[close_subway_index]에서 df3은 DataFrame을 나타내며, .iloc[]는 행 위치를 기반으로 데이터를 선택하는 데 사용됩니다.
# close_subway_index는 가까운 지하철역의 인덱스를 나타냅니다.
df.head()
함수는 데이터프레임에서 처음 다섯 행을 반환합니다. 이 함수는 데이터의 구조를 빠르게 파악하고자 할 때 유용하게 사용됩니다.
1
df.head() # 데이터프레임의 처음 다섯 행을 출력합니다.
댓글남기기