본문 바로가기
프로젝트/(세미)강남구 지역 상권 기반 시간대별 편의점 매출 예측

좌표 데이터(.shp) -3 반경 내 좌표 개수 세기

by 규딩코딩 2023. 9. 9.

 

0. 준비하기

- 필요한 라이브러리를 설치해주고, 각 버스정류장 좌표 / 각 상권 중앙 좌표 / 지하철 역 좌표 데이터를 불러와주자.

 

1. 좌표계 변환하기

- 이번 반경 내 좌표 찾기에서 기준 좌표가 되는 상권 중앙 좌표값을 다른 좌표들과 함께 맞춰주고 직관적으로 이해하기 쉽게 WGS84 위경도 좌표로 변환해주자

# 좌표 변환 함수 정의
def transform_coordinates(x, y):
    epsg5181 = pyproj.CRS("EPSG:5181")
    wgs84 = pyproj.CRS("EPSG:4326")
    transformer = pyproj.Transformer.from_crs(epsg5181, wgs84, always_xy=True)
    longitude, latitude = transformer.transform(x, y)
    return f"{latitude}, {longitude}"

# 좌표 변환 적용하여 상권 중앙위경도 값 추가
df_all['상권_중앙위경도_값'] = df_all.apply(lambda row: transform_coordinates(row['엑스좌표_값'], row['와이좌표_값']), axis=1)

 

2. 좌표 컬럼 만들기

- 버스, 지하철 좌표 값들도 위경도 좌표로 만들어 칼럼을 새로 만들어주자.

- 여기서 주목해야할 것은 중복값을 제거하는 것이다. 이유는 현재 데이터는 버스데이터의 경우 3개년 각 분기별 총 12개, 그러니까 같은 버스 정류장의 데이터가 한 점의 좌표를 가지자면 총 12개가 겹쳐있어 개수 세기에 혼란을 불러일으키기 때문이다. 이는 지하철 데이터도 마찬가지이다.

# '버스정류장_위경도_값' 열 생성
BUS_GN['버스정류장_위경도_값'] = BUS_GN['Y좌표'].astype(str) + ', ' + BUS_GN['X좌표'].astype(str)

BUS = BUS_GN[['버스정류장ARS번호', '버스정류장_위경도_값']].drop_duplicates().reset_index(drop=True)

 

# '지하철역_위경도_값' 열 생성
SUB_GN['지하철역_위경도_값'] = SUB_GN['위도'].astype(str) + ', ' + SUB_GN['경도'].astype(str)

SUB = SUB_GN[['지하철역', '지하철역_위경도_값']].drop_duplicates().reset_index(drop=True)

 

3. 반경 내 좌표 개수 세기

- 반경 300미터 내에 버스 정류장 수를 다음의 코드를 이용하여 구하고, 칼럼으로서 나타낼 수 있다.

 

- within_radius(coord1, coord2)

이 함수는 두 지점 간의 거리를 계산하고, 그 거리가 300 미터 이내에 있는지 여부를 판단합니다. coord1과 coord2는 좌표를 나타내며, geodesic 함수를 사용하여 두 지점 사이의 거리를 계산합니다. 만약 거리가 300 미터 이내이면 True를 반환하고, 그렇지 않으면 False를 반환합니다.

 

- count_bus_stops_within_radius(all_coords, bus_coords)

이 함수는 상권 중앙 좌표를 기준으로 반경 내에 있는 버스 정류장의 수를 계산합니다. all_coords는 모든 상권 중앙 좌표의 리스트이고, bus_coords는 버스 정류장들의 좌표를 나타내는 리스트입니다. 이 함수는 bus_coords의 각 정류장에 대해, all_coords 중 어떤 좌표와의 거리가 300 미터 이내에 있는지 확인하고, 맞다면 count를 증가시킵니다.

최종적으로는 반경 내에 있는 버스 정류장의 총 수를 반환합니다.

from geopy.distance import geodesic

# 좌표 간 거리를 계산하고, 300미터 이내에 있는지 확인하는 함수
def within_radius(coord1, coord2):
    return geodesic(coord1, coord2).meters <= 300

# 상권 중앙 좌표를 기준으로 반경 내에 있는 버스 정류장 수를 계산하는 함수
def count_bus_stops_within_radius(all_coords, bus_coords):
    count = 0
    for bus_coord in bus_coords:
        if any(within_radius(all_coord, bus_coord) for all_coord in all_coords):
            count += 1
    return count

# ALL 데이터프레임의 좌표값을 추출하여 리스트로 변환
all_coords = [tuple(map(float, coord.split(', '))) for coord in ALL['상권_중앙위경도_값']]

# BUS 데이터프레임의 좌표값을 추출하여 리스트로 변환
bus_coords = [tuple(map(float, coord.split(', '))) for coord in BUS['버스정류장_위경도_값']]

# 각 상권의 중앙 좌표를 기준으로 반경 내에 있는 버스 정류장 수를 계산하여 컬럼에 추가
ALL['버스정류장_수'] = [count_bus_stops_within_radius([all_coord], bus_coords) for all_coord in all_coords]

 

- 비슷한 내용으로 지하철 역 개수까지 구해주면 다음과 같이 결과가 나오게 된다.

from geopy.distance import geodesic

# 좌표 간 거리를 계산하고, 300미터 이내에 있는지 확인하는 함수
def within_radius(coord1, coord2):
    return geodesic(coord1, coord2).meters <= 300

# 상권 중앙 좌표를 기준으로 반경 내에 있는 지하철 역 수를 계산하는 함수
def count_subway_stations_within_radius(all_coords, subway_coords):
    count = 0
    for subway_coord in subway_coords:
        if any(within_radius(all_coord, subway_coord) for all_coord in all_coords):
            count += 1
    return count

# ALL 데이터프레임의 좌표값을 추출하여 리스트로 변환
all_coords = [tuple(map(float, coord.split(', '))) for coord in ALL['상권_중앙위경도_값']]

# SUB 데이터프레임의 좌표값을 추출하여 리스트로 변환
subway_coords = [tuple(map(float, coord.split(', '))) for coord in SUB['지하철역_위경도_값']]

# 각 상권의 중앙 좌표를 기준으로 반경 내에 있는 지하철 역 수를 계산하여 컬럼에 추가
ALL['지하철역_수'] = [count_subway_stations_within_radius([all_coord], subway_coords) for all_coord in all_coords]
ALL

 

********** 참 고 용 데 이 터 프 레 임 **********

 

 

 

반응형