전복 연령 예측 모델 만들기

소개



이번은 the UC Irvine Machine Learning Repository 로부터, 전복의 데이터를 취득해, 전복의 연령 예측을 하는 모델의 작성까지의 길을 써 가고 싶습니다.
Jupyter notebook에서의 구현을 확인하고 있으므로, 환경에 따라서는 다른 거동을 할지도 모르므로, 주의해 주세요.

데이터 준비



우선, 사용하는 module를 읽어 둡니다.
import pandas as pd
import sklearn
from pandas import Series,DataFrame
from sklearn import linear_mode
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor

이번에 사용할 데이터는 여기에서 다운로드하여 abalone.data라는 파일을 얻습니다.

검색된 파일을 엽니다.
with open('abalone.data') as f:
    abalone_file = f.read()

내용을 확인하고,
abalone_file



이러한 출력이 되었습니다.\n 로 단락지어져 있을 것 같았으므로, 다음과 같이 DataFrame의 형태로 해, 내용을 확인해 보았습니다.
abalone_data = []
for line in abalone_file.split('\n'):
    abalone_data.append(line.split(','))

abalone_df = DataFrame(abalone_data)

abalone_df.head()



컬럼이 수치가 되어 있어 어떤 값인가를 잘 모르기 때문에, 데이터를 취득한 the UC Irvine Machine Learning Repository 의 설명란을 보고, 컬럼의 설정을 했습니다.
# 列名の設定
abalone_df.columns = ['Sex', 'Length', 'Diameter', 'Height', 'Whole weight', 'Shucked weight', 'Shell weight', 'Viscera weight', 'Rings']

그런 다음 데이터 내용의 유형을 확인합니다.
abalone_df.info()

출력 결과↓
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4178 entries, 0 to 4177
Data columns (total 9 columns):
 #   Column          Non-Null Count  Dtype 
---  ------          --------------  ----- 
 0   Sex             4178 non-null   object
 1   Length          4177 non-null   object
 2   Diameter        4177 non-null   object
 3   Height          4177 non-null   object
 4   Whole weight    4177 non-null   object
 5   Shucked weight  4177 non-null   object
 6   Shell weight    4177 non-null   object
 7   Viscera weight  4177 non-null   object
 8   Rings           4177 non-null   object
dtypes: object(9)
memory usage: 293.9+ KB

모든 Dtype이 object가 되어 버리고 있었으므로, 적절한 것으로 변환합니다.
이 때의 변환이 조금 주위 어색한 느낌이 들었으므로, 더 좋은 방법이 있으면 가르쳐 주시면 기쁩니다.
# abalone_dfのSex列以外を取得し、float型に変換した新しいdataframeを作成
abalone_dframe = abalone_df.iloc[:, 1:9].astype('float')
# 新しく作成したabalone_dframeに元のabalone_dfのSex列のデータを代入
abalone_dframe['Sex'] = abalone_df['Sex']

변환이 완료되었는지 확인합니다.
abalone_dframe.info()

출력 결과↓
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4178 entries, 0 to 4177
Data columns (total 9 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   Length          4177 non-null   float64
 1   Diameter        4177 non-null   float64
 2   Height          4177 non-null   float64
 3   Whole weight    4177 non-null   float64
 4   Shucked weight  4177 non-null   float64
 5   Shell weight    4177 non-null   float64
 6   Viscera weight  4177 non-null   float64
 7   Rings           4177 non-null   float64
 8   Sex             4178 non-null   object 
dtypes: float64(8), object(1)
memory usage: 293.9+ KB

형식 변환이 완료되었습니다.
그러나 Non-Null Count 의 부분의 값으로 Sex4178 라고 표시되어 있어 위화감을 느꼈으므로, 데이터의 뒤 5개를 확인해 보았습니다.
abalone_dframe.tail()



과연, 마지막 행은 Sex 열만 공백으로 되어 있습니다.
마지막 줄은 필요하지 않으므로 삭제합니다.
abalone_dframe = abalone_dframe.drop(4177)

확인
abalone_dframe.info()

출력 결과↓
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4177 entries, 0 to 4176
Data columns (total 9 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   Length          4177 non-null   float64
 1   Diameter        4177 non-null   float64
 2   Height          4177 non-null   float64
 3   Whole weight    4177 non-null   float64
 4   Shucked weight  4177 non-null   float64
 5   Shell weight    4177 non-null   float64
 6   Viscera weight  4177 non-null   float64
 7   Rings           4177 non-null   float64
 8   Sex             4177 non-null   object 
dtypes: float64(8), object(1)
memory usage: 326.3+ KB

좋아 보인다.Rings 의 데이터는 연령 식별에만 사용되므로 삭제합니다.
abalone_dframe =  abalone_dframe.drop('Rings', axis=1)

이번에 성별 데이터가 M, F, I라는 범주로 되어 있으므로 설명 변수로 사용할 수 있도록 더미 변수로 변환합니다.
abalone_dframe = pd.get_dummies(abalone_dframe, drop_first=True, columns=['Sex'])

확인
abalone_dframe.head()


Rings 가 사라지고, Sex_ISex_M 의 더미 데이터가 작성되고 있는 것을 확인할 수 있었습니다.

우선 데이터의 준비는 완료, 라고 합니다.

모델 만들기



이번에는 중회귀 분석과 랜덤 포레스트 회귀를 실시해 보겠습니다.

중회귀 분석


X = abalone_dframe.drop('Age', axis=1)
Y = abalone_dframe['Age']

l_model = linear_model.LinearRegression()

# 学習データとしてデータの70%を使用
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=0)

clf = l_model.fit(X_train, y_train)

print('重回帰分析:', clf.score(X_test, y_test))

출력 결과↓
重回帰分析: 0.5253868694528048

각 열의 데이터 값이 통일성이 부족하기 때문에 학습 데이터를 표준화해 보았습니다.
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

clf = l_model.fit(X_train_std, y_train)

print('重回帰分析:', clf.score(X_test_std, y_test))

출력 결과↓
重回帰分析: 0.5253868694528043

어라, 결과는 변하지 않아,,
여기서 표준화한 경우와 하지 않았을 경우의 차이를 가르쳐 주시면 기쁩니다,,,

랜덤 포레스트 회귀


estimator = RandomForestRegressor()

clf = estimator.fit(X_train_std, y_train)
print('ランダムフォレスト回帰:', clf.score(X_test_std, y_test))

출력 결과↓
ランダムフォレスト回帰: 0.5437448805034208

랜덤 포레스트 회귀가 중회귀 분석보다 정밀도가 높은 결과가 되었습니다.



그리드 검색을 사용해보기


param_grid = {'criterion':['mse','friedman_mse','mae'],
              'max_depth': [2,3,4,5,6,7,8,9],
              'n_estimators': [1,10,50,100]}

# グリッドサーチ
gs = GridSearchCV(estimator=estimator, param_grid=param_grid, scoring='r2', n_jobs=-1)
gs = gs.fit(X_train, y_train)

# score、ベストパラメータを表示
print('ランダムフォレスト回帰:',gs.score(X_test,y_test))
print('ベストパラメータ:',gs.best_params_)

출력 결과↓
ランダムフォレスト回帰: 0.5438998974098809
ベストパラメータ: {'criterion': 'friedman_mse', 'max_depth': 7, 'n_estimators': 100}

조금 정확도가 높아졌습니다.

결론



아직도 지식이 부족해지면서, 노력해 실장해 보았습니다.
개선점이나 정밀도를 높이는 방법 등, 어떤 일이든 상관없기 때문에, 지적해 주시면 기쁩니다.
끝까지 읽어 주셔서 감사합니다.

좋은 웹페이지 즐겨찾기