본문 바로가기
연습장/python

[python] 두 지점간 직선거리 구하기

by Ruas 2023. 6. 27.
728x90

이번 포스트에서는 두 지점간의 직선거리를 구하는 방법에 대해서 알아본다.

사용하는 Dataset은 이전 포스트에서 완성한 전국축제 데이터를 활용할 예정이니, 아래 포스트를 참조하면 된다.

 

 

[Kakao] 카카오 API를 활용한 경도/위도 데이터 수집

오늘 살펴볼 것은 주소 데이터를 활용한 경도/위도 수집 방법이다. 경도/위도 데이터를 얻는 방법은 사실 API를 사용하지 않아도 구글 맵에서 충분히 얻을 수 있다. 위의 사진과 같이 경도/위도

ruas-coding.tistory.com

Dataset의 상세 정보는 다음과 같다.

 

✅ 이전 과정에서 geopandas를 사용하여 데이터프레임을 생성하여, geometry라는 불필요한 column이 존재한다.

✅ 데이터에는 주소와 경도, 위도를 포함한 축제명, 축제정보 등의 정보를 포함한다.

 

이번 포스트를 통해 진행할 내용은 다음과 같다.

 

✅ 서울시청과 각 축제 개최지까지의 직선거리를 계산하여 데이터 프레임으로 저장한다.

✅ 데이터 프레임에는 축제명, 위도, 경도, 주소, 거리 데이터를 포함한다.

✅ 직선 거리의 단위는 km로 통일한다.

 

💡 사용 라이브러리
from haversine import haversine
import geopandas as gpd
import numpy as np
import pandas as pd​

1. Haversine 공식

시작하기에 앞서 직선거리를 계산하는 방법에 대해 이야기 해보겠다.

 

우리가 두 점 사이의 직선 거리를 구하는 방법에는 피타고라스 정의가 있다.

가장 간편하게 직선거리를 구할 수 있는 방법이고, 많이 사용하는 방법일 것이다.

 

Source: Wikipedia

 

하지만, 위경도를 바탕으로 두 지점간 직선거리를 계산하는 경우에는 다르다.

피타고라스의 정의를 활용할 수 있는 상황은 두 점이 평면 위에 있는 경우이다.

우리가 살고 있는 지구는 둥근 구의 형태를 하고 있기 때문에 피타고라스의 정의를 적용하여 직선거리를 계산하면 오차가 생길 수 밖게 없다.

 

이때 우리가 쓸 수 있는 방식이 바로 Haversine 공식이다.

 

Source: Wikipedia

 

 

Haversine formula - Wikipedia

From Wikipedia, the free encyclopedia Formula for the great-circle distance between two points on a sphere The haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes. Important in navigati

en.wikipedia.org

 

자세한 내용은 위의 링크에서 확인하면 된다.


2. 데이터 전처리

 

하지만 위에서 언급했다시피 불필요한 geometry column이 존재하는 데이터이다.

해당 파일을 그대로 불러오는 경우 geopandas에서 에러가 발생하기 때문에 해당 column을 먼저 제거해 주겠다.

 

이전 포스팅에 설명한 코드에 다음 코드를 이어 붙여 데이터를 가공한다.

del check_data['geometry']

check_data.to_csv("수정완료.csv", encoding='EUC-KR')

geometry column이 제거된 데이터 프레임을 얻을 수 있다.


3. 데이터 불러오기 및 가공

df = gpd.read_file('수정완료.csv', encoding = 'EUC-KR')
df

데이터 불러오기는 어려운 부분이 없으므로 별도로 설명하지는 않겠다.

 

데이터를 불러온 후 데이터를 사용하는 과정에서 문제가 발생하지 않도록 하는 가공 과정이 필요하다.

이번 포스트에서 사용하는 데이터에도 필요한 과정인지는 확인해보지 않았으나, 거의 대부분의 경우에서 해당 과정이 필요했다.

 

맨 처음으로 해줄 것은 데이터에 포함되어 있는 빈 공간을 제거하는 것이다.

각 데이터에 빈 공간이 포함되어 있는 경우에는 오류가 발생할 수 있기 때문에 되도록이면 꼭 진행하는 것이 좋다.

df.replace('', np.nan, inplace=True)

 

다음으로, DataFrame 형식으로 저장되어 있는 데이터에서 위도, 경도 데이터만 추출하여 리스트 형식으로 전환하는 과정이다.

location_data = df[['위도', '경도']].values[:len(df)].tolist()

추출한 데이터를 location_data라는 리스트 형식의 변수에 저장하는데,

이 과정을 DataFrame의 길이만큼 반복하도록 하여 전체 데이터를 리스트에 저장할 수 있도록 한다.

 

하지만 여기서 문제가 발생한다.

밑에서 설명할 Haversine 함수에 데이터를 전달하기 위해서는 int 혹은 float 형식의 데이터 타입을 유지해야하지만,

위의 과정을 통해 데이터를 변환하면 모든 데이터가 string 타입으로 변환되어 버린다.

 

때문에 밑에서 진행할 연산을 진행할 수 없으므로, 다시 한번 형변환을 진행한다.

location_data = np.array(location_data, dtype=np.float32).tolist()

이렇게 형변환을 진행하면 리스트 내의 데이터가 모두 float 타입을 유지하고 있음을 확인할 수 있다.


4. 데이터 프레임 생성

거리를 계산하기에 앞서, 가공한 데이터를 저장할 수 있는 Dataframe을 생성한다.

위에서 언급했던 것처럼 Dataframe은 축제명, 주소, 위도, 경도, 거리를 포함해야 한다.

 

calculate_df = pd.DataFrame(columns=['축제명', '주소','위도', '경도', '거리'])

5. 기준점 지정 및 거리 계산

기준점은 서울시청으로 지정한다.

서울시청의 위경도는 37.566295, 126.977945 이다.

 

center = [37.566295, 126.977945]

for i in range(len(location_data)):
    tmp = location_data[i]
    result = haversine(center, tmp, unit = 'km')
    print("{} ~ 서울시청 직선거리: {}km".format(df['축제명'][i], result))
    
    new_row = {'축제명': df['축제명'][i],
                '주소': df['소재지도로명주소'][i],
                '위도': df['위도'][i],
                '경도': df['경도'][i],
                '거리': result}
    calculate_df = pd.concat([calculate_df, pd.DataFrame([new_row])])

 

for loop을 돌면서 location_data에 저장되어 있는 위경도와 기준점 데이터를 사용하여 직선거리를 계산한다.

haversine 함수에 두 데이터를 전달하고, km단위로 지정하도록 unit을 설정하여 계산을 진행한다.

계산 결과는 result 변수에 저장되며, 해당 결과를 출력하도록 한다.

다음으로 이전 단계에서 생성한 데이터프레임에 데이터 삽입을 위해 nrow를 생성, 데이터와 매칭시킨다.

이후 pandas 라이브러리의 concat을 사용하여 기존 calculate_df에 이어 붙이도록 한다.

 

위의 과정을 반복하면

데이터 프레임에 깔끔하게 데이터를 저장할 수 있다.

 

아래는 해당 포스트의 전체 코드를 정리한 깃허브 링크이다.

 

GitHub - SCUTUM98/Ruas_Factory

Contribute to SCUTUM98/Ruas_Factory development by creating an account on GitHub.

github.com

 

728x90

'연습장 > python' 카테고리의 다른 글

[python] 경도/위도 데이터를 활용한 지도 시각화  (0) 2023.07.05

댓글