import pandas as pd
import numpy as np
from shapely.geometry import Point
import geopandas as gpd
from geopandas.tools import sjoin
import pyproj
from tqdm import tqdm
def preprocess_data(df, x_col, y_col):
wgs84 = pyproj.CRS('EPSG:4326') # WGS84 좌표계 (위도, 경도)
utm_k = pyproj.CRS('EPSG:5179') # UTM-K 좌표계 (한국)
project = pyproj.Transformer.from_crs(wgs84, utm_k, always_xy=True).transform
df['geometry'] = df.apply(lambda row: Point(project(row[x_col], row[y_col])), axis=1)
return gpd.GeoDataFrame(df, geometry='geometry', crs=utm_k)
def calculate_density(gdf_real_estate, gdf_locations, radius):
gdf_real_estate['buffer'] = gdf_real_estate.geometry.buffer(radius)
joined = sjoin(gdf_locations, gdf_real_estate.set_geometry('buffer'), how='inner', predicate='within')
density = joined.groupby(joined.index_right).size().rename('density')
return gdf_real_estate.join(density, how='left').fillna(0)['density']
def process_in_chunks(df, locations_gdf, radius, chunk_size=10000):
results = []
for i in tqdm(range(0, len(df), chunk_size)):
chunk = df.iloc[i:i+chunk_size]
chunk_gdf = preprocess_data(chunk, '좌표X', '좌표Y')
density = calculate_density(chunk_gdf, locations_gdf, radius)
results.append(density)
return pd.concat(results)
# 버스 정류장과 지하철역 데이터 전처리
bus_gdf = preprocess_data(dt_bus, 'X좌표', 'Y좌표') # 버스 정류장 좌표계 변환
# 지하철 데이터는 위도, 경도 데이터를 X, Y로 변환
subway_gdf = preprocess_data(dt_subway, '경도', '위도') # 지하철 데이터도 동일하게 좌표 변환
# 반경 설정
bus_radius = 500 # 미터 단위
subway_radius = 1000 # 1km를 미터 단위로 표현
# 청크 크기 설정
chunk_size = 10000
print("버스 정류장 밀도 계산 중 (500m 반경)...")
concat['bus_stop_density_500m'] = process_in_chunks(concat, bus_gdf, bus_radius, chunk_size)
print("지하철역 밀도 계산 중 (1km 반경)...")
concat['subway_station_density_1km'] = process_in_chunks(concat, subway_gdf, subway_radius, chunk_size)
# 결과 출력
print(concat[['좌표X', '좌표Y', 'bus_stop_density_500m', 'subway_station_density_1km']].head())
RMSE : 8432.15101327254
#첫 번째 행을 '날짜', 두 번째 행을 '기준금리'로 변환
dt_rate = pd.DataFrame({
'날짜' : dt_rate.iloc[0, :].values, #세로로 변환
'기준금리' : dt_rate.iloc[1, :].values
})
dt_rate.reset_index(drop=True, inplace=True)
print(dt_rate.head())
#날짜에서 '월' 지우기
dt_rate['날짜']=dt_rate['날짜'].str.replace('월','')
#데이터타입 일치시키기
dt_rate['날짜'] = dt_rate['날짜'].astype(int)
concat['계약년월'] = concat['계약년월'].astype(int)
# 병합 과정에서 누락되는 것을 방지하기 위해, 계약년월과 기준금리가 일치하는지 직접 확인하는 방식으로 병합
concat['기준금리'] = concat['계약년월'].map(dt_rate.set_index('날짜')['기준금리'])
#날짜 컬럼 제거
#concat.drop(columns='날짜', inplace=True)
#기준금리 데이터타입 변환
concat['기준금리']= concat['기준금리'].astype(float)
#결과 출력
print(concat.head(5))
# 결측치 확인
print(f"기준금리 결측치 수: {concat['기준금리'].isnull().sum()}")
RMSE test: 8336.50080272665
# 만약 가중치를 적용하고 싶다면:
bus_weight = 0.5 # 예: 버스 밀도에 가중치 0.5
subway_weight = 0.8 # 예: 지하철 밀도에 가중치 0.7
concat['weighted_combined_density'] = (concat['bus_stop_density_500m'] * bus_weight +
concat['subway_station_density_1km'] * subway_weight)
concat= concat.drop(columns=['bus_stop_density_500m','subway_station_density_1km'])
RMSE test: 8326.393583335255
로컬에서는 RMSE가 낮게 나오는데, submit 해보니까 RMSE가 훌쩍 뛰어버리는 경우를 보고.. 오버피팅 나는 부분을 잡아보자는 생각에 지하철,버스 밀도를 합친 피처를 만들어보았다!
다음 정보들을 더한다면 더 좋은 성능이 나올 수 있을 것 같다




https://sincere-nova-ec6.notion.site/Fast-Up-Report-Guide-6e9ab2d757ef483ea9515e1f4b1e99b5
https://dacon.io/edu/1016/
https://dacon.io/competitions/official/21265/overview/description