## x,y값샘플제작
손든횟수=[1,2,3,1,1,3,1,3]
성적=[90,100,80,100,88,77,55,85]
import pandas as pd
import numpy as np
df=pd.DataFrame(dict({'손든횟수':손든횟수, '성적':성적}))
df
손든횟수 | 성적 | |
---|---|---|
0 | 1 | 90 |
1 | 2 | 100 |
2 | 3 | 80 |
3 | 1 | 100 |
4 | 1 | 88 |
5 | 3 | 77 |
6 | 1 | 55 |
7 | 3 | 85 |
Part1. [단순선형회귀-최소제곱법계산식]
x=df['손든횟수'].values
y=df['성적'].values
x,y
(array([1, 2, 3, 1, 1, 3, 1, 3], dtype=int64), array([ 90, 100, 80, 100, 88, 77, 55, 85], dtype=int64))
xData=np.reshape(x,(-1,1))
xData
array([[1], [2], [3], [1], [1], [3], [1], [3]], dtype=int64)
from sklearn.linear_model import LinearRegression
import numpy as np
model=LinearRegression()
model.fit(xData,y)
model.coef_, model.intercept_
(array([-0.96363636]), 86.18181818181819)
– [작업1] model.coef_와 model.intercept_값을 아래 수식으로 직접 계산해봅니다. –
# 공식을 이용하여 구한 회귀 | 위의 값과 비교해보면 같다.
coef=np.sum((x-np.mean(x))*(y-np.mean(y))) / (np.sum((x-np.mean(x))**2))
coef
-0.9636363636363636
np.mean(y)-(np.mean(x)*coef)
86.18181818181819
상수화 추가
$ y = w_1x_1 + b $ 는
내적곱 $ y = w_1x_1 + w_0x_0 $ 와 같다고 볼 수있다. 이때 $w_0$는 1, $x_0$는 b이다.
이렇게 연산하는 이유는 b, w를 한 개의 행렬로 계산할 수 있게 되기 때문이다.
– [작업2] model.coef_와 model.intercept_값을 아래 수식으로 직접 계산해봅니다. –
newX=np.c_[np.ones(len(x)),x] # 상수화 추가 | 1로된 배열 생성 | c_는 concat함수로 좌우로 연결함
newX
array([[1., 1.], [1., 2.], [1., 3.], [1., 1.], [1., 1.], [1., 3.], [1., 1.], [1., 3.]])
# newX의전치행렬*newX
계산1=np.dot(newX.T,newX) # T는 배열의 전치를 수행하는 함수 | dot은 행열 내적곱을 하는 함수
계산1
array([[ 8., 15.], [15., 35.]])
#계산1의 역행렬
# np.random.seed(0)
계산1역행렬= np.linalg.inv(계산1) # 역행열
계산1역행렬
array([[ 0.63636364, -0.27272727], [-0.27272727, 0.14545455]])
역행렬
원래 행렬 A와 곱셈을 통해 항등행렬(대각선이 1인 행렬)을 얻을 수 있는 행렬
전치
행렬 A의 행과 열을 열과 행으로 바꾼 행렬
# 최종결과
계산2=np.dot(계산1역행렬,newX.T)
계산3=np.dot(계산2,y)
계산3 ##첫번째값은 b, 두번째는 x1, 세번째는 x2
array([86.18181818, -0.96363636])
Part2. [다중선형회귀_최소제곱법계산식]
- 위의 작업2방법으로 계산합니다.
df['공지확인횟수']=[1,2,20,7,8,1,2,3]
df
손든횟수 | 성적 | 공지확인횟수 | |
---|---|---|---|
0 | 1 | 90 | 1 |
1 | 2 | 100 | 2 |
2 | 3 | 80 | 20 |
3 | 1 | 100 | 7 |
4 | 1 | 88 | 8 |
5 | 3 | 77 | 1 |
6 | 1 | 55 | 2 |
7 | 3 | 85 | 3 |
x=df[['손든횟수','공지확인횟수']].values
y=df['성적'].values
display(x)
array([[ 1, 1], [ 2, 2], [ 3, 20], [ 1, 7], [ 1, 8], [ 3, 1], [ 1, 2], [ 3, 3]], dtype=int64)
# 사이킷런 모델에서 계산된값
from sklearn.linear_model import LinearRegression
import numpy as np
model=LinearRegression()
model.fit(x,y)
model.coef_, model.intercept_
(array([-1.17727639, 0.12771958]), 85.87993553585818)
# 직접 계산한 최소제곱법
newX=np.c_[np.ones(len(x)),x]
계산1=np.dot(newX.T,newX)
np.random.seed(0)
계산1역행렬= np.linalg.inv(계산1)
계산2=np.dot(계산1역행렬,newX.T)
계산3=np.dot(계산2,y)
계산3 ##첫번째값은 b, 두번째는 x1, 세번째는 x2
# 이값으로 해석하면 손든횟수가 많을수록 성적은 -1배 감소한다. | x1의 인터셉트(weight)가 -1이기 때문에
# 이값으로 해석하면 공지확인횟수가 많을수혹 성적은 0.1배 증가한다. | x2의 인터셉트(weight)가 0.1
array([85.87993554, -1.17727639, 0.12771958])
### 위의 작업을 함수로 작업해보기
x=df[['손든횟수','공지확인횟수']].values
y=df['성적'].values
def linear(x,y):
newX=np.c_[np.ones(len(x)),x] # 상수항 추가로 인해 reshape를 하지 않아도 된다.
계산1=np.dot(newX.T,newX)
np.random.seed(0)
계산1역행렬= np.linalg.inv(계산1)
계산2=np.dot(계산1역행렬,newX.T)
계산3=np.dot(계산2,y)
return 계산3
linear(x,y)
array([85.87993554, -1.17727639, 0.12771958])
GridSearch
그리드서치는 머신러닝 모델에서 최적의 하이퍼파라미터를 찾기 위해 사용되는 탐색 방법 중 하나입니다.
그리드 서치는 가능한 모든 하이퍼파라미터 조합을 다중 for문을 시도하여 최적의 조합을 찾는 방법입니다.
예를 들어, 하이퍼파라미터 A에 [0.1,0.2,0.3]의 값들과 하이퍼파라미터 B에 [1,2,3]의 값을 지정한 경우,
그리드 서치는 총 9개의 조합을 만들어 각각에 대해 모델을 학습하고 평가해 최적의 조합을 찾아냅니다.
CV(Cross-Validation)
CV는 일반적으로 모델의 성능 평가와 하이퍼파라미터 튜닝에 널리 사용되는 검증 기법입니다.
CV는 다음과 같은 단계로 진행됩니다:
-
데이터 분할: 주어진 데이터를 학습 데이터와 테스트 데이터로 나눕니다. 전통적인 CV 방법은 데이터를 K개의 서로 다른 부분 집합으로 나누는데, 이를 K-Fold Cross-Validation이라고 합니다. 일반적으로 K 값은 5 또는 10이 많이 사용되지만, 다른 값도 선택할 수 있습니다.
-
모델 학습 및 평가: K 개의 부분 집합 중 하나를 선택하여 학습 데이터로 사용하고, 나머지 K-1 개의 부분 집합을 테스트 데이터로 사용하여 모델을 학습하고 평가합니다. 이 과정을 K 번 반복하여 K 개의 모델을 학습하고 평가합니다.
-
성능 평가: K 번의 평가 결과를 종합하여 모델의 평균 성능을 계산합니다. 일반적으로 평가 지표로는 정확도(accuracy), 정밀도(precision), 재현율(recall), F1 스코어(F1 score) 등이 사용됩니다.
하이퍼파라미터(alpha)
alpha는 릿지 회귀(Ridge Regression) 또는 라쏘 회귀(Lasso Regression)와 같은 정규화(regularization) 기법에서 사용되는 하이퍼파라미터입니다. 정규화는 모델의 복잡도를 제어하고 과적합을 방지하기 위해 사용되는 기법으로, alpha는 이 정규화 강도를 조절하는 매개변수입니다.
alpha 값은 일반적으로 0에서 큰 양의 값 사이에 있으며, 일반적으로 로그 스케일로 설정됩니다. alpha 값이 0에 가까울수록 정규화의 효과가 약화되며, 0보다 큰 값일수록 정규화의 강도가 강해집니다. 따라서, 더 큰 alpha 값은 더 강한 제약을 모델에 부과하고, 가중치를 작게 만듭니다.
alpha 값을 조정함으로써 모델의 복잡도와 일반화 간의 트레이드오프를 조절할 수 있습니다. 작은 alpha 값을 사용하면 모델은 더 복잡해지고 학습 데이터에 더 잘 적합할 수 있지만, 테스트 데이터에 대한 일반화 성능이 저하될 수 있습니다. 큰 alpha 값을 사용하면 모델은 더 단순화되고 일반화 성능이 향상될 수 있지만, 학습 데이터에 대한 적합도가 줄어들 수 있습니다.
alpha 값의 최적값을 찾기 위해서는 일반적으로 그리드 서치(Grid Search)나 다른 하이퍼파라미터 튜닝 방법을 사용하여 여러 가지 alpha 값에 대해 모델을 평가하고 비교해야 합니다. 최적의 alpha 값은 주어진 데이터셋과 모델에 따라 달라질 수 있으므로, 실험과 검증을 통해 선택해야 합니다.
# 그리드서치 실습
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Lasso
from sklearn.model_selection import GridSearchCV
import pandas as pd
##########데이터 로드
x_data = np.array([
[2,1],
[3,2],
[3,4],
[5,5],
[7,5],
[2,5],
[8,9],
[9,2],
[6,10],
[7,12]
])
y_data = np.array([3,5,7,10,12,7,13,13,12,12])
##########데이터 분석
##########데이터 전처리
x_train, x_test, y_train, y_test = train_test_split(x_data, y_data, test_size=0.3)
##########모델 훈련
model = Lasso()
param_grid = {'alpha':[0.01,0.1,1,10,100]} # alpha= 하이퍼파라미터 | 그리드서치를 통해 여러 가지 alpha값에 대해 모델을 평가하고 비교해야 함
grid = GridSearchCV(model, param_grid=param_grid)
grid.fit(x_train, y_train)
print(f'그리드서치가 찾아낸 최적의 하이퍼파라미터 조합: {grid.best_params_}')
df = pd.DataFrame(grid.cv_results_) # 그리드 서치를 수행한 결과 | 각 하이퍼파라미터 조합의 정보를 포함함.
print(df.sort_values(by=['param_alpha'])[['params','mean_test_score']])
##########모델 검증
print(grid.score(x_test, y_test)) #
##########모델 사용
print(grid.predict([[2,1]])[0]) # 최적의 모델을 사용하여 데이터 예측을 수행
그리드서치가 찾아낸 최적의 하이퍼파라미터 조합: {'alpha': 0.01} params mean_test_score 0 {'alpha': 0.01} NaN 1 {'alpha': 0.1} NaN 2 {'alpha': 1} NaN 3 {'alpha': 10} NaN 4 {'alpha': 100} NaN 0.8779231555293396 4.3847133947153925
c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\metrics\_regression.py:918: UndefinedMetricWarning: R^2 score is not well-defined with less than two samples. warnings.warn(msg, UndefinedMetricWarning) c:\devtools\Miniconda3\envs\meta\Lib\site-packages\sklearn\model_selection\_search.py:952: UserWarning: One or more of the test scores are non-finite: [nan nan nan nan nan] warnings.warn(
피클
객체를 저장하고 읽어오는 모듈로 학습한 모델을 저장하고 불러올 수 있다.
import pandas as pd
from sklearn.linear_model import LinearRegression
import pickle
import numpy as np
import os
##########데이터 로드
train_df = pd.read_excel('https://github.com/cranberryai/todak_todak_python/blob/master/machine_learning/regression/%E1%84%8B%E1%85%A1%E1%84%87%E1%85%A5%E1%84%8C%E1%85%B5%E1%84%8B%E1%85%A1%E1%84%83%E1%85%B3%E1%86%AF%E1%84%8F%E1%85%B5.xlsx?raw=true', sheet_name='train')
test_df = pd.read_excel('https://github.com/cranberryai/todak_todak_python/blob/master/machine_learning/regression/%E1%84%8B%E1%85%A1%E1%84%87%E1%85%A5%E1%84%8C%E1%85%B5%E1%84%8B%E1%85%A1%E1%84%83%E1%85%B3%E1%86%AF%E1%84%8F%E1%85%B5.xlsx?raw=true', sheet_name='test')
##########데이터 분석
##########데이터 전처리
x_train = train_df.drop(['Son'], axis=1)
x_test = test_df.drop(['Son'], axis=1)
y_train = train_df['Son']
y_test = test_df['Son']
print(x_train.head())
'''
Father
0 160.782
1 166.116
2 165.608
3 169.672
4 176.530
'''
x_train = x_train.to_numpy()
x_test = x_test.to_numpy()
##########모델 생성
model = LinearRegression()
##########모델 학습
model.fit(x_train, y_train)
##########모델 검증
print(model.score(x_train, y_train)) #
print(model.score(x_test, y_test)) #0.251997790584662
if not os.path.exists('models/son_height_regression_model'):
os.makedirs('models/son_height_regression_model')
with open('models/son_height_regression_model/model.pkl', 'wb') as f:
pickle.dump(model, f)
##########모델 예측
x_test = np.array([
[164.338]
])
y_predict = model.predict(x_test)
print(y_predict[0]) #169.66660924268297
Father 0 165.100 1 165.100 2 167.132 3 155.194 4 160.020 0.24967004992776776 0.2519977905846619 170.46931035654347
Tree 구조
node로 표현하는 tree 구조는 빠르다는 장점이 있지만 많은 용량을 할당해야하는 단점이 있습니다.
-
불순도(impurity) : 해당 범주안에 서로 다른 데이터가 얼마나 섞여 있는지를 뜻 한 종류의 데이터가 쏠려 있을 수록 순도( 불순도)가 높다. -
엔트로피(entropy) : 엔프로피가 1이면 불순도 최대(한 범주안에 데이터가 반반씩 있음) 0이면 불순도 최소(한 범주안에 같은 종류의 데이터만 있음) -
정보획득(information gain) : gain 지수라고도 함. 노드 분기 이전의 엔트로피에서 분기 이후의 엔트로피를 뺀 수치 이 지수가 크면 클수록 좋은 분기.
가지치기
트리 구조의 오버피팅을 막기위한 전략. 트리에 노드가 너무 많다면 오버피팅으로 볼 수 있습니다.
최대 깊이나 터미널 노드의 최대 개수, 혹은 한 노드가 분할하기 위한 최소 데이터수를 제한할 수 있습니다.
실습 - 자동으로 모은 중고 자동차 데이터 분석
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df = pd.read_csv('csv\\vehicles.csv')
EDA 및 데이터 기초 통계 분석
불필요한 데이터 제거하기
df.head(3)
Unnamed: 0 | id | url | region | region_url | price | year | manufacturer | model | condition | ... | drive | size | type | paint_color | image_url | description | state | lat | long | posting_date | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 7240372487 | https://auburn.craigslist.org/ctd/d/auburn-uni... | auburn | https://auburn.craigslist.org | 35990 | 2010.0 | chevrolet | corvette grand sport | good | ... | rwd | NaN | other | NaN | https://images.craigslist.org/00N0N_ipkbHVZYf4... | Carvana is the safer way to buy a car During t... | al | 32.590000 | -85.480000 | 2020-12-02T08:11:30-0600 |
1 | 1 | 7240309422 | https://auburn.craigslist.org/cto/d/auburn-201... | auburn | https://auburn.craigslist.org | 7500 | 2014.0 | hyundai | sonata | excellent | ... | fwd | NaN | sedan | NaN | https://images.craigslist.org/00s0s_gBHYmJ5o7y... | I'll move to another city and try to sell my c... | al | 32.547500 | -85.468200 | 2020-12-02T02:11:50-0600 |
2 | 2 | 7240224296 | https://auburn.craigslist.org/cto/d/auburn-200... | auburn | https://auburn.craigslist.org | 4900 | 2006.0 | bmw | x3 3.0i | good | ... | NaN | NaN | SUV | blue | https://images.craigslist.org/00B0B_5zgEGWPOrt... | Clean 2006 BMW X3 3.0I. Beautiful and rare Bl... | al | 32.616807 | -85.464149 | 2020-12-01T19:50:41-0600 |
3 rows × 26 columns
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 458213 entries, 0 to 458212 Data columns (total 26 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 458213 non-null int64 1 id 458213 non-null int64 2 url 458213 non-null object 3 region 458213 non-null object 4 region_url 458213 non-null object 5 price 458213 non-null int64 6 year 457163 non-null float64 7 manufacturer 439993 non-null object 8 model 453367 non-null object 9 condition 265273 non-null object 10 cylinders 287073 non-null object 11 fuel 454976 non-null object 12 odometer 402910 non-null float64 13 title_status 455636 non-null object 14 transmission 455771 non-null object 15 VIN 270664 non-null object 16 drive 324025 non-null object 17 size 136865 non-null object 18 type 345475 non-null object 19 paint_color 317370 non-null object 20 image_url 458185 non-null object 21 description 458143 non-null object 22 state 458213 non-null object 23 lat 450765 non-null float64 24 long 450765 non-null float64 25 posting_date 458185 non-null object dtypes: float64(4), int64(3), object(19) memory usage: 90.9+ MB
df.isna().sum() # 결측치 확인
Unnamed: 0 0 id 0 url 0 region 0 region_url 0 price 0 year 1050 manufacturer 18220 model 4846 condition 192940 cylinders 171140 fuel 3237 odometer 55303 title_status 2577 transmission 2442 VIN 187549 drive 134188 size 321348 type 112738 paint_color 140843 image_url 28 description 70 state 0 lat 7448 long 7448 posting_date 28 dtype: int64
df.describe()
Unnamed: 0 | id | price | year | odometer | lat | long | |
---|---|---|---|---|---|---|---|
count | 458213.000000 | 4.582130e+05 | 4.582130e+05 | 457163.000000 | 4.029100e+05 | 450765.000000 | 450765.000000 |
mean | 229106.000000 | 7.235233e+09 | 4.042093e+04 | 2010.746067 | 1.016698e+05 | 38.531925 | -94.375824 |
std | 132274.843786 | 4.594362e+06 | 8.194599e+06 | 8.868136 | 3.228623e+06 | 5.857378 | 18.076225 |
min | 0.000000 | 7.208550e+09 | 0.000000e+00 | 1900.000000 | 0.000000e+00 | -82.607549 | -164.091797 |
25% | 114553.000000 | 7.231953e+09 | 4.900000e+03 | 2008.000000 | 4.087700e+04 | 34.600000 | -110.890427 |
50% | 229106.000000 | 7.236409e+09 | 1.099500e+04 | 2013.000000 | 8.764100e+04 | 39.244500 | -88.314889 |
75% | 343659.000000 | 7.239321e+09 | 2.149500e+04 | 2016.000000 | 1.340000e+05 | 42.484503 | -81.015022 |
max | 458212.000000 | 7.241019e+09 | 3.615215e+09 | 2021.000000 | 2.043756e+09 | 82.049255 | 150.898969 |
df.columns
Index(['Unnamed: 0', 'id', 'url', 'region', 'region_url', 'price', 'year', 'manufacturer', 'model', 'condition', 'cylinders', 'fuel', 'odometer', 'title_status', 'transmission', 'VIN', 'drive', 'size', 'type', 'paint_color', 'image_url', 'description', 'state', 'lat', 'long', 'posting_date'], dtype='object')
데이터 소개
- 이번 주제는 Used Cars Dataset을 사용합니다.
- 파일은 한 개이며, 각각의 컬럼은 아래와 같습니다.
- vehicles.csv
id : 중고차 거래의 아이디
url : 중고차 거래 페이지
region : 해당 거래의 관리 지점
region_url : 거래 관리 지점의 홈페이지
price : 기입된 자동차의 거래가
year : 거래가 기입된 년도
manufacturer : 자동차를 생산한 회사
model : 자동차 모델명
condition : 자동차의 상태
cylinders : 자동차의 기통 수
fuel : 자동차의 연료 타입
odometer : 자동차의 운행 마일 수
title_status : 자동차의 타이틀 상태 (소유주 등록 상태)
transmission : 자동차의 트랜스미션 종류
vin : 자동차의 식별 번호 (vehicle identification number)
drive : 자동차의 구동 타입
size : 자동차 크기
type : 자동차의 일반 타입 (세단, ...)
paint_color : 자동차 색상
image_url : 자동차 이미지
description : 세부 설명
county : 실수로 생성된 미사용 컬럼
state : 거래가 업로드된 미 주
lat : 거래가 업로드된 곳의 위도
long : 거래가 업로드된 곳의 경도
df.drop(['Unnamed: 0', 'id', 'url', 'region_url', 'VIN',
'image_url', 'description', 'state', 'lat',
'long', 'posting_date'], axis=1, inplace=True)
df['age'] = 2023 - df['year'] # age 컬럼을 새로 생성
df.drop('year', axis=1, inplace=True)
# drop은 특정열을 제거하는 함수 | 분석할 필요없는 컬럼을 제거함
# axis는 제거할 축을 지정하는 옵션 (0은 행 제거 | 1은 열 제거)
# inplace는 원본 데이터 프레임을 변경할지 여부. False라면 새로운 데이터프레임을 리턴함.
df.head(3)
region | price | manufacturer | model | condition | cylinders | fuel | odometer | title_status | transmission | drive | size | type | paint_color | age | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | auburn | 35990 | chevrolet | corvette grand sport | good | 8 cylinders | gas | 32742.0 | clean | other | rwd | NaN | other | NaN | 13.0 |
1 | auburn | 7500 | hyundai | sonata | excellent | 4 cylinders | gas | 93600.0 | clean | automatic | fwd | NaN | sedan | NaN | 9.0 |
2 | auburn | 4900 | bmw | x3 3.0i | good | 6 cylinders | gas | 87046.0 | clean | automatic | NaN | NaN | SUV | blue | 17.0 |
df.columns
Index(['region', 'price', 'manufacturer', 'model', 'condition', 'cylinders', 'fuel', 'odometer', 'title_status', 'transmission', 'drive', 'size', 'type', 'paint_color', 'age'], dtype='object')
범주형(문자) 데이터 값의 범위, 기초 통계 분석하기
len(df['manufacturer'].value_counts()) # 제조사의 개수
43
df['manufacturer'].value_counts() # 제조사별 데이터 개수
# 왼쪽컬럼이 index가 된다
ford 79666 chevrolet 64977 toyota 38577 honda 25868 nissan 23654 jeep 21165 ram 17697 gmc 17267 dodge 16730 bmw 12352 hyundai 10975 mercedes-benz 10628 subaru 10510 volkswagen 10489 kia 8854 chrysler 7499 lexus 7119 cadillac 6743 buick 6009 mazda 5931 audi 5583 acura 4008 infiniti 3714 lincoln 3338 pontiac 3037 volvo 2866 mini 2330 mitsubishi 2301 porsche 1779 rover 1662 mercury 1645 saturn 1393 tesla 1067 jaguar 1060 fiat 955 alfa-romeo 187 harley-davidson 139 ferrari 96 datsun 63 aston-martin 35 land rover 21 morgan 3 hennessey 1 Name: manufacturer, dtype: int64
fig = plt.figure(figsize=(8,10)) # 가로8인치, 세로10인치
sns.countplot(
y='manufacturer',
data=df.fillna('n.a'), # 결측치는 n/a로 표현하겠음. fillna함수가 새로운 데이터프레임을 반환하지 않기 떄문에 재사용 하지 못한다.
order=df.fillna('n/a')['manufacturer'].value_counts().index # 제조사 개수가 높은 순으로 정렬
)
<Axes: xlabel='count', ylabel='manufacturer'>
countplot은 주어진 데이터에서 각 카테고리별로 빈도를 시각화하는 데 사용되는 seaborn 라이브러리의 함수입니다. 주로 범주형 변수의 분포를 살펴보고자 할 때 유용하게 사용됩니다.
sns.countplot(
y='condition',
data=df.fillna('n/a'),
order=df.fillna('n/a')['condition'].value_counts().index
)
<Axes: xlabel='count', ylabel='condition'>
수치형 데이터의 통계 분석
rugplot은 단일 변수의 분포를 확인하고자 할 때 주로 사용됩니다.
fig = plt.figure(figsize=(8,2))
sns.rugplot(x='price', data=df, height=1) # label을 price로만 준것 뿐 아니라 자동으로 price컬럼을 적용함
<Axes: xlabel='price'>
sns.histplot(x='age', data=df, bins=18, kde=True)
<Axes: xlabel='age', ylabel='Count'>
데이터 클리닝 수행
범주형 데이터 클리닝
아래의 방법 중 적절히 판단하여 처리
-
결손 데이터가 포함된 row를 제거
-
혹은 결손 데이터를 others 범주로 변경
-
지나치게 소수인 범주를 others 범주로 변경
-
classifier를 학습해서 결손 데이터를 추정하여 채워넣기
col = 'paint_color'
counts = df[col].fillna('others').value_counts()
# 결손데이터를 others로 처리
plt.grid()
plt.plot(range(len(counts)), counts)
# x데이터 = 각 범주의 인덱스
# y데이터 = 각 범주의 빈도수
[<matplotlib.lines.Line2D at 0x1a89c95ddd0>]
n_categorical = 7
colors = counts.index[n_categorical:]
# 7번 인덱스 이후로는 데이터 수가 적어 의미 없다고 판단
# 살릴 색상 범주를 colors 변수에 저장
df[col] = df[col].apply(lambda s: s if str(s) not in colors else 'others')
# colors안에 있는 이름의 값이 아니라면 모두 others로 변경하고 적용
df[col].value_counts()
white 82786 black 64145 silver 46722 red 33274 blue 32746 grey 30455 others 27242 Name: paint_color, dtype: int64
수치형 데이터 클리닝
quantile()
를 이용하여 outlier를 제거
quantile은 주어진 데이터의 분위수를 계산하는 함수로 분위수 위치에 있는 값을 반환합니다.
분위수란 데이터를 크기별로 정렬했을 때, 특정 백분율에 해당하는 위치에 있는 값을 의미
옵션
-
series: 분위수를 계산하고자 하는 시리즈(데이터 열)입니다.
-
q: 원하는 분위수를 나타내는 값을 입력합니다. 이 값은 0과 1 사이의 실수로 지정하며, 예를 들어 0.25는 25% 분위수를 의미합니다.
-
interpolation: 분위수를 계산하는 동안 사용할 보간법(interpolation) 방법을 지정합니다. 기본값은 ‘linear’로, 선형 보간법을 사용합니다. 다른 가능한 옵션으로 ‘lower’, ‘higher’, ‘midpoint’, ‘nearest’ 등이 있습니다.
p1 = df['price'].quantile(0.99) # 99퍼 분위수에 해당하는 값
p2 = df['price'].quantile(0.1) # 10퍼 분위수에 해당하는 값
print(p1, p2)
59900.0 651.0
# 99퍼와 10퍼 분위수에 해당하는 값의 차이가 많이나므로 그 사이에 있는 값들을 추출
df = df[(p1 > df['price']) & (df['price'] > p2)]
# 해당 조건을 만족하는 기존 df의 price행만 바뀜
# Boxplot 계열로 범주형 데이터를 시각화하여 분석하기
fig = plt.figure(figsize=(10, 5))
sns.boxplot(x='paint_color', y='price', data=df)
<Axes: xlabel='paint_color', ylabel='price'>
o1 = df['odometer'].quantile(0.99)
o2 = df['odometer'].quantile(0.1)
df = df[(o1 > df['odometer']) & (df['odometer'] > o2)]
# 컬럼간의 상관계수 확인하기
sns.heatmap(df.corr(), annot=True, cmap='YlOrRd')
C:\Users\user\AppData\Local\Temp\ipykernel_17708\269042974.py:6: FutureWarning: The default value of numeric_only in DataFrame.corr is deprecated. In a future version, it will default to False. Select only valid columns or specify the value of numeric_only to silence this warning. sns.heatmap(df.corr(), annot=True, cmap='YlOrRd')
<Axes: >
모델 학습을 위한 데이터 전처리
standardScaler를 이용해 수치형 데이터 표준화
from sklearn.preprocessing import StandardScaler
x_num = df[['odometer', 'age']]
sclaer = StandardScaler()
sclaer.fit(x_num) # 피팅
x_scaled = sclaer.transform(x_num)
x_scaled = pd.DataFrame(x_scaled, index=x_num.index, columns=x_num.columns)
# get_dummies를 이용해 범주형 데이터를 one-hot 벡터로 변경하기
x_cat = df.drop(['price', 'odometer', 'age'], axis=1) # 숫자형 데이터를 제거
x_cat = pd.get_dummies(x_cat)
# 입출력 데이터 통합하기
x = pd.concat([x_scaled, x_cat], axis=1)
y = df['price']
x.shape
(322166, 23756)
train, test데이터 분리
from sklearn.model_selection import train_test_split
# train_test_split() 함수로 학습 데이터와 테스트 데이터 분리하기
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
Regression 모델 학습
XBGoost Regression 모델 학습하기
# 여기서부터 데이터 클리닝을 못하여 뻗었다.
댓글남기기