일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- skip connection
- numpy
- 백준
- feature map
- 정규화
- 인접행렬
- SQLD 후기
- SQLD
- 엔터티
- BFS
- get_dummies()
- depthwise convolution
- 식별자
- 인접리스트
- resnet
- Two Pointer
- pytorch
- Depthwise Separable Convolution
- dp
- 1x1 Convolution
- dfs
- 그래프
- bottleneck
- 데이터모델링
- mobilenet
- Inductive Bias
- outer join
- SQL
- CROSS JOIN
- 연산량 감소
- Today
- Total
SJ_Koding
01. [Dacon basic], 펭귄 몸무게 예측 경진대회 참가 코드[최종 26위 / 725명, private score : 308.10401(RMSE)] 본문
01. [Dacon basic], 펭귄 몸무게 예측 경진대회 참가 코드[최종 26위 / 725명, private score : 308.10401(RMSE)]
성지코딩 2022. 1. 6. 15:52저는 오늘 처음으로 Dacon AI경진대회를 참가해보았습니다.
주제는 펭귄 몸무게 예측으로, 머신러닝 입문자를 위한 Basic 대회입니다. (작성일 기준, 저한테 맞는 수준입니다 ㅎ)
https://dacon.io/competitions/official/235862/overview/description
구글 코랩에서 CPU환경으로 진행을 하였으며 skleran 모듈을 이용하여 모델을 구성했습니다.
또한 평가 지표로 RMSE를 사용합니다. Mean Squared Error에 Root를 씌운 값으로 평가를 진행합니다.
데이터는 3개의 csv파일로 주어집니다.
1. train.csv : 학습 데이터
- id : 샘플 아이디
- Species: 펭귄의 종을 나타내는 문자열
- Island : 샘플들이 수집된 Palmer Station 근처 섬 이름
- Clutch Completion : 관찰된 펭귄 둥지의 알이 2개인 경우 Full Clutch이며 Yes로 표기
- Culmen Length (mm) : 펭귄 옆모습 기준 부리의 가로 길이
- Culmen Depth (mm) : 펭귄 옆모습 기준 부리의 세로 길이
- Flipper Length (mm) : 펭귄의 팔(날개) 길이
- Sex : 펭귄의 성별
- Delta 15 N (o/oo) : 토양에 따라 변화하는 안정 동위원소 15N:14N의 비율
- Delta 13 C (o/oo) : 먹이에 따라 변화하는 안정 동위원소 13C:12C의 비율
- Body Mass (g): 펭귄의 몸무게를 나타내는 숫자 (g)
2. test.csv : 테스트 데이터
- id : 샘플 아이디
- Species: 펭귄의 종을 나타내는 문자열
- Island : 샘플들이 수집된 Palmer Station 근처 섬 이름
- Clutch Completion : 관찰된 펭귄 둥지의 알이 2개인 경우 Full Clutch이며 Yes로 표기
- Culmen Length (mm) : 펭귄 옆모습 기준 부리의 가로 길이
- Culmen Depth (mm) : 펭귄 옆모습 기준 부리의 세로 길이
- Flipper Length (mm) : 펭귄의 팔(날개) 길이
- Sex : 펭귄의 성별
- Delta 15 N (o/oo) : 토양에 따라 변화하는 안정 동위원소 15N:14N의 비율
- Delta 13 C (o/oo) : 먹이에 따라 변화하는 안정 동위원소 13C:12C의 비율
3. sample_submissoin.csv : 제출 양식
- id : 샘플 아이디
- Body Mass (g) : 펭귄의 몸무게를 나타내는 숫자 (g)
데이터 상세 설명
- 성인 Adélie, Chinstrap 및 Gentoo 펭귄의 둥지 관찰, 펭귄 크기 데이터 및 혈액 샘플의 동위원소 측정을 포함한 데이터입니다.
- 남극의 Palmer Station 근처 Palmer 군도에 있는 섬에서 관찰된 Adélie, chinstrap, Gentoo 펭귄의 먹이를 찾는 성체의 크기 측정, 클러치 관찰 및 혈액 동위원소 비율.
- 데이터는 Kristen Gor man 박사와 Palmer Station Long Term Ecological Research(LTER) 프로그램에 의해 수집되어 제공되었습니다.
- 출처: https://allisonhorst.github.io/palmerpenguins/
코드 설명
1. 데이터 로드 및 결측치 확인
먼저 df.read_csv()
함수를 통해 데이터를 DataFrame으로 변환시킵니다.
구글 Colab 환경에서 진행을 했기 때문에, Google Drive Mount를 통해 데이터를 저장하고 불러왔습니다. 따라서 경로는 알맞게 수정해주어야 합니다.
import pandas as pd
df_train = pd.read_csv('/content/drive/MyDrive/dacon/penguin_weight_predict/train.csv')
df_test = pd.read_csv('/content/drive/MyDrive/dacon/penguin_weight_predict/test.csv')
df_train.info(), df_test.info()
일단 info()함수를 통해 데이터를 조회했을 때, non-null Count가 다른 부분이 있다면, 결측치 (NaN)값이 존재한다는 것을 확인할 수 있습니다.
결측치가 몇 개인지 조회하려면 isna()
와 sum()
함수를 사용합니다. 그리고 그 전에 id컬럼을 제거하라는 공지가 있어 id컬럼을 삭제하는 작업도 진행합니다. (df_train과 df_test 둘 다 적용시켜줍니다.)
df_train.drop('id', axis=1, inplace = True) # id는 제외하고 분석
df_test.drop('id', axis=1, inplace = True)
print(f'df_train 결측치 조회\n{df_train.isna().sum()}')
print(f'df_test 결측치 조회\n{df_test.isna().sum()}')
출력 결과를 보면, 'Sex', 'Delta 15 N (o/oo)', 'Delta 13 C (o/oo)' 에 대하여 결측치가 존재하는 것을 볼 수 있습니다.
train셋에는 총 9개, test셋에는 총 23개의 결측치가 존재하는 것을 확인했습니다.
2. 데이터 결측치 처리 및 범주형 데이터 처리 (pd.get_dummies())
머신러닝에서 결측치는 항상 처리해주어야합니다. 저는 'Delta @'에 대해서는 평균값 대체, 'Sex'에 대해 행 삭제 기법을 사용하였습니다.
df_train.fillna(df_train.mean(), inplace=True)
df_test.fillna(df_train.mean(), inplace=True)
temp_train = df_train.dropna()
temp_test = df_test.dropna()
코드를 보면 해당 결측치가 존재하는 컬럼에 mean값을 채워주어 결측치를 처리하고
그 후에 결측치의 행 (axis = 0)을 제거하면 어차피 'Sex' 컬럼의 결측치만 남아있는 상태로 3개의 행이 삭제될 것입니다.
따라서 출력결과를 보면 결측치가 더 이상 존재하지 않습니다.
test셋에서도 동일하게 적용 하지만 'Sex'컬럼에 대한 행 삭제를 진행하지 않았습니다. 앞서 설명드린 데이터 중 sample_submission.csv파일의 행 개수와 달라지기 때문에 평가를 진행할 수 없었습니다. 따라서 'Sex'가 결측치 인 경우 모두 'MALE'로 변환시켜주었습니다. 'Sex'에 따른 몸무게는 충분히 의미가 있을 거라 생각했습니다. 따라서 보간법의 개념을 추가하였습니다.
X_train_Sex = temp_train.select_dtypes(include=['int', 'float'])
X_train_Sex = X_train_Sex.drop('Body Mass (g)', axis=1)
Y_train_Sex = temp_train['Sex']
from sklearn.model_selection import train_test_split
sex_x_train, sex_x_test, sex_y_train, sex_y_test = train_test_split(X_train_Sex, Y_train_Sex
)
from sklearn.ensemble import RandomForestClassifier
model_sex = RandomForestClassifier().fit(sex_x_train, sex_y_train)
model_sex.score(sex_x_test, sex_y_test)
0.8571428571428571
df_train.loc[df_train['Sex'].isna(), 'Sex'] = \
model_sex.predict(df_train[df_train['Sex'].isna()].select_dtypes(include=['int', 'float']).drop('Body Mass (g)', axis=1))
df_test.loc[df_test['Sex'].isna(), 'Sex'] = \
model_sex.predict(df_test[df_test['Sex'].isna()].select_dtypes(include=['int', 'float']))
한 줄로 동시에 쓰느랴 복잡해 보이지만, 'Sex'에 대해 학습된 model_sex의 predict를 사용하여 값을 가져와 대입시켜주었습니다. 여기서 select_dtypes는 지정된 열의 타입만 가져오게 됩니다. 저는 int형과 float형을 추출하였고, test셋에는 'Body Mass (g)' 컬럼이 없기 때문에, 이를 포함하여 학습을 시키면 안됩니다. 따라서 drop을 통해 해당 열을 제거하였습니다.
temp_train.loc[df_train['Sex'] == 'MALE', 'Sex'] = 0
temp_train.loc[df_train['Sex'] == 'FEMALE', 'Sex'] = 1
그 후, 성별에 대해 'MALE'은 0, 'FEMALE'은 1로 지정하였습니다.
df_train = pd.get_dummies(df_train)
df_test = pd.get_dummies(df_test)
pd.get_dummies함수는 정형 데이터에 대해 자동으로 One-Hot인코딩을 진행해주는 똑똑한 함수입니다.
X = df_train.drop('Body Mass (g)', axis=1)
Y = df_train['Body Mass (g)']
X 출력
Y 출력
3. 데이터 분할 및 여러 개의 모델 학습, 선택
from sklearn.neighbors import KNeighborsRegressor
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.1)
모델의 선택은 시행착오라고 배웠습니다. 다양한 모델의 성능을 확인하고 모델을 선택해보겠습니다.
model = KNeighborsRegressor(n_neighbors=5).fit(x_train, y_train)
score_List.append(f'KNeighborsRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = LinearRegression().fit(x_train, y_train)
score_List.append(f'LinearRegression: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = Ridge().fit(x_train, y_train)
score_List.append(f'Ridge: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = Lasso().fit(x_train, y_train)
score_List.append(f'Lasso: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = DecisionTreeRegressor().fit(x_train, y_train)
score_List.append(f'DecisionTreeRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = RandomForestRegressor().fit(x_train, y_train)
score_List.append(f'RandomForestRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = GradientBoostingRegressor().fit(x_train, y_train)
score_List.append(f'GradientBoostingRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = XGBRegressor().fit(x_train, y_train)
score_List.append(f'XGBRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
model = LGBMRegressor().fit(x_train, y_train)
score_List.append(f'LGBMRegressor: train_score: {model.score(x_train, y_train)}, val_score: {model.score(x_test, y_test)}')
[print(i) for i in score_List]
train_score가 아닌 val_score를 봐주셔야합니다.
LinearRegression, Ridge, Lasso, LGBMRegressor 등등이 성능이 좋게 나온 것을 확인할 수 있었습니다.
4. 데이터 앙상블 (LinearRegression, Ridge, Lasso)
model_LR = LinearRegression().fit(X, Y)
model_RID = Ridge().fit(X, Y)
model_LA = Lasso().fit(X, Y)
model_LGBM = LGBMRegressor().fit(X, Y)
model_XGB = XGBRegressor().fit(X, Y)
제가 선택한 모델 5개에 대하여, 분할된 셋이 아닌 기존 셋을 통해 모델 학습을 진행해 줍니다.
pred_LR = model_LR.predict(df_test)
pred_RID = model_RID.predict(df_test)
pred_LA = model_LA.predict(df_test)
pred_LGBM = model_LGBM.predict(df_test)
pred_XGB = model_XGB.predict(df_test)
pred = pred_LR*0.2 + pred_RID*0.2 + pred_LA*0.2 + pred_LGBM*0.2 + pred_XGB*0.2
그 후 predict의 값을 구하고, 적절한 비율로 곱한 후 모두 더함으로써 모델 앙상블을 진행하였습니다.
submission = pd.read_csv('/content/drive/MyDrive/dacon/penguin_weight_predict/submission.csv')
submission['Body Mass (g)'] = pred
submission.to_csv('/content/drive/MyDrive/dacon/penguin_weight_predict/submission.csv', index=False)
submission
그 후 submission에 대입하고 사이트에 제출하였습니다.
스코어는 275.71371이 나왔으며 684명중 18위를 기록했습니다.
첫 AI경진대회를 참가해보았습니다. Basic난이도였기에 가능했습니다. 하지만 앞으로 발전하기 위한 첫 걸음이므로 큰 의미가 있다고 생각합니다.
감사합니다.
-sjkoding-
'AI Competition' 카테고리의 다른 글
05. [Dacon Basic] 항공사 고객 만족도 예측 경진대회 (최종 2등!!) (1) | 2022.02.08 |
---|---|
04. [Dacon Basic] 집값 예측 경진대회 (0) | 2022.02.08 |
03.[Dacon Basic] 영화 리뷰 감정분석 경진대회 (최종39위 / 605명) (1) | 2022.01.20 |
02. [Dacon 교육] Fashion MNIST : 의류 클래스 예측 (csv파일)아주 쉽게 따라하기. (Pytorch 이용) (0) | 2022.01.14 |