Imitation, Imagination, Integration

Pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
0. Data 수집
- File Download
- API
- Crawling & Scraping
1. 도메인 지식 확보
- Docs를 읽어본다 (주어 졌을때만)
- 이미 내가 알고 있는 전문 분야를 활용한다
- 구글링
- 책
2. Data 불러오기
- Pandas Dataframe으로 불러오기
- (비정형 데이터인 경우는 찾아봐야함..)
3. Data 파악하기
- head로 대략적인 데이터 살피기
- Tidy Data인지 확인하기
- info로 데이터 정보 확인하기
- missing data 확인하기
- dtype 확인하기
4. Data 조작하기
- Wide Format인 경우 melt 하기
- missing data 처리하기
- dtype 확인하고 encoding 하기
- train - test set 분리하기
- 부적절한 data 값 수정하기
5. Data 분석하기 (EDA)
- describe로 대략적인 값의 특성 확인하기
- 그래프 그려 보기
- 왜도, 첨도 확인하기
- 데이터의 숨겨진 의미 파악하기
- 데이터 양이 충분한지 파악하기 (중심 극한 정리)
- Feature 갯수가 데이터의 양에 비해 많은지 확인하기 (오캄의 면도날)
6. Data 전처리하기
- Feature Selection
- Feature Scaling
- Dimensionality Reduction
7. 모델링 하기
- 기계학습 or 딥러닝
- 지도학습 or 비지도학습 or 강화학습
- 자연어 or 이미지 or 음성 처리
- 모델링 순서
- 알고리즘 비교하기
- 하이퍼 파라미터 찾기 (GridSearchCV)
8. 성능 테스트


도메인 지식 확보하기

  1. Data를 내려받아 쓰는 경우 Docs가 있다면 잘 읽어보고 데이터를 이해한다
  2. Docs가 없고 도메인 지식이 없을 경우 구글링을 하거나 책을 통해 공부한다
  3. 웬만하면 내가 관심있는 분야를 선정한다

데이터 불러오기

Pandas DataFrame에 맞게 불러온다


seaborn에서 불러올 때

1
2
3
4
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

file에서 불러올 때

1
2
3
import pandas as pd

iris = pd.read_csv('iris.csv', engine='python') # 필요에 따라 옵션이 달라질 수 있다.

Data 파악하기

1
2
3
4
5
6
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

iris.head(5)

head


Tidy Data인지 확인하기

데이터 양에 비해 Wide Format인지 아직 판단하기 이르지만

언뜻 봐서 melt할만한 Column은 없어보인다.

Wide Format 데이터의 양에 비해 Column이 많은 DataFrame, 즉 가로로 넓은 형태의 데이터 형태를 말한다.


info로 데이터 정보 확인하기

1
2
3
4
5
6
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

iris.info()

info


info로 알 수 있는 것들

1
2
3
4
5
1. 데이터 갯수  => 150개 (데이터 양이 적다. 하지만 예제 데이터이니 일단 한번 끝까지 해보자)
2. Feature 갯수 => 4개 (Data 150개에 4개 Feature면 적당한가? 아직 모름)
3. Dtype => Feature 4개 모두 float64 , target data인 species는 object (기계학습 할때 int나 float형으로 바꿔야 겠다)
4. Memory size => 6.0+KB (작다. 불러오는데 큰 문제 없음. memory size가 몇 이하여야 하는지는 잘 모름)
5. Missing Data => 없음

미싱데이터 시각화 하기

info로 미싱데이터를 확인 했지만 혹시 어정쩡하게 미싱 데이터가 있거나

미싱데이터의 분포를 쉽게 확인하려면 그래프를 그리자

1
2
3
4
5
6
import missingno as mino
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')
mino.matrix(iris)

mino


Label Encoding

info를 확인 했을 때 species data를 숫자형으로 바꿔야 된다고 판단 했었고 target 데이터의 값이 문자이면

학습을 할 수 없기 때문에 숫자로 인코딩 해준다 (인코딩과 동시에 dtype 자동변경)

Scikit LabelEncoder 활용하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import seaborn as sns
from sklearn.preprocessing import LabelEncoder

iris = sns.load_dataset('iris')
target = iris.iloc[:,-1]

le = LabelEncoder()
le.fit_transform(target)
: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
target = pd.DataFrame(le.fit_transform(target))
target.rename({0:'target'}, axis=1, inplace=True)

Replace 활용하기

1
2
3
4
5
6
7
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')
target = iris.iloc[:,-1]

target.replace({'setosa':0,'versicolor':1,'virginica':2}, inplace=True)

Train-Test Set 분리하기

Train, Test set을 분리할 때는 보유한 데이터의 숫자를 감안해서 쪼갠다

데이터의 갯수가 만개 이하일 때는 보통 Train : Test 비율 80 : 20 또는 75 : 25로 분할한다

그러나 그 이상으로 데이터가 많을 경우 최대한 Train 데이터 비율을 늘려 사용한다.

출처: Brunch

1
2
3
4
5
6
7
8
9
from sklearn.model_selection import train_test_split

# 관례상 행렬은 대문자, 벡터는 소문자로 표기
X_train, X_test, y_train, y_test = train_test_split(data, target)

len(X_train)
: 112
len(X_test)
: 38

데이터 분석하기

데이터의 숨은 의미를 찾아보자!


수치로 데이터 형태, 분포, 경향 확인하기

1
2
3
4
5
6
7
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

data = iris.iloc[:,:-1]
data.describe()

describe

describe 그래프로 보기

describe는 숫자로 나오기 때문에 한눈에 파악하기 힘들다

따라서 그래프로 확인!

1
2
3
4
5
6
7
8
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

data = iris.iloc[:,:-1]

data.boxplot()

boxplot

sepal_width 데이터에서 outlier, 즉 소수의 데이터가 데이터 분포에서 멀리 떨어져 있는 경우가 포착되었다.

하지만 데이터의 갯수도 적고 크게 벗어난 갖이 아니므로 그냥 냅두자


데이터간 산점도 그래프 그리기

1
2
3
4
5
6
7
import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

# hue는 색상 => 보통 target data를 서로 다른 색을 구분지어 칠하고 싶을때 사용
sns.pairplot(iris, hue='species')

pairplot2


왜도, 첨도 그래프 그리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

iris = sns.load_dataset('iris')
data = iris.iloc[:,:-1]

data.skew() # 왜도
: sepal_length 0.314911
sepal_width 0.318966
petal_length -0.274884
petal_width -0.102967
dtype: float64

data.kurt() # 첨도
: sepal_length -0.552064
sepal_width 0.228249
petal_length -1.402103
petal_width -1.340604
dtype: float64

f, axes = plt.subplots(2, 2, figsize=(7, 7), sharex=True)
sns.distplot(data.iloc[:,0], color="skyblue", ax=axes[0,0])
sns.distplot(data.iloc[:,1], color="olive", ax=axes[0,1])
sns.distplot(data.iloc[:,2], color="gold", ax=axes[1,0])
sns.distplot(data.iloc[:,3], color="teal", ax=axes[1,1])
for i, ax in enumerate(axes.reshape(-1)):
ax.text(x=0.97, y=0.97, transform=ax.transAxes, s="Skewness: %f" % data.iloc[:,i].skew(),\
fontweight='demibold', fontsize=10, verticalalignment='top', horizontalalignment='right',\
backgroundcolor='white', color='xkcd:poo brown')
ax.text(x=0.97, y=0.91, transform=ax.transAxes, s="Kurtosis: %f" % data.iloc[:,i].kurt(),\
fontweight='demibold', fontsize=10, verticalalignment='top', horizontalalignment='right',\
backgroundcolor='white', color='xkcd:dried blood')
plt.tight_layout()

skewkurt

왜도 왜도는 데이터가 대칭이 아닌 정도를 나타낸다. 만약 왜도의 값이 음수이면 오른쪽으로 치우친 정도를 나타내고 왜도의 값이 양수이면 왼쪽으로 치우친 정도를 나타낸다.

첨도 첨도는 데이터가 중간값 분포의 정도를 나타낸다. 보통 첨도의 값이 3보다 작으면 완만한 분포를 나타내고 첨도의 값이 3보다 크면 뾰족한 분포를 나타낸다. 지금 데이터에서는 음수면 완만 양수면 뾰족이라고 생각하면 된다.


Data 전처리하기

연습용 데이터라 딱히 전처리할게 없음.. 그래도 학습용으로 추후에 추가할 것.


모델링 하기

iris data는 정형데이터에 target data 갯수가 유한개 이므로 classification 방법 중

가장 무난한 logistic regression으로 분류를 시작해보자


Scikit으로 기계학습 하는 순서

1
2
3
4
1. 활용할 모델 이름 import
2. 인스턴스화
3. fit
4. predict

LogisticRegression

1
2
3
4
5
6
7
8
9
10
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(X_train, y_train)

: LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, l1_ratio=None, max_iter=100,
multi_class='warn', n_jobs=None, penalty='l2',
random_state=None, solver='warn', tol=0.0001, verbose=0,
warm_start=False)

성능 검사하기

Cross_val_score를 통해 대략적인 성능을 확인해보자


Cross_val_score

1
2
3
4
5
from sklearn.model_selection import cross_val_score

cross_val_score(lr, X_test, y_test, cv=10).mean()

: 0.835 # Accuracy

결과 분석 Logistic regression으로 분류하고 cross_val_score를 확인해본 결과 0.835라는 정확도가
나왔기 때문에 iris data는 앞으로 도전해볼 모델도 분류 모델임을 먼저 시도해보는 것이 좋을 것이라고 판단된다.


K-Means

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.neighbors import KNeighborsClassifier

knn = KNeighborsClassifier()
knn.fit(X_train, y_train)

: KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=None, n_neighbors=5, p=2,
weights='uniform')

cross_val_score(knn, X_test, y_test, cv=10).mean()

: 1

SVM

1
2
3
4
5
6
7
8
9
10
11
12
from sklearn.svm import SVC

svc = SVC()
svc.fit(X_train, y_train)

: SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
kernel='rbf', max_iter=-1, probability=False, random_state=None,
shrinking=True, tol=0.001, verbose=False)

cross_val_score(svc, X_test, y_test, cv=10).mean()
: 0.9800000000000001

Naive Bayes

1
2
3
4
5
6
7
8
9
from sklearn.naive_bayes import GaussianNB

gnb = GaussianNB()
gnb.fit(X_train, y_train)

: GaussianNB(priors=None, var_smoothing=1e-09)

cross_val_score(gnb, X_test, y_test, cv=10).mean()
: 0.96

학습 모델로 새로운 값 예측 해보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 학습된 값들  
lr.predict([[5.1, 3.5, 1.4, 0.2]]) # setosa
: array([0], dtype=int64)
lr.predict([[6.7, 3.1, 4.7, 1.5]]) # versicolor
: array([1], dtype=int64)
lr.predict([[7.7, 2.8, 6.7, 2.]]) # virginica
: array([2], dtype=int64)


# 새로운 값으로 예측하기

lr.predict([[4, 3, 1, 0.1]])
: array([0], dtype=int64)

lr.predict([[6, 3, 5, 1]])
: array([1], dtype=int64)

lr.predict([[7, 1, 5, 3]])
: array([2], dtype=int64)

Train - Test - split으로 정확도 보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import seaborn as sns
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix

iris = sns.load_dataset('iris')
iris.species = iris.species.map({'setosa': 0, 'versicolor':1,'virginica':2})

knn = KNeighborsClassifier()
iris_data = iris[iris.columns[:-1]]
iris['species']

knn.fit(iris_data, iris['species'])

X_train, X_test, y_train , y_test = train_test_split(iris[iris.columns[:-1]], iris.species)

knn.fit(X_train, y_train)
knn.predict(X_test)

: array([1, 1, 2, 2, 0, 1, 1, 1, 2, 1, 0, 0, 2, 0, 0, 1, 1, 2, 0, 2, 1, 2,
1, 1, 0, 1, 0, 0, 0, 2, 2, 0, 1, 0, 2, 2, 0, 2], dtype=int64)

knn.predict(X_test) == y_test.values

: array([ True, True, True, True, True, True, True, True, True,
True, True, True, False, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True])

confusion_matrix(y_test, knn.predict(X_test))

: array([[13, 0, 0],
[ 0, 13, 1],
[ 0, 0, 11]], dtype=int64)