<jupyter_start><jupyter_text>"AI Competition to Predict Parking Demand"> "[DACON]"- toc:true- branch: master- badges: true- comments: true- author: <NAME> & <NAME>- categories: [Colab, DACON Contest]  1.Library & Data Load<jupyter_code>from google.colab import drive
drive.mount('/content/drive')      
# !mkdir "/content/drive/MyDrive/DACON/Data/AI Competition to Predict Parking Demand"
# !mkdir "/content/drive/MyDrive/DACON/Data/AI Competition to Predict Parking Demand/submission"
# !unzip "/content/drive/MyDrive/DACON/Data/AI Competition to Predict Parking Demand.zip" -d "/content/drive/MyDrive/DACON/Data/AI Competition to Predict Parking Demand/"
import pandas as pd
import numpy as np
import os
from sklearn.impute import SimpleImputer
import seaborn as sns
from tqdm.notebook import tqdm
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder

from lightgbm import LGBMRegressor
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import GridSearchCV

# !sudo apt-get install -y fonts-nanum
# !sudo fc-cache -fv
# !rm ~/.cache/matplotlib -rf

plt.rc('font', family='NanumBarunGothic') 
%matplotlib inline
plt.rcParams['axes.unicode_minus'] = False # 한글 폰트 사용시 마이너스 폰트 깨짐 해결<jupyter_output><empty_output><jupyter_text>데이터 불러오기<jupyter_code>path='/content/drive/MyDrive/DACON/Data/AI Competition to Predict Parking Demand'
train = pd.read_csv(path+'/train.csv')
test = pd.read_csv(path+'/test.csv')
submission= pd.read_csv(path+'/sample_submission.csv')
age_gender_info=pd.read_csv(path+'/age_gender_info.csv')
#데이터 잘못된거 1번해결 전용면적별 세대수 다 더함
for code in tqdm(train.단지코드.unique()):
  train.loc[train[train.단지코드==code].index,('총세대수')]=train.loc[train[train.단지코드==code].index,('전용면적별세대수')].sum()
  
for code in tqdm(test.단지코드.unique()):
  test.loc[test[test.단지코드==code].index,('총세대수')]=test.loc[test[test.단지코드==code].index,('전용면적별세대수')].sum()  
#데이터 잘못된거 2번해결
train.loc[train[train.단지코드=='C1397'].index,('단지코드')]='C2085'
train.loc[train[train.단지코드=='C2085'].index,('총세대수')]=train.loc[train[train.단지코드=='C2085'].index,('총세대수')].unique().sum()

train.loc[train[train.단지코드=='C1649'].index,('단지코드')]='C2431'
train.loc[train[train.단지코드=='C2431'].index,('총세대수')]=train.loc[train[train.단지코드=='C2431'].index,('총세대수')].unique().sum()
train.loc[train[train.단지코드=='C2431'].index,('등록차량수')]=train.loc[train[train.단지코드=='C2431'].index,('등록차량수')].unique().sum()

test.loc[test[test.단지코드=='C1036'].index,('단지코드')]='C2675'
test.loc[test[test.단지코드=='C2675'].index,('총세대수')]=1254
train.loc[train.임대료=='-'].단지코드.unique()
test[test.임대료=='-'].단지코드.unique()
#데이터 잘못된거 3번해결
test[test.임대료=='-'].단지코드.unique()
drop_list=['C1095', 'C2051', 'C1218', 'C1894', 'C2483', 'C1502', 'C1988','C2085']
for code in drop_list:
  _index=train[train.단지코드==code].index
  train=train.drop(_index)
data=pd.concat([train,test]).reset_index(drop=True)
data.loc[data.임대보증금=='-','임대보증금']=np.nan
data.loc[data.임대료=='-','임대료']=np.nan
data.임대보증금=data.임대보증금.fillna(-1)
data.임대료=data.임대료.fillna(-1)
data=data.astype({'임대보증금':'int', '임대료':'int'})
data.loc[data.임대료==-1,'임대료']=np.nan
data.loc[data.임대보증금==-1,'임대보증금']=np.nan
data.isnull().sum()
data.describe()<jupyter_output><empty_output><jupyter_text>함수<jupyter_code>def fillna_(df, na_columns, method):
  imp = SimpleImputer(missing_values = np.nan, strategy = method)
  for col in na_columns:
    df[col] = imp.fit_transform(df[[col]])
  return df
def code_dupli(data,col):
  num =[]
  for code in data.단지코드:
    num.append(data.loc[data.단지코드==code,col].unique().shape[0])
  plt.hist(num)
  plt.title(col)<jupyter_output><empty_output><jupyter_text>2. Data 전처리  이산형데이터 탐색<jupyter_code>sns.countplot(x="임대건물구분", data=data)
plt.title("임대건물구분")
plt.show()
sns.countplot(x="공급유형", data=data)
plt.title("공급유형")
plt.show()
sns.countplot(x="자격유형", data=data)
plt.title("자격유형")
plt.show()
code_dupli(data,'임대건물구분')
code_dupli(data,'지역')
code_dupli(data,'공급유형')
code_dupli(data,'자격유형')
pd.crosstab(data['공급유형'], data['자격유형'], margins=True).style.background_gradient(cmap='summer_r')<jupyter_output><empty_output><jupyter_text>위의 그래프는 각 단지의 column별 종류의 개수를 히스토그램으로 나타낸 것이다.임대건물구분, 공급유형, 자격유형은 하나의 단지의 여러 종류의 유형이 들어가 있음을 알 수 있다.위에 크로스탭을 보아 자격유형 (J,K,L,M,N,O), (B,G,H), (C,F,I) 묶고공급유형(공공임대(10년), 공공임대(50년), 공공임대(5년), 공공임대(분납), 장기전세), (임대상가, 공공분양) 이렇게 다시 범주화 한다.)<jupyter_code>data.loc[(data.자격유형=='J')|(data.자격유형=='K')|(data.자격유형=='L')|(data.자격유형=='M')|(data.자격유형=='N')|(data.자격유형=='O'),'자격유형']='JKLMNO'
data.loc[(data.자격유형=='B')|(data.자격유형=='G')|(data.자격유형=='H'),'자격유형']='BGH'
data.loc[(data.자격유형=='C')|(data.자격유형=='F')|(data.자격유형=='I'),'자격유형']='CFI'

data.loc[(data.공급유형=='공공임대(5년)')|(data.공급유형=='공공임대(10년)')|(data.공급유형=='공공임대(50년)')|(data.공급유형=='공공임대(분납)')|(data.공급유형=='장기전세'),'공급유형']='공공임대_장기전세'
data.loc[(data.공급유형=='임대상가')|(data.공급유형=='공공분양'),'공급유형']='임대상가_공공분양'<jupyter_output><empty_output><jupyter_text>연속형 변수 탐색<jupyter_code>plt.boxplot(data[['전용면적']].dropna().values, notch=True)
plt.xticks([1],['전용면적'])
plt.boxplot(data[['임대보증금']].dropna().values, notch=True)
plt.xticks([1],['임대보증금'])
plt.boxplot(data[['임대료']].dropna().values, notch=True)
plt.xticks([1],['임대료'])
data[['전용면적','임대보증금','임대료','도보 10분거리 내 지하철역 수(환승노선 수 반영)','도보 10분거리 내 버스정류장 수','단지내주차면수']].describe()<jupyter_output><empty_output><jupyter_text>이상치 처리<jupyter_code>#이상치 제거 대충
data.loc[data.전용면적>200,'전용면적']=200
data.loc[data.임대보증금>150000000,'임대보증금']=150000000
data.loc[data.임대료>800000,'임대료']=800000<jupyter_output><empty_output><jupyter_text><jupyter_code>#지하철 변수를 지하철의 유 무
#버스 정류장 개수를 1, 2, 3, 4, 5 이상으로 재범주화

data.loc[data['도보 10분거리 내 지하철역 수(환승노선 수 반영)']==0,'도보 10분거리 내 지하철역 수(환승노선 수 반영)']='무'
data.loc[data['도보 10분거리 내 지하철역 수(환승노선 수 반영)']!='무','도보 10분거리 내 지하철역 수(환승노선 수 반영)']='유'
data.loc[data['도보 10분거리 내 버스정류장 수']>=5,'도보 10분거리 내 버스정류장 수']='5 이상'
# LabelEncoder를 이용하여 지역, 지하철, 버스 라벨 인코더

data['지역'] = LabelEncoder().fit_transform(data['지역'])
data['도보 10분거리 내 지하철역 수(환승노선 수 반영)'] = LabelEncoder().fit_transform(data['도보 10분거리 내 지하철역 수(환승노선 수 반영)'].astype(str))
data['도보 10분거리 내 버스정류장 수'] = LabelEncoder().fit_transform(data['도보 10분거리 내 버스정류장 수'].astype(str))<jupyter_output><empty_output><jupyter_text>결측치 처리<jupyter_code>data.isnull().sum()<jupyter_output><empty_output><jupyter_text>data의 결측값을 확인했더니  임대보증금, 임대료, 도보 10분거리 내 지하철역 수(환승노선 수 반영), 도보 10분거리 내 버스정류장 수 변수에 결측값이 존재한다<jupyter_code>#임대보증금, 임대료 결측치 처리
data.loc[(data.자격유형!='D')&(data.임대료.isna())].단지코드.unique()
na_rent=data.loc[data.임대료.isna()]
na_security_deposit=data.loc[data.임대보증금.isna()]
for i in na_rent.index:
  data.loc[i,'임대료'] = data.loc[(data.임대건물구분==na_rent.임대건물구분[i]) & (data.공급유형==na_rent.공급유형[i]) & (data.자격유형==na_rent.자격유형[i]) & (data.지역==na_rent.지역[i]) & (data.전용면적>=na_rent.전용면적[i]-5) & (data.전용면적<=na_rent.전용면적[i]+5)].임대료.mean()

for i in na_security_deposit.index:
  data.loc[i,'임대보증금']  = data.loc[(data.임대건물구분==na_security_deposit.임대건물구분[i]) & (data.공급유형==na_security_deposit.공급유형[i]) & (data.자격유형==na_security_deposit.자격유형[i]) & (data.지역==na_security_deposit.지역[i]) & (data.전용면적>=na_security_deposit.전용면적[i]-5) & (data.전용면적<=na_security_deposit.전용면적[i]+5)].임대보증금.mean()
data.loc[(data.자격유형!='D')&(data.임대료.isna())].단지코드.unique()
data=data.loc[(data.단지코드!='C1326') & (data.단지코드!='C1786') & (data.단지코드!='C2186')]
#지하철역 수, 버스정류장 수 결측치는 최빈값으로 대체한다.
data=fillna_(data, ['자격유형','도보 10분거리 내 지하철역 수(환승노선 수 반영)','도보 10분거리 내 버스정류장 수'], 'most_frequent')<jupyter_output>/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  after removing the cwd from sys.path.
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  after removing the cwd from sys.path.
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:4: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See[...]<jupyter_text>데이터 변환<jupyter_code>df=data[['임대건물구분','공급유형','자격유형']].drop_duplicates().reset_index(drop=True)
for i in range(df.shape[0]):
  data[df.임대건물구분[i]+'_'+df.공급유형[i]+"_"+df.자격유형[i]]=0
for i in range(df.shape[0]):
  data.loc[(data.임대건물구분==df.임대건물구분[i])&(data.공급유형==df.공급유형[i])&(data.자격유형==df.자격유형[i]),df.임대건물구분[i]+'_'+df.공급유형[i]+"_"+df.자격유형[i]]=data.loc[(data.임대건물구분==df.임대건물구분[i])&(data.공급유형==df.공급유형[i])&(data.자격유형==df.자격유형[i]),'전용면적별세대수']
data['총 면적']=data.전용면적*data.전용면적별세대수
new_data=pd.DataFrame()
new_data=pd.concat([new_data,data.groupby('단지코드')['총 면적'].sum()],axis=1)
new_data=pd.concat([new_data,data.groupby('단지코드')['임대보증금'].sum()],axis=1)
new_data=pd.concat([new_data,data.groupby('단지코드')['임대료'].sum()],axis=1)
for i in range(df.shape[0]):
  new_data=pd.concat([new_data,data.groupby('단지코드')[df.임대건물구분[i]+'_'+df.공급유형[i]+"_"+df.자격유형[i]].sum()],axis=1)
data_1=data[['단지코드','총세대수','지역','공가수','도보 10분거리 내 지하철역 수(환승노선 수 반영)','도보 10분거리 내 버스정류장 수','단지내주차면수','등록차량수']].drop_duplicates('단지코드')
data_1.index=data_1.단지코드
data_1.drop('단지코드',axis=1,inplace=True)
final_data=pd.concat([data_1,new_data],axis=1)
final_data<jupyter_output><empty_output><jupyter_text>final_data 탐색<jupyter_code>final_data.describe()
# 공가율 파생변수 생성
final_data['공가율']=final_data.공가수/final_data.총세대수
discrete_variables=['지역','도보 10분거리 내 지하철역 수(환승노선 수 반영)',
       '도보 10분거리 내 버스정류장 수']
continuous_variable=['등록차량수','총세대수', '공가수', '단지내주차면수','총 면적', '임대보증금', '임대료', '공가율']
sns.pairplot(final_data.loc[:,continuous_variable])
plt.title("Continuous Variable")
plt.show()
#TrainSet과 Test으로 구분
new_train=pd.DataFrame()
new_test=pd.DataFrame()

for code in list(train.단지코드.unique()):
  new_train=new_train.append(final_data.loc[final_data.index==code])

for code in list(test.단지코드.unique()):
  new_test=new_test.append(final_data.loc[final_data.index==code])
sns.distplot(new_train['등록차량수'])<jupyter_output>/usr/local/lib/python3.7/dist-packages/seaborn/distributions.py:2619: FutureWarning: `distplot` is a deprecated function and will be removed in a future version. Please adapt your code to use either `displot` (a figure-level function with similar flexibility) or `histplot` (an axes-level function for histograms).
  warnings.warn(msg, FutureWarning)<jupyter_text>3. 모델링<jupyter_code>from sklearn.linear_model import ElasticNet, Lasso, LinearRegression, RidgeCV, Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV, cross_val_score, StratifiedKFold, KFold
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import VotingRegressor
from sklearn.preprocessing import StandardScaler
s_scaler=StandardScaler()
train_y=new_train['등록차량수']
train_X=new_train.drop('등록차량수',axis=1)
test_X=new_test.drop('등록차량수',axis=1)
X_train, X_test, y_train, y_test = train_test_split(train_X, train_y, test_size=0.1, random_state=12)<jupyter_output><empty_output><jupyter_text>회귀모델<jupyter_code>def cv_rmse(model,x,y):
    rmse = np.sqrt(-cross_val_score(model, s_scaler.fit_transform(x) , y, 
                                   scoring="neg_mean_squared_error", 
                                   cv = 5))
    return(rmse)

def ridge_selector(k,x,y):
    ridge_model = make_pipeline(RidgeCV(alphas = [k],
                                        cv=5)).fit(s_scaler.fit_transform(x), y)
    ridge_rmse = cv_rmse(ridge_model,x,y).mean()
    return(ridge_rmse)
r_alphas = [4.8,4.85,4.9,4.95,5,5.05,5.1]

ridge_scores = []
for alpha in r_alphas:
    score = ridge_selector(alpha, X_train, y_train)
    ridge_scores.append(score)
    
plt.plot(r_alphas, ridge_scores, label='Ridge')
plt.legend('center')
plt.xlabel('alpha')
plt.ylabel('score')

ridge_score_table = pd.DataFrame(ridge_scores, r_alphas, columns=['RMSE'])
ridge_score_table
RIDGE=Ridge(alpha=4.95,random_state=12)
RIDGE.fit(s_scaler.fit_transform(X_train),y_train)
pred_RIDGE=RIDGE.predict(s_scaler.fit_transform(X_test))<jupyter_output><empty_output><jupyter_text>부스팅,  붓스트랩 트리<jupyter_code>from sklearn.linear_model import  Ridge, Lasso
from xgboost import XGBRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import mean_squared_error
from xgboost import plot_importance
# 데이터를 로딩하고 학습데이타와 테스트 데이터 분리

XGB = XGBRegressor()
RF = RandomForestRegressor()

XGB_param = {
    'learning_rate':[0.1,0.2], 
    'n_estimators':[100,150,200],
    'max_depth':[2,4,6,8], 
    'subsample':[0.5,0.7,0.9], 
    'colsample_bytree':[0.5,0.7,0.9],
    'min_samples_split':[2,3]
    }
RF_param = {
    'n_estimators':[100,150,200],
    'max_depth':[2,4,6,8], 
    'min_samples_leaf':[2,3],
    'min_samples_split':[2,3,4]
    }
### refit=True 가 default 임. True이면 가장 좋은 파라미터 설정으로 재 학습 시킴.  
grid_XGB = GridSearchCV(XGB, param_grid=XGB_param, cv=5, refit=True, return_train_score=True,
                        scoring='neg_mean_squared_error')
grid_XGB.fit(X_train, y_train)

grid_RF = GridSearchCV(RF, param_grid=RF_param, cv=5, refit=True, return_train_score=True,
                       scoring='neg_mean_squared_error')
grid_RF.fit(X_train, y_train)

# GridSearchCV 결과는 cv_results_ 라는 딕셔너리로 저장됨. 이를 DataFrame으로 변환
scores_df_XGB = pd.DataFrame(grid_XGB.cv_results_)
scores_df_RF = pd.DataFrame(grid_RF.cv_results_)
scores_df_XGB.mean_test_score=np.sqrt(-scores_df_XGB.mean_test_score)
scores_df_XGB.std_train_score=np.sqrt(scores_df_XGB.std_train_score)
scores_df_XGB.split0_test_score=np.sqrt(-scores_df_XGB.split0_test_score)
scores_df_XGB.split1_test_score=np.sqrt(-scores_df_XGB.split1_test_score)
scores_df_XGB.split2_test_score=np.sqrt(-scores_df_XGB.split2_test_score)
scores_df_XGB.split3_test_score=np.sqrt(-scores_df_XGB.split3_test_score)
scores_df_XGB.split4_test_score=np.sqrt(-scores_df_XGB.split4_test_score)

scores_df_RF.mean_test_score=np.sqrt(-scores_df_RF.mean_test_score)
scores_df_RF.std_train_score=np.sqrt(scores_df_RF.std_train_score)
scores_df_RF.split0_test_score=np.sqrt(-scores_df_RF.split0_test_score)
scores_df_RF.split1_test_score=np.sqrt(-scores_df_RF.split1_test_score)
scores_df_RF.split2_test_score=np.sqrt(-scores_df_RF.split2_test_score)
scores_df_RF.split3_test_score=np.sqrt(-scores_df_RF.split3_test_score)
scores_df_RF.split4_test_score=np.sqrt(-scores_df_RF.split4_test_score)
scores_df_XGB[['rank_test_score','params', 'mean_test_score','std_train_score',  
           'split0_test_score', 'split1_test_score', 'split2_test_score', 'split3_test_score', 'split4_test_score']].sort_values('rank_test_score').head(5)
scores_df_RF[['rank_test_score','params', 'mean_test_score','std_train_score',  
           'split0_test_score', 'split1_test_score', 'split2_test_score', 'split3_test_score', 'split4_test_score']].sort_values('rank_test_score').head(5)
print('XGB GridSearchCV 최적 파라미터:', grid_XGB.best_params_)
print('XGB GridSearchCV 최고 정확도: {0:.4f}'.format(np.sqrt(-grid_XGB.best_score_)))

print('RF GridSearchCV 최적 파라미터:', grid_RF.best_params_)
print('RF GridSearchCV 최고 정확도: {0:.4f}'.format(np.sqrt(-grid_RF.best_score_)))


# refit=True로 설정된 GridSearchCV 객체가 fit()을 수행 시 학습이 완료된 Estimator를 내포하고 있으므로 predict()를 통해 예측도 가능. 
pred_XGB = grid_XGB.predict(X_test)
pred_RF = grid_RF.predict(X_test)

print('XGB : 테스트 데이터 세트 정확도: {0:.4f}'.format(np.sqrt(mean_squared_error(y_test,pred_XGB))))
print('RF : 테스트 데이터 세트 정확도: {0:.4f}'.format(np.sqrt(mean_squared_error(y_test,pred_RF))))
print('RIDGE : 테스트 데이터 세트 정확도: {0:.4f}'.format(np.sqrt(mean_squared_error(y_test,pred_RIDGE))))
votingC = VotingRegressor(estimators=[('XGB',grid_XGB.best_estimator_),('RF',grid_RF.best_estimator_) ,('Ridge', RIDGE)], n_jobs=-1)
votingC = votingC.fit(s_scaler.fit_transform(X_train),y_train)
pred_voting=votingC.predict(s_scaler.fit_transform(X_test))
plot_importance(grid_XGB.best_estimator_)
print('Voting : 테스트 데이터 세트 정확도: {0:.4f}'.format(np.sqrt(mean_squared_error(y_test,pred_voting))))<jupyter_output>Voting : 테스트 데이터 세트 정확도: 150.2447
{'fraction_non_alphanumeric': 0.17647418644482504, 'fraction_numerical': 0.022877416197700024, 'mean_word_length': 7.026018654884634, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 67, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '579082', 'license': 'Apache-2.0', 'n_tokens_mistral': 8280, 'n_tokens_neox': 9890, 'n_words': 968, 'path': '_notebooks/2021_12_31_AI_Competition_to_Predict_Parking_Demand.ipynb', 'repo_name': 'JoGyeongDeok/PigDuck', 'size': '16361'}