KT AIVLE School 3기/머신러닝

KT Avile DX트랙 25일차

Do잇 2023. 3. 8. 17:55

 

🔍 머신러닝 3일차!

 

📝 어제에 이어서 데이터 전처리

 

📌 변수 추가

- 분석에 의미가 있다고 판단되는 변수를 추가한다.

# 데이터 확인
data['Name']

# Title 변수 추가
data['Title'] = data['Name'].str.extract('([A-Za-z]+)\.') # [a-zA-Z] : 알파벳 모두
#추출대상에 공백을 포함하지 않아서 공백은 나오지 않는다.

# Title 확인
data['Title']

# 확인
data['Title'].value_counts()

# 중요 호칭외에는 Others로 변경.
main_tit = ['Mr','Miss','Mrs','Master']
data.loc[data['Title'].isin(main_tit)==False,'Title'] = 'Others'

# 확인
data['Title'].value_counts()

💡 정규표현식 : 특정한 조건의 문자를 '검색'하거나 '치환'하는 과정을 매우 간편하게 처리하기 위한 수단

df.Name.str.extract(' ([a-zA-Z]+)\.')

# Dot(.) 메타 문자는 줄바꿈 문자인 \n을 제외한 모든 문자와 매치됨

-extract함수 안에 있는 정규식에서는 중괄호 ([a-zA-Z]+)부분이 추출된다.

-띄어쓰기로 시작해 모든 알파벳이 포함된 문자열을 한 번이상 반복하다가 dot(.)으로 마무리하는 문자열이다.

 따라서 Mr,Miss 등 영어 호칭이 추출된다.

 

df.Name.str.contains('(Mr)')

- Mr가 포함된 행 확인

- str.contains()를 통해 지정한 문자열이 포함되어 있는지 확인할 수 있다.

- 검색 문자열이 포함되어 있는 경우에는 True, 아닌 경우에는 False를 반환한다.

 

r'(day)'

- day가 포함된 모든 문자열을 의미.

 

💡 DataFrame.isin(values

- isin메서드는 DataFrame객체의 각 요소가 values값과 일치하는지 여부를 bool형식으로 반환한다.

- Series일 경우 : Index가 일치해야 한다. 
- DataFrame일 경우 : Index와 열 레이블이 일치해야 한다.
- Dict일 경우 : key는 열 레이블이다.

 

📌 Age 결측치를 중앙값으로 채우기

# 결측치 확인
data.isna().sum()

# Age 결측치를 중앙값으로 채우기 1
data['Age'].fillna(data["Age"].median(), inplace=True)

# Age 결측치를 중앙값으로 채우기 2
age_median=data["Age"].median()
data['Age'].fillna(age_median, inplace=True)

 

📌 Age 결측치를 Title별 중앙값으로 채우기

 

# 결측치 확인
data.isna().sum()

# Age 결측치를 Title 별 중앙값으로 채우기 
# data.groupby(by='Title',as_index=False)[['Age']].median()

# groupby 수정
age_median = data.groupby(by='Title')['Age'].transform('median')
data['Age'].fillna(age_median, inplace=True)

💡 df.transform( ' 함수 ' ): 함수를 df에 적용하는 메서드

 

💡 결측치의 타입은 실수(float)

💡 결측치 채우기의 경우 Series(시리즈)로 채우려면 행수가 데이터프레임과 같은 시리즈를 주어야한다.

 

📌 train_test_split() 함수 내의 매개변수 stratify

# 모듈 불러오기
from sklearn.model_selection import train_test_split

# 7:3으로 분리
x_train, x_test, y_train, y_test = train_test_split(x,y,
                                                    test_size=0.3,
                                                    stratify=y,
                                                    #y값 기준으로 균등하게 분할되게끔 .
                                                    random_state=1)

💡 train_test_split() 함수 내의 매개변수 stratify

- 테스트 세트의 갯수가 훈련 세트에 비해 터무니 없이 작을 때 샘플링 편향이 발생할 수 있음.
- 그것을 방지하기 위해 train_test_split()함수 내에 stratify 매개변수에 타깃 데이터(y)를 전달하면 클래스 비율에 맞게 데이터를 나누게 됨.
- 쉽게 말하면 그냥 골고루 비율 맞춰서 데이터 잘 나눠주는 옵션이다 정도로 이해하면 된다.

- stratify에 대한 결과는 classification_report에서 확인할 수 있다.

- KT Aivle 단체카톡 민초단님

📌 precision_score

# 모듈 불러오기
from sklearn.metrics import precision_score

# 성능 평가
print(precision_score(y_test,y_pred)) 
# 1에 대한 precision이었다.이게 기본값평균이 아니었다.

print(precision_score(y_test,y_pred, average=None)) 
# 평균을 내지말라고 하면 P와 N 두개 다 보여준다.

print(precision_score(y_test,y_pred, average='macro')) # 산술평균

print(precision_score(y_test,y_pred, average='weighted'))# 가중평균

print(precision_score(y_test,y_pred, average='binary')) 
# average의 기본값 => binary(p의 값을 보여줌)

오류) Target is multiclass but average='binary'. 에 대한 해결법

💡 average 매개변수 정리

- None = 평균을 내지말고 각각의 값 P,N 둘 다 표시
- macro = 산술평균
- weighted = 가중평균
- binary = 기본값(P의 값을 보여줌)

 

- 위 average 매개변수는 Precision_score뿐만 아니라, recall_score와 f1_score에도 동일하게 적용됨.

- iris데이터는 단순한 데이터이므로 Precision_score, recall_score, f1_score의 값이 동일하게 나올 수도 있다.

 

 

💡precision_score 함수의 average 매개변수는 multiclass classification 문제에서만 사용 가능한 값들만 사용 가능합니다. 오류 메시지에서도 알 수 있듯이 'binary' 값은 multiclass 문제에서는 사용할 수 없습니다. 따라서 다른 값을 사용하셔야 합니다. 'micro', 'macro', 'weighted' 등이 사용 가능합니다.

기본적으로 파라미터 average는 binary, 즉 이진 분류로 default가 되어 있기 때문에 파라미터 값을 따로 설정해주어야 합니다. 사용될 수 있는 파라미터 값은 다음과 같습니다.
- micro : 각각의 TP, FN, FP, TN 값들을 모두 합친 Total TP, FN, FP, TN 값들을 이용해 계산
- macro : 각각의 클래스에 따라 TP, FN, FP, TN 값들을 이용해서 평가지표를 계산한 후 그 값들의 평균을 사용
- weighted : 각 클래스에 해당하는 data 개수에 가중치를 주어 평균을 구하는 것
어떤 옵션을 선택할 지는 문제의 특성에 따라 다르며, 가장 적합한 옵션을 선택해야 합니다.

- 너굴안내님의 precision_score 함수 오류에 대한 1:1 문의 튜터님의 답변 

 

📕 기본 알고리즘 (이론)

성능은 기본적으로 앙상블 알고리즘이 제일 좋다.

하지만 기본적으로 알고리즘을 알고 있어야 한다.

 

📌Linear Regression (선형 회귀)

- 회귀 : 평균으로 돌아가려는 경향

- X 값이 0 일 때, Y 값을 Y절편이라고 한다.

- 데이터는 다양한 형태를 가질 것이며 최선의 직선(오차제곱의 합이 가장 작은 값)을 긋기가 쉽지 않음

  (오차제곱의 합이 가장 작은 값: SSE, MSE, MAE이 가장 작은 값)

- 선형 회귀의 목적은 최선의 직선을 찾는 것.

- 최적의 회귀모델은 전체 데이터의 오차 합이 최소가 되는 모델을 의미함.

- 결국 오차 합이 최소가 되는 가중치 w1과 편향 w0을 찾는 것을 의미함.

 

- 독립변수 개수로 회귀분석을 단순 회귀와 다중 회귀로 분류

 

📌 단순회귀

- 독립변수 하나와 종속변수 하나가 일대일 대응 관계를 갖는 선형 회귀

- x값 하나만으로 y값을 설명할 수 있는 경우

 ex) 행복지수(y = 종속변수)가 연수입(x = 독립변수)만으로 결정됨.

- 회귀식: hat_y = w0 + w₁x₁

- 반복학습을 통해서 최선의 가중치(w₁)와 편향(w0)을 찾음.

 

# 모델 학습 후 회귀 계수 확인 가능
print(model.coef_)      # 가중치(기울기)
print(model.intercept_) # 편향(절편)

이를 회귀식으로 표현하면

y = 편향절편 + 가중치 * x

 

단순회귀는 이 값만 주어진다면 회귀선을 시각화하여 그릴 수 있다.

 

📌 다중회귀

- 여러 독립변수가 종속변수에 영향을 미치는 선형 회귀

- y값을 설명하기 위해서는 여러개의 x값이 필요한 경우

ex) 여러요인들(x = 독립변수들)에 의해 보스턴 지역 집 값(y = 종속변수)이 결정됨.

- 회귀식: hat_y = w0 + w₁x₁+w₂x₂+w₃x₃+···+wnxn

- 각 독립변수의 최선의 가중치(w₁, w₂ ,w₃···)와 편향(w0)을 찾음

# 모델 학습 후 회귀 계수 확인 가능
print(list(x_train[features]))
print(model.coef_)      # 가중치(기울기)
print(model.intercept_) # 편향(절편)

이를 회귀식으로 표현하면

y = 편향절편 + 가중치w₁ * x₁ + 가중치w₂ * x₂ + 가중치w₃ * x₃

 

다중회귀는 이 값이 주어진다고 하더라도 회귀선을 시각화하여 그릴 수 없다.

시각화에 너무 집중하지 말자.

 

 

💾 선형회귀 실습(익히기 03_01_선형회귀(Cars데이터))

 

# speed, dist 관계 산점도
plt.scatter(x='speed', y='dist', data=data)
plt.xlabel('Speed(mph)')
plt.ylabel('Dist(ft)')
plt.show()

 

📌모델링

# 1단계: 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score
# 선형회귀에서는 평가지표를 mae와 r2 이 두개를 보자
# MSA,RMSA,MAE 다 봐도 되지만 너무 많잖아
# accuracy는 분류모델이지 회귀모델이 아니다. 여기서 나오면 안돼!!

# 2단계: 선언하기
model = LinearRegression()

# 3단계: 학습하기
model.fit(x_train,y_train)

# 4단계: 예측하기
y_pred=model.predict(x_test)

# 5단계: 평가하기
print('MAE :', mean_absolute_error(y_test, y_pred))
print('R2 :', r2_score(y_test, y_pred))

 

📌 회귀계수를 살펴보자

# 회귀계수 확인
print(model.coef_) #가중치(기울기)
print(model.intercept_) # 편향(절편)

Distance = 3.91 × Speed -16.37

 

📌 기타 선형회귀

 

# y=ax+b 
a = model.coef_
b = model.intercept_

# speed 에 들어갈 적당한 X값이 필요
speed = np.array([x_train.min(), x_train.max()]) 

# 선형회귀식
dist = speed * a + b

# 산점도
plt.scatter(x_train, y_train) # 학습데이터 산점도
plt.scatter(x_test, y_test)    # 테스트데이터 y=실제값 산점도
plt.scatter(x_test, y_pred)    # 테스트데이터 y=예측값 산점도
# y_pred값은 직선상에 놓여있다.

# 회귀선 (학습데이터에 대해서 최선의 직선, 따라서 최적의 회귀선이 아닐수도 있음.)
plt.plot(speed, dist, color='r')

# 학습데이터의 평균값 
plt.axhline(y_train.mean(), color='r', linestyle='--')

# 확인
plt.show()

 

📌 시각화

plt.plot(y_test.values, label='Actual')
plt.plot(y_pred, label='Predicted')
plt.legend()
plt.ylabel('Dist(ft)')
plt.show()

 

 

💾 LinearRegression 실습

📌단순 회귀(실습_03_01_ 선형회귀(Happy 데이터))

 

모델링

# 1단계: 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# 2단계: 선언하기
model = LinearRegression()

# 3단계: 학습하기
model.fit(x_train,y_train)

# 4단계: 예측하기
y_pred= model.predict(x_test)

# 5단계: 평가하기
print('MAE:',mean_absolute_error(y_test,y_pred))
print('R2:',r2_score(y_test,y_pred)) 
# r2_score 대신에 model.score(x_test,y_test) 해도 R2나옴

model.score(x_test,y_test) # 회귀일 때는 R2, 분류일 때는 Accuracy가 나옴

# 회귀계수 확인
print(model.coef_)
print(model.intercept_)

# 예측값, 실제값 시각화
plt.plot(y_test.values, label='Actual')
plt.plot(y_pred, label='Predicted')
plt.legend()
plt.ylabel('happiness')
plt.show()

happiness = 0.72 × income + 0.16

 

📌 다중회귀(실습_03_02_ 선형회귀(Carseats 데이터)

 

데이터 준비(전처리 과정)

# target 확인
target='Sales'

# 데이터 분리
x=data.drop(target, axis = 1)
y=data.loc[:, target]

# 데이터 확인
data.info()

# 가변수화 대상: ShelveLoc, Education, Urban, US
cols=['ShelveLoc', 'Education', 'Urban', 'US'] 
#Education 교육수준으로 가변수화 대상

# 가변수화
x= pd.get_dummies(x, columns=cols, drop_first=True) 
# data가 아니라 x를 가변수화하는 것을 잊지 말자!

# 확인
x.head() # data가 아니라 x를 확인하는 것을 잊지 말자!

# 모듈 불러오기
from sklearn.model_selection import train_test_split

# 데이터 분리
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.3, random_state=1)
# x_train, y_train, x_test, y_test라고 적으면 절대 안됨!!

# 여기서 object 형식의 값이 있으면 안됨.
# 확인
x_train.info()

 

모델링

# 1단계: 불러오기
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# 2단계: 선언하기
model = LinearRegression() 

# 학습 전 데이터 제대로 분리했는지 확인
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)

# 3단계: 학습하기
model.fit(x_train,y_train)

# 4단계: 예측하기
y_pred = model.predict(x_test)

# 5단계: 평가하기
print('MAE:', mean_absolute_error(y_test,y_pred))
print('R2:', r2_score(y_test,y_pred))

# 회귀계수 확인(칼럼이름까지 같이 출력)
print(list(x))
print(model.coef_)
print(model.intercept_)

💡 LinearRegression는 선언하기 과정에서 튜닝이 안된다.(괄호안에 넣을 수 있는 값이 없다.)

따라서 전처리 과정에서 이상치 제거나 성능에 방해되는 컬럼을 제거하는 것도 고려해보아야한다.

 

가중치

# 가중치 데이터프레임 만들기
tmp = pd.DataFrame()
tmp['feature']= list(x) 
# list(x)를 써도 되고, x.columns를 써도 된다.
tmp['weight']=model.coef_
tmp.sort_values(by='weight',ascending=True,inplace=True) 
# barh라서 아래에서부터 시작된다.

# 가중치 시각화
plt.figure(figsize=(5,5))
plt.barh(tmp['feature'],tmp['weight'])
plt.show()

# 무조건 가중치가 크다고 그 변수가 가장 중요한 값은 아니다.
# 표준화나 정규화를 해야한다.

 

시각화

# 예측값, 실젯값 시각화
plt.plot(y_test.values, label='Actual')
plt.title('comparison btw test-pred')
plt.plot(y_pred, label='Predicted')
plt.legend()
plt.ylabel('Sales')
plt.show()

 

📕 KNN (K-Nearest Neighbor) : 회귀와 분류에 모두 사용가능

- k 최근접 이웃

- 회귀와 분류에 사용되는 매우 간단한 지도학습 알고리즘

- 다른 알고리즘에 비해 이해하기 쉽지만, 연산 속도가 느림

 

⭐ k값의 중요성

-k(탐색하는 이웃 개수)에 따라 데이터를 다르게 예측할 수도 있음

- k값에 따라 예측 값이 달라지므로 적절한 k값을 찾는 것이 중요(기본값 = 5 = 이웃의 개수)

- 일반적으로.

   -k를 1로 설정 안함 → 이웃 하나로 현재 데이터를 판단하기에는 너무 편향된 정보

   -k를 홀수로 설정 → 짝수인 경우 과반수 이상의 이웃이 나오지 않을 수 있음

- 검증 데이터로 가장 정확도가 높은 k를 찾아 KNN알고리즘의 k로 사용

 

💡 맨하튼 거리는 유클리드 거리보다 항상 크거나 같다.

 

📌Scaling 스케일링 작업

 

- KNN모델 성능을 높이기 위해서는 스케일링 작업을 진행해야한다.

- 모든 데이터가 같은 범위의 데이터를 가질 때 좋은 성능을 보여준다.- 스케일링 여부에 따라 KNN 모델 성능이 달라질 수 있음을 꼭 기억해야한다.

 

 

💾 kNN(k-Nearest Neighbor) 실습

💡 결측치 처리

- 시계열 데이터이므로 선형보간법으로 채운다.

   df. interpolate(method='linear', inplace=True)

# 결측치 확인
data.isnull().sum()

# 결측치 채우기
data.interpolate(method='linear', inplace=True)
# interpolate에서 매개변수를 method='linear'로 줘서 선형보간

# 확인
data.isnull().sum()

`interpolate`는 결측치(missing values)를 보간(interpolation)하여 데이터를 대체하는 방법. 

판다스(Pandas)에서는 `interpolate` 메서드를 사용하여 시계열(time-series) 데이터나 연속적인 수치 데이터에서 우리는 일종의 연속성있는 패턴을 발견할 수 있는데 이를 결측치를 채우는데 사용한다. `interpolate` 메서드는 다양한 방법으로 보간(Interpolation)을 통해 앞,뒤 값을 통하여 유추하여 좀 더 스마트하게 결측치(NaN)를 채워줄 수 있도록 매개변수를 제공한다.

 

참고(Reference) - Pandas 공식 도큐먼트

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.interpolate.html

 

pandas.DataFrame.interpolate — pandas 1.5.3 documentation

‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘spline’, ‘barycentric’, ‘polynomial’: Passed to scipy.interpolate.interp1d. These methods use the numerical values of the index. Both ‘polynomial’ and ‘spline’ req

pandas.pydata.org

 

📌 정규화 작업

 

  • 방법1: 공식 사용 => 결과: 데이터프레임형태열이름 있음.
# 학습데이터에서 최댓값, 최솟값 구하기
x_max = x_train.max()
x_min = x_train.min()

# 정규화
x_train = (x_train - x_min)/(x_max - x_min)
x_test = (x_test - x_min)/(x_max - x_min)
# 정규화하기 전으로 되돌려놓을 수 없음

# 확인
x_train.describe()

x_test.describe() # 최대값이 1을 넘었다고 해도 어쩔 수 없다.

 

  • 방법2: 함수 사용=> 결과: 배열형태열이름 사라져버림.
x_train.head(5)

# 모듈 불러오기
from sklearn.preprocessing import MinMaxScaler


# 정규화
scaler=MinMaxScaler()
scaler.fit(x_train) # x_train(학습데이터)에서 최소값, 최대값을 학습(확인)해!!
x_train = scaler.transform(x_train) # 그 사실을 가지고 x_train을 정규화해
x_test = scaler.transform(x_test) # 그 사실을 가지고 x_test를 정규화해

# 결과가 배열이 됨(열 이름이 사라짐)
x_train[:5]

# 정규화하기 전으로 되돌려놓을 수 있는 장점
scaler.inverse_transform(x_train)[:5]
# 소수점까지 되돌려놓을 수는 없음
# 칼럼까지 되돌려놓을 수는 없음

 

✔ 모델링

# 1단계: 불러오기
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_absolute_error, r2_score

# 2단계: 선언하기
model = KNeighborsRegressor()

# 3단계: 학습하기
model.fit(x_train, y_train)

# 4단계 예측하기
y_pred = model.predict(x_test)

# 5단계: 평가하기
print('MAE:',mean_absolute_error(y_test,y_pred))
print('R2:',r2_score(y_test,y_pred))

 

💡 2단계 선언하기에서 model = KNeighborsRegressor(n_neighbors=5)를 넣어주면

    k값을 선언해준 것.

  - k값에 따라 예측 값이 달라지므로 적절한 k값을 찾는 것이 중요

   (n_neighbors = 기본값 = 5 = 이웃의 개수)

  - k가 클수록 가장 단순한 모델이 된다.
   ( k가 1일 때 가장 복잡한 모델이다.)
   ( k값은 많아야 5 ~ 10 사이이다. 10도 너무 많음) 

 

 

시각화

# 예측값, 실젯값 시각화
plt.plot(y_test.values, label='Actual')
plt.plot(y_pred, label='Predicted')
plt.legend()
plt.ylabel('Ozone')
plt.show()

 

 

💡가변수화한 값은 0,1 밖에 없다. (범주값이 0과 1사이의 연속값으로 바뀐 것)

   따라서 가변수화한 값은 정규화를 해도 되고 안해도 된다.

   가변수화한 값을 정규화한다면 정수에서 실수(float)형태가 된다.

 

 

💡 가장 단순한 모델 => 평균

   kNN은 k개의 이웃에게 물어서 평균을 내는 것.

   데이터의 개수와 k값의 개수가 같다면 k값은 평균이다.

   따라서 KNN은 K값이 클수록 단순해진다.

 

 

💡 평가(미래,test)데이터가 현재(학습,train)데이터에 영향을 못 미친다.

   따라서, Scaling 스케일링(정규화 - 거리에 대한 고려와 표준화)는 무조건 학습데이터와 평가데이터를 분리한 후에 Scaling 스케일링 해야한다.

 

 

💡 미래의 데이터(평가데이터)는 1보다 클 수도 있고 음수가 될 수도 있다.

    미래의 데이터(평가데이터)는 0과 1을 벗어날 수 있다. => 이상치(Outlier)

 

 

💡 함수 = function = x에 대한 y대응값

   = 직선을 수식화한 것 = 직선을 표현한 수식

 

 

💡스케일링의 종류

1. 표준화

 - 표준화는 분포의 범위가 다양할 때, 분포를 비교하기 위한 (특히 정규분포) 방법.

 - 표준화를 거치면 z-score가 된다.

 - 모든 분포가 평균은 0, 표준편차는 1이 되므로 분포에 대한 비교가 가능해진다.

2. 정규화

 - 모든 feature(변수)를 0과 1 사이 값으로 변환하는 방식.

 - 이상치 제거가 선행되어야한다.

 - 이상치가 존재할 경우, 성능이 저하된다.

 

표준화와 정규화의 차이점

 - 표준화는 이상치와 상관없이 분포를 그대로 유지해준다.

 - 반면에 정규화는 값의 범위를 0에서 1로 맞춰야하기 때문에 이상치에 따라서 분포가 좀 더 압축된다.

 

따라서, 이상치가 큰 경우 표준화가 적절하고, 이상치가 작은 경우 대체로 정규화를 사용한다.

우리는 수업시간에 표준화가 아닌 정규화를 사용할 것이다. 

 

 

 

 

 

 

 

 

 

 

 

 

 

'KT AIVLE School 3기 > 머신러닝' 카테고리의 다른 글

KT Ailvle DX트랙 29일차  (0) 2023.03.14
KT Aivle DX 트랙 27일차  (0) 2023.03.11
KT Aivle DX 트랙 26일차  (0) 2023.03.09
KT Avile DX트랙 24일차  (0) 2023.03.07
KT Aivle DX트랙 23일차  (0) 2023.03.06