IT/Data 분석

[게 나이 예측] 선형회귀 베이스라인

송시 2023. 6. 3. 16:09
728x90

데이터 안에서 게의 나이를 예측 하는 kaggle 의 playground 에 참여해보았다.

 

https://www.kaggle.com/competitions/playground-series-s3e16

 

Regression with a Crab Age Dataset | Kaggle

 

www.kaggle.com

총 8개의 독립변수[피처]를 토대로 종속변수인 게의 나이를 예측하는 문제다.

 

문제의 평가 기준은 MAE(Mean Absolute Error) 로 예측한 값을 추축한다.

 

Error 를 측정하는 것이기 때문에 0에 가까울 수록 높은 예측력을 갖고 있게 된다.

 

변수는 다음과 같다. (Age 를 제외한 8개는 모두 독립변수)

Sex object 게의 성 (Male, Female, Intermediate)
Length float 게의 길이(feet 기준)
Diameter float 게의 지름(feet 기준)
Height float 게의 높이(feet 기준)
Weight float 게의 무게(ounces 기준)
Shucked Weight float 껍질 없는 무게(ounces 기준)
Viscera Weight float 장기 무게(ounces 기준)
Shell Weight float 껍질의 무게(ounces 기준)
Age int 게의 나이(달 기준)

MAE 이기 때문에 선형회귀로 베이스 라인을 잡아보고 빠르게 진행해보겠다.

 

path='/kaggle/input/playground-series-s3e16/'
train_df = pd.read_csv(path+'train.csv')
test_df = pd.read_csv(path+'test.csv')
sample_sub = pd.read_csv(path+'sample_submission.csv')

 

print(train_df.shape, test_df.shape)

(74051, 10) (49368, 9)

train_df 변수가 9개가 아닌 10개가 나왔고, test_df 는 8개가 아닌 9개가 나왔다. test_df 에는 예측하고자 하는 Age 가 없을 것이기에 train_df의 변수 - 1 이기 때문에 10 과 9가 나온 것이다.

 

train_df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 74051 entries, 0 to 74050
Data columns (total 10 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   id              74051 non-null  int64  
 1   Sex             74051 non-null  object 
 2   Length          74051 non-null  float64
 3   Diameter        74051 non-null  float64
 4   Height          74051 non-null  float64
 5   Weight          74051 non-null  float64
 6   Shucked Weight  74051 non-null  float64
 7   Viscera Weight  74051 non-null  float64
 8   Shell Weight    74051 non-null  float64
 9   Age             74051 non-null  int64  
dtypes: float64(7), int64(2), object(1)
memory usage: 5.6+ MB

id 값은 제거해도 독립변수와 연관이 없기에 제거하면 되고 제거 후엔 독립변수가 총 8개가 된다.

 

앞서 말했던 것 처럼 train_df, test_df 에 각각 id 를 제거하면 변수는 10 - 1 = 9(Age 포함), 9 - 1= 8 이 된다.

 

각 독립 변수의 고유한 값의 갯수가 몇개 있는지를 아는 것이 EDA 과정에서 중요한데 연속형 숫자를 가질 것으로 예상되는 변수들이 (무게, 길이)라 의미는 없을 것이고, Sex 정도만 고유한 값이 몇개 인지 확인해보자.

 

train_df['Sex'].unique()

array(['I', 'M', 'F'], dtype=object)

독립변수에 대해서 알아봤을 때 나왔던 M=Male, F=Female, I = Intermediate 가 나온다.

 

게에 대한 성별 관련 도메인을 공부해보았는데 Intermediate(중간의) 라고 할만큼 게의 성별이 애매한 경우가 없는 것 같더라.(Sexual dimorphism)

https://en.wikipedia.org/wiki/Crab

그냥 다른 말로 성별을 구별하지 못하고 데이터가 기록되었다 정도로 이해하면 될 것 같다.

 

object 형태로 저장되어 있기에 Sex 는 원 핫 인코딩으로 처리를 해본 후 가장 간단한 lineargression 으로 베이스 라인을 선택해보겠다.

 

all_data = pd.concat([train_df,test_df],ignore_index=True)
all_data = all_data.drop(columns='id')
all_data_encoding = pd.get_dummies(all_data)
print(all_data_drop.info())
print(all_data_drop.head())

 

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 123419 entries, 0 to 123418
Data columns (total 11 columns):
 #   Column          Non-Null Count   Dtype  
---  ------          --------------   -----  
 0   Length          123419 non-null  float64
 1   Diameter        123419 non-null  float64
 2   Height          123419 non-null  float64
 3   Weight          123419 non-null  float64
 4   Shucked Weight  123419 non-null  float64
 5   Viscera Weight  123419 non-null  float64
 6   Shell Weight    123419 non-null  float64
 7   Age             74051 non-null   float64
 8   Sex_F           123419 non-null  uint8  
 9   Sex_I           123419 non-null  uint8  
 10  Sex_M           123419 non-null  uint8  
dtypes: float64(8), uint8(3)
memory usage: 7.9 MB
None
   Length  Diameter  Height     Weight  Shucked Weight  Viscera Weight  \
0  1.5250    1.1750  0.3750  28.973189       12.728926        6.647958   
1  1.1000    0.8250  0.2750  10.418441        4.521745        2.324659   
2  1.3875    1.1125  0.3750  24.777463       11.339800        5.556502   
3  1.7000    1.4125  0.5000  50.660556       20.354941       10.991839   
4  1.2500    1.0125  0.3375  23.289114       11.977664        4.507570   

   Shell Weight   Age  Sex_F  Sex_I  Sex_M  
0      8.348928   9.0      0      1      0  
1      3.401940   8.0      0      1      0  
2      6.662133   9.0      0      0      1  
3     14.996885  11.0      1      0      0  
4      5.953395   8.0      0      1      0  

결측치가 없고, Sex 가 원 핫 인코딩으로 잘 저장된 것도 확인된다.

 

all_data_encoding.drop(columns='Age',inplace=True)
X = all_data_encoding[:len(train_df)]
Y = train_df['Age']

 

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(X,Y,random_state=100,shuffle=True,test_size=0.2)

 

from sklearn.linear_model import LinearRegression
model_LR = LinearRegression()
model_LR.fit(x_train,y_train)
y_pred = model_LR.predict(x_test)

 

from sklearn.metrics import mean_absolute_error
print(f'{y_pred[:5]}\n{y_pred.astype(int)[:5]}')
print(f'{mean_absolute_error(y_test,y_pred)} \n{mean_absolute_error(y_test,y_pred.astype(int))}')

[10.30036098 10.23518101  6.83617007  7.23905981 10.2260716 ]
[10 10  6  7 10]
1.4867050765343677 
1.4421038417392478

Age 가 소수일 필요는 없으니 MAE 오차도 소수일때와 정수로 변경했을 때 차이가 나고, 정수일때 오류를 더 줄일 수 있었다.

 

test_df_encoding = all_data_encoding[len(train_df):]
y_pred_test = model_LR.predict(test_df_encoding)
print(y_pred_test.astype(int)[:5])

[ 7  7 10  9  7]

 

test_df['Age'] = y_pred_test.astype(int)
test_df_sub = test_df[['id','Age']]
test_df_sub.set_index('id',inplace=True)
print(test_df_sub.head())
test_df_sub.to_csv('submission.csv')

 

이대로 캐글에 제출해보았다.

 

 

원 핫 인코딩으로 Sex 를 처리만 하고 베이스라인 모델로 LinearRegression 모델의 결과로서 MAE 1.44 오류로 현재 점수가 나왔다.

 

대회의 리더보드에 현재 571 중 447 등을 했다. 대충 78% 정도 수준에 머문다.

 

일단 EDA 과정을 건성으로 했으니, EDA 와 feature engeering 을 통해서 MAE 수치를 줄이도록 해봐야 겠다.

 

 

 

728x90