[ 오늘 배운 내용 ]
1. Feature Engineering
2. NaN 조치
3. Dummy Variable
4. Scaling
5. 모델링
오늘은 전날 배웠던 데이터 전처리 메서드를 다시 한번 훑어본 뒤
feature와 target으로 데이터프레임을 분리해주고 NaN값을 제거하거나 다른 값으로 채워주는 처리 및 범주형 데이터를 수치화 시켜주는 dummy variable(가변수화) 작업을 했다.
그 다음 Min-Max Scale과 Standardization의 두 가지 feature Scaling도 해 본 뒤 간단한 모델링도 해보며 머신러닝의 기본적인 스텝을 전반적으로 밟아보았다.
NaN값이란?
NA(Not Available) 혹은 NaN(Not a Number)라고 하며
- 사용할 수 없는 값
- 잘못 들어간 값
- 빈 값
등을 가리키는 값이다.
NaN값이 있는 행을 삭제하거나 다른 값으로 채워주는 등의 별도 처리가 필요하다. 특히 중요한 변수에 NaN 값이 있다면 모델링을 하기 전에 반드시 조치를 해놓아야 한다.
NaN 찾기
data.isnull().sum()
data.isna().sum()
# Date 0
# Open 5
# High 5
# Low 5
# Close 5
# Volume 5
# exch_Close 0
# exch_Diff 0
# dtype: int64
isnull(), isna() : 둘 다 똑같이 작동하는 NaN값인지를 판명하는 메서드이며 .sum()과 함께 사용하여 데이터프레임의 각 칼럼에서 NaN값의 개수를 세 준다.
data.info()
# <class 'pandas.core.frame.DataFrame'>
# Int64Index: 977 entries, 0 to 976
# Data columns (total 8 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 Date 977 non-null object
# 1 Open 972 non-null float64
# 2 High 972 non-null float64
# 3 Low 972 non-null float64
# 4 Close 972 non-null float64
# 5 Volume 972 non-null float64
# 6 exch_Close 977 non-null float64
# 7 exch_Diff 977 non-null float64
# dtypes: float64(7), object(1)
# memory usage: 68.7+ KB
.info() 메서드를 사용했을 때에도 Non-Null Count 항목을 통해 NaN 값의 개수를 알 수 있다.
[ NaN값 조치 방법 1 - 행을 제거 ]
.dropna(axis=0) 를 사용하여 행을 제거할 수 있다. axis=1이면 칼럼이 제거되는데 NaN값이 있는 칼럼을 통째로 삭제하는 것은 활용할 수 있는 데이터로서의 손실이 크므로 주로 행을 삭제해준다. (해당 칼럼에 NaN값이 훨씬 많은 등의 경우에는 칼럼을 삭제하는 것이 더 나을 수도 있다.)
data1 = data.dropna(axis=0)
data1.isnull().sum()
# Date 0
# Open 0
# High 0
# Low 0
# Close 0
# Volume 0
# exch_Close 0
# exch_Diff 0
# dtype: int64
지워진 행에 대해서는 인덱스가 지워진 채로 데이터프레임이 구성되기 때문에 인덱스를 재배치 하고 싶다면 .reset_index()를 해주면 된다.
[ NaN값 조치 방법 2 - 다른 값으로 채운다. ]
.fillna(method='ffill') 를 사용하여 이전 행의 값으로 채워줄 수 있다. method='bfill'일 경우에는 다음 행의 값으로 채워준다. method 옵션을 지정하지 않고 그냥 fillna(값)을 넣어서 원하는 값으로 채워 넣을 수도 있다.
(칼럼별로 다른 값을 넣을 때는 딕셔너리 형식으로 지정)
data2 = data.fillna(method='ffill')
data2.isnull().sum()
# Date 0
# Open 0
# High 0
# Low 0
# Close 0
# Volume 0
# exch_Close 0
# exch_Diff 0
# dtype: int64
채워넣을 값을 직접 지정해 줄 때에는 수치형 칼럼에는 mean()을 사용하여 구한 평균값을,
범주형 칼럼에는 mode()를 사용하여 구한 최빈값을 주로 사용한다.
[ NaN값 조치 방법 3 - 앞뒤값의 중간값으로 채우기 ]
.interpolate(method='linear') 를 사용하면 앞뒤값의 중간값으로 NaN 값을 채워준다. 시계열 데이터의 경우에는 행의 차례도 매우 중요하기 때문에 주로 시계열 데이터에 NaN값이 있을 때 사용한다.
data3 = data.interpolate(method='linear')
data3.isnull().sum()
# Date 0
# Open 0
# High 0
# Low 0
# Close 0
# Volume 0
# exch_Close 0
# exch_Diff 0
# dtype: int64
[ NaN값 조치 방법 4 - K-Nearest Neighbors ]
K-Nearest Neighbors 알고리즘의 원리를 사용해서 결측치를 채워주는 방법으로
sklearn.impute의 KNNImputer()를 사용하면 지정해준 k값에 따라 해당 데이터의 분포에서 가장 가까운 k개의 값의 평균으로 NaN값을 채워준다.
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=5) # KNNImputer 선언
x_test_filled = pd.DataFrame(imputer.fit_transform(x_test)) # 결측치 채우기
x_test_filled.columns = list(x_test) # 칼럼 이름 다시 붙여주기
스케일링과 비슷한 방식으로 fit_transform()으로 결측치를 채워준다.
KNNImputer로 결측치를 채우고나면 넘파이 배열의 형태로 값들을 반환하기 때문에 다시 데이터프레임으로 변환하면 칼럼의 이름들이 다 사라진 채로 칼럼 이름이 0부터 시작하는 인덱스값으로 바뀌어 있게 된다.
위의 코드에서는 x_test 데이터셋을 이어서 사용하기 위해 데이터프레임으로 변환 후 칼럼 이름을 다시 붙여주었다.
KNNImputer() 로 결측치를 채워주는 것이 다른 방식들보다 훨씬 합리적인 것 같다. 2차 미니프로젝트를 진행하면서 KNNImputer로 결측치를 채워줬을 때, 훨씬 좋은 결과가 나왔다.
결측치가 몇개 없는 데이터라면 다른 방식을 써도 괜찮겠지만 결측치가 많은 데이터를 채워주어야 할 경우에는 특정 값으로만 모두 채우는 것보다는 KNN과 같이 다른 데이터들과의 연관성을 찾아 최대한 비슷한 값으로 채워주는 방식을 사용하는 것이 좋을 것 같다고 생각한다.
가변수(Dummy Variable) 화
범주형 입력변수는 컴퓨터가 계산 가능한 숫자로 가변수화 하여 사용해야 한다. 가변수화는 숫자로 나타내긴 하지만 진짜 숫자의 형식이 아닌 의미상 숫자이다.
예를 들면 봄,여름,가을,겨울의 4계절을 나타내는 계절 칼럼이 있을 경우
계절 |
봄 |
여름 |
봄 |
가을 |
겨울 |
봄 | 여름 | 가을 | 겨울 |
1 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
1 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 0 | 0 | 1 |
와 같은 식으로 0과 1로만 해당 값을 판별할 수 있도록 바꿀 수 있다.
봄,여름,가을,겨울을 1,2,3,4의 숫자로 표현할 수 있지 않냐고 생각할 수도 있지만 이렇게 하게 되면 겨울은 여름의 2배라는 관계가 생겨버려 학습에 영향을 줄 수 있다. 따라서 서로 영향을 끼칠 수 없도록 이런 식의 one-hot encoding을 해 주어야 한다.
pd.get_dummies( df, columns=[ ], drop_first=True ) 를 사용해서 범주형 변수를 가변수화 시켜줄 수 있다.
파라미터로 해당하는 데이터프레임을 넣어주고 columns= 에 가변수화 시켜줄 칼럼들을 넣어준다.
drop_first=True는 첫 칼럼은 버린다는 뜻으로 어차피 한 변수는 나머지 변수들에 의해 결정될 수 있기 때문에 칼럼 하나를 빼주는 것이다. (모든 값이 0인 경우를 사용하면 되기 때문)
data2 데이터프레임의 'WeekDay' 칼럼의 범주형 요일 값들을 가변수화 시켜주었다.
# 가변수화 수행
dummy = pd.get_dummies(data2, columns=['WeekDay'], drop_first=True)
dummy.head()
WeekDay 칼럼은 사라지고 WeekDay_값 형식의 칼럼들이 생긴 것을 볼 수 있다.
Scaling
각 feature 별 범위가 달라서 생기는 왜곡을 방지하기 위한 기법으로 feature들의 범위를 맞춰준다.
주로 사용하는 scaling 기법으로는 Min-Max Scaling (Normalization)과 Standardization이 있다.
- Min-Max Scaling : feature의 최소~최대값이 0~1이 되도록 해줌
- Standardization : feature 값들의 평균이 0, 표준편차가 1이 되도록 해줌
아래 코드는 min-max scaling을 수행한 경우이다.
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# 선언하기
scaler = MinMaxScaler()
# 만들고 적용 .fit_transform() : .fit() + .transform()
x1 = scaler.fit_transform(x)
# 적용하고 나면 넘파이 어레이가 된다.
# 모델링할 때에는 넘파이 어레이여도 상관 없지만, 편하게 살펴보기 위해 데이터프레임으로 변환
x1 = pd.DataFrame(x1, columns = list(x))
x1.head()
MinMax 스케일링 시에는 사이킷런의 MinMaxScaler를 사용해준다.
MinMaxScaler 객체를 생성해준 뒤 fit_transform() 메서드를 적용해주면 scaling이 완료되는데 적용이 되고 나면 넘파이 어렝가 된다.
모델링에는 그대로 사용해도 상관 없지만 직관적으로 확인해보기 위해 데이터프레임으로 변환해준다.
그 밖에 Standardization과 간단한 모델링도 해보았는데 모델링은 다음 과정에서 제대로 배울 내용이고 Standardization보다는 min-man scaling이 많이 쓰이는 방법이라고 해서 이정도만 정리했다.
'KT AIVLE School' 카테고리의 다른 글
(3주차 - 22.08.11) 데이터 분석 및 의미 찾기 2 - Seaborn,이변량분석1 (0) | 2022.08.12 |
---|---|
(3주차 - 22.08.10) 데이터 분석 및 의미 찾기 1 (0) | 2022.08.10 |
(3주차 - 22.08.08) 데이터 처리1 (0) | 2022.08.08 |
(2주차 - 22.08.05) 웹크롤링3 (0) | 2022.08.05 |
(2주차 - 22.08.04) 웹크롤링2 (0) | 2022.08.04 |