본문 바로가기

TIL 통합

2/19 수요일 TIL - 머신러닝 및 부동산 추천 알고리즘

프로젝트 동안 하고 만든 것들 
 

  1. 부동산 적정가격 예측/평가 머신러닝 전처리 및 모델링
  2. 그리고 부동산 적정가격 알려주는 알고리즘,
  3. 조건에 맞는, 적정가격과 실제가격 차이 적은 부동산 알려주는 알고리즘

 
하 개뿌듯...

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler, StandardScaler
from sklearn.preprocessing import LabelEncoder


from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score

#머신러닝 데이터 전처리 : *데이터 : 부동산데이터, 동별 데이터 통합본
re = pd.read_csv('C:/Users/neddy/Desktop/스파르타 코딩클럽/프로젝트/심화 프로젝트/머신러닝/최종집 선정용/머신러닝최종.csv')
re = re.dropna(subset=['연식'])

st_sc1 = StandardScaler()
st_sc2 = StandardScaler()

le = LabelEncoder()

mm_sc1 = MinMaxScaler()
mm_sc2 = MinMaxScaler()
mm_sc3 = MinMaxScaler()
mm_sc4 = MinMaxScaler()
mm_sc5 = MinMaxScaler()
mm_sc6 = MinMaxScaler()
mm_sc7 = MinMaxScaler()
mm_sc8 = MinMaxScaler()

re['size_sc'] = st_sc1.fit_transform(re[['size']])
re['소득_sc'] = st_sc2.fit_transform(re[['평균소득']])

re['le건물'] = le.fit_transform(re[['building']])

re['mm여성비중'] = mm_sc1.fit_transform(re[['여성인구비중']])
re['mm청년비중'] = mm_sc2.fit_transform(re[['청년인구비중']])
re['mm청년중여성비중'] = mm_sc3.fit_transform(re[['청년중여성비중']])
re['mm전체중청년여성비중'] = mm_sc4.fit_transform(re[['전체중청년여성비중']])
re['mm직장인구밀도'] = mm_sc5.fit_transform(re[['직장인구밀도']]) #좋은 분포는 아니나 큰 이상치도 없으므로 일단은 mm으로
re['mm2030상주인구비중'] = mm_sc6.fit_transform(re[['2030상주인구비중']])



#데이터를 월세랑 전세 나누기
re_month = re.query('type == "월세"').reset_index()       
re_whole = re.query('type == "전세"').reset_index()


#점수 알려주는 알고리즘
def get_score(model_name, y_true, y_pred):
  acc = accuracy_score(y_true, y_pred).round(3)
  f1 = f1_score(y_true, y_pred, average = 'macro').round(3)
  print(model_name, 'acc 스코어는: ', acc, 'f1_score(macro)는 :', f1)
  
  
  
#월세(#보증금 포함) : 랜덤포레스트
re_month_f = re_month[['분기', 'add1', 'add2', 'type', 'deposit', 'rent', 'name', 'le건물', 'size_sc', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중',	'mm청년중여성비중',	'mm전체중청년여성비중', '연식',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']]
X_features = ['deposit', 'le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
X = re_month_f[X_features]
y = re_month_f['rent']

model_rf = RandomForestClassifier(random_state = 42)
model_rf.fit(X, y)
y_rf_pred = model_rf.predict(X)
get_score('rf', y, y_rf_pred)  
#rf acc 스코어는:  0.94 f1_score(macro)는 : 0.898




#전세 : 의사결정나무

re_whole_f = re_whole[['분기', 'add1', 'add2', 'type', 'deposit', 'rent', 'le건물', 'name', 'size_sc', '전분기대비인구증감률',	'mm여성비중', 'mm청년비중',	'mm청년중여성비중',	'mm전체중청년여성비중', '연식',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']]
#re_whole_ff = re_whole_f.query('deposit <=75000') 해봤자 f1만 0.005점 높아짐

wX_features = ['le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
wX = re_whole_f[wX_features]
wy = re_whole_f['deposit']

model_dtw = DecisionTreeClassifier(random_state = 42, max_depth = 70)
model_dtw.fit(wX, wy)
y_dtw_pred = model_dtw.predict(wX)

get_score('dt', wy, y_dtw_pred)
#dt acc 스코어는:  0.887 f1_score(macro)는 : 0.804





#전월세 통합(개별 입력) 적정가격 알려주는 알고리즘
#api 통한 최신 데이터의 경우 분기에 20233 입력(이후 인구데이터 없음)
#전세의 경우 보증금에 'X' 등 아무 임의의 값 입력

district_df = pd.read_csv('C:/Users/neddy/Desktop/스파르타 코딩클럽/프로젝트/심화 프로젝트/머신러닝/최종집 선정용/최종선전용데이터.csv')  

def showmetheprice(type, 보증금, 건물용도, 면적, 연식, 동이름, 분기):      
    r_size = np.array([면적]).reshape(-1, 1)
    scaled_size = st_sc1.transform(r_size)   # 사이즈 전처리
    r_building = np.array([건물용도]).reshape(-1, 1)
    labeled_building = le.transform(r_building)  # 건물 전처리
    house_df = pd.DataFrame([[type, 보증금, scaled_size[0][0], labeled_building[0], 연식]],
                            columns=['type', 'deposit', 'size_sc', 'le건물', '연식'])
    dfr = district_df.query('add2 == @동이름 & 분기 == @분기').reset_index()   # 동이름 및 분기에 따라 맞는 동데이터 추출
    dfr = dfr.copy()
    dfr['소득_sc'] = st_sc2.transform(dfr[['평균소득']])         #동데이터 전체 전처리
    dfr['mm여성비중'] = mm_sc1.transform(dfr[['여성인구비중']])
    dfr['mm청년비중'] = mm_sc2.transform(dfr[['청년인구비중']])
    dfr['mm청년중여성비중'] = mm_sc3.transform(dfr[['청년중여성비중']])
    dfr['mm전체중청년여성비중'] = mm_sc4.transform(dfr[['전체중청년여성비중']])
    dfr['mm직장인구밀도'] = mm_sc5.transform(dfr[['직장인구밀도']])
    dfr['mm2030상주인구비중'] = mm_sc6.transform(dfr[['2030상주인구비중']])
    x_temp = ['전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중', 'mm전체중청년여성비중', 'mm직장인구밀도', '소득_sc', 'mm2030상주인구비중', '지하철점수', '복합문화공간']
    x_temp2 = dfr[x_temp]  # 동정보사용할것들추리기
    final = pd.concat([house_df, x_temp2], axis=1)
    if type == '월세':
        X_features_f = ['deposit', 'le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
        final_f = final[X_features_f]
        predicted_price = model_rf.predict(final_f)
        print("적정 월세는:", predicted_price, "입니다")
    if type == '전세':
        X_features_f = ['le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
        final_f = final[X_features_f]
        predicted_price = model_dtw.predict(final_f)
        print("적정 전세는:", predicted_price, "입니다")





#조건(희망 동, 전월세type, 예산)에 맞게 추천 부동산 리스트 보여주는 알고리즘 : 일부 미완성
import pandas as pd
import numpy as np

houses_df = pd.read_csv('C:/Users/neddy/Desktop/스파르타 코딩클럽/프로젝트/심화 프로젝트/머신러닝/최종집 선정용/전월세가통합.csv')
district_df = pd.read_csv('C:/Users/neddy/Desktop/스파르타 코딩클럽/프로젝트/심화 프로젝트/머신러닝/최종집 선정용/최종선전용데이터.csv')  

def showmetheproperhouses(희망법정동명, 희망전월세type, 보증금예산, 월세예산):    #보증금예산 상하 10% 월세 10%
    # if 희망법정동명 == '강일동': 이렇게 하면 안 됨!!!
    #     희망법정동명 = '통합(강일동/상일동)'
    # if 희망법정동명 == '상일동':
    #     희망법정동명 = '통합(강일동/상일동)'
    # if 희망법정동명 == '신설동':
    #     희망법정동명 = '통합(신설동/용두동)'
    # if 희망법정동명 == '용두동':
    #     희망법정동명 = '통합(신설동/용두동)'
    global district_df                
    rdistrict_df = district_df.query('add2 == @희망법정동명')   #동데이터 필터링
    global houses_df  #  부동산데이터 전역 변수임을 명시
    rhouses_df = houses_df.query('법정동명 == @희망법정동명')
    main_features = ['법정동명', '전월세구분', '임대면적', '보증금(만원)', '임대료(만원)', '건물명', '건축년도', '건물용도', '계약일']
    rhouses_df = rhouses_df[main_features]
    rhouses_df = rhouses_df.rename(columns={'임대면적': 'size', '보증금(만원)': 'deposit', '건물용도' : 'building'})
    rhouses_df['계약일'] = pd.to_datetime(rhouses_df['계약일'], format='%Y%m%d')
    rhouses_df['건축년도'] = pd.to_datetime(rhouses_df['건축년도'], format='%Y')
    rhouses_df['연식'] = rhouses_df['계약일'].dt.year - rhouses_df['건축년도'].dt.year
    rhouses_df = rhouses_df.dropna(subset=['연식'])
    month_to_quarter = {
        1: 20221, 2: 20221, 3: 20221,
        4: 20222, 5: 20222, 6: 20222,
        7: 20223, 8: 20223, 9: 20223,
        10: 20224, 11: 20224, 12: 20224,
        13: 20231, 14: 20231, 15: 20231,
        16: 20232, 17: 20232, 18: 20233,
        19: 20231, 20: 20231, 21: 20231
    }
    rhouses_df = rhouses_df
    rhouses_df['분기'] = rhouses_df['계약일'].apply(lambda x: month_to_quarter.get(x.month, np.nan))
    # rhouses_df.loc[rhouses_df['법정동명'] == '신설동', '법정동명'] = '통합(신설동/용두동)'
    # rhouses_df.loc[rhouses_df['법정동명'] == '용두동', '법정동명'] = '통합(신설동/용두동)'
    # rhouses_df.loc[rhouses_df['법정동명'] == '강일동', '법정동명'] = '통합(강일동/상일동)'
    # rhouses_df.loc[rhouses_df['법정동명'] == '상일동', '법정동명'] = '통합(강일동/상일동)'
    rhouses_df = pd.merge(rhouses_df, rdistrict_df, left_on = ['법정동명', '분기'], right_on = ['add2', '분기'] )   #api할 경우 분기 데이터 맞출 필요 없음(2023년 3분기 외부데이터로 하면 됨)
    rhouses_df['size_sc'] = st_sc1.transform(rhouses_df[['size']])           #전체 전처리
    rhouses_df['소득_sc'] = st_sc2.transform(rhouses_df[['평균소득']])
    rhouses_df['le건물'] = le.transform(rhouses_df[['building']])
    rhouses_df['mm여성비중'] = mm_sc1.transform(rhouses_df[['여성인구비중']])
    rhouses_df['mm청년비중'] = mm_sc2.transform(rhouses_df[['청년인구비중']])
    rhouses_df['mm청년중여성비중'] = mm_sc3.transform(rhouses_df[['청년중여성비중']])
    rhouses_df['mm전체중청년여성비중'] = mm_sc4.transform(rhouses_df[['전체중청년여성비중']])
    rhouses_df['mm직장인구밀도'] = mm_sc5.transform(rhouses_df[['직장인구밀도']])
    rhouses_df['mm2030상주인구비중'] = mm_sc6.transform(rhouses_df[['2030상주인구비중']])
    if 희망전월세type == '월세':
        rrhouses_df = rhouses_df.query('전월세구분 == "월세" & @보증금예산*0.9 <= deposit <= @보증금예산*1.1 & @월세예산*0.9 <= `임대료(만원)` <= @월세예산*1.1')
        rx_features = ['deposit', 'le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
        x_rhouses = rrhouses_df[rx_features]
        rrhouses_df['예상적정가'] = model_rf.predict(x_rhouses)
        rrhouses_df['차이'] = rrhouses_df['임대료(만원)'] - rrhouses_df['예상적정가']
        rentfeatures = ['법정동명', '전월세구분', 'size', '건물명', '연식', 'building', 'deposit', '임대료(만원)', '예상적정가', '차이']
        rrhouses_df = rrhouses_df[rentfeatures].rename(columns = {'deposit' : '보증금(만원)', 'size' : '면적', 'building' : '건물용도'})  #절대값 정렬 해줘야함
        rrhouses_df = rrhouses_df.sort_values(by=['차이', '임대료(만원)', '연식']).sort_values(by = ['면적'], ascending = False)
        rrhouses_df = rrhouses_df.reindex(rrhouses_df['차이'].abs().sort_values().index)
    if 희망전월세type == '전세':
        rrhouses_df = rhouses_df.query('전월세구분 == "전세" & @보증금예산*0.9 <= deposit <= @보증금예산*1.1').head()
        rx_features = ['le건물', 'size_sc', '연식', '전분기대비인구증감률', 'mm여성비중', 'mm청년비중', 'mm청년중여성비중',	'mm전체중청년여성비중',	'mm직장인구밀도',	'소득_sc',	'mm2030상주인구비중', '지하철점수', '복합문화공간']
        x_rhouses = rrhouses_df[rx_features]
        rrhouses_df['예상적정가'] = model_dtw.predict(x_rhouses)
        rrhouses_df['차이'] = rrhouses_df['deposit'] - rrhouses_df['예상적정가']
        leasefeatures = ['법정동명', '전월세구분', 'size', '건물명', '연식', 'building', 'deposit', '임대료(만원)', '예상적정가', '차이']
        rrhouses_df = rrhouses_df[leasefeatures].rename(columns = {'deposit' : '보증금(만원)', 'size' : '면적', 'building' : '건물용도'})
        rrhouses_df = rrhouses_df.sort_values(by=['차이', '연식']).sort_values(by = ['면적'], ascending = False)
        rrhouses_df = rrhouses_df.reindex(rrhouses_df['차이'].abs().sort_values().index)  #절대값 정렬 해줘야함
    return rrhouses_df.head()

 
 
대충 장장 일주일을 바친 흔적.
전처리에만 꼬박 나흘 걸리고
그러고서 코딩하는데 잔 에러 때문에 마찬가지로 삼사일 걸린듯ㅋㅋㅋㅋ
 
 
해놓고 나니 진짜 성장한거 같음

'TIL 통합' 카테고리의 다른 글

02/21 수요일 Til  (0) 2024.02.21
02/20 Til  (0) 2024.02.20
2/15 심화 프로젝트ing  (0) 2024.02.15
2/14  (0) 2024.02.14
02/13  (0) 2024.02.13