리팩토링이란 소프트웨어를 보다 쉽게 이해할 수 있고, 적은 비용으로 수정할 수 있도록 겉으로 보이는 동작의 변화 없이 내부 구조를 변경하는 것.
Refactoring의 이유
- 코드를 정돈하여 중복된 부분을 제거
- 코드를 이해하면서 내부 구조를 바꾸는것으로 명확해져서 이해가 쉬워짐
- 코드의 이해가 쉬워 지면서 자동으로 버그를 알게 되어 Robust한 코드를 작성 하게 도와준다
- 코드디자인을 향상시키며,이는 곧 디자인이 나빠지는 것을 멈추게 하며, 소프트웨어를 보다 빨리 개발 할 수 있도록 도와준다.
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Refactoring 해야하는 시기
- The Rule of Tree
Don Roberts의 가이드 라인에 따르면, 처음 뭔가를 할때는 그냥 해라, 두번째 비슷하게 뭔가를 할때는 위축되더라도 어찌되었던 duplicate해라. 세번째 비슷하게 뭔가 할때는 리팩터링을 해라. - Comprehension Refactoring: Making Code Easier to Understand / Making It Easier to Add a Feature
코드를 수정하려고 할때 그 코드나 자기 자신 혹은 누군가에 의해 쓰여졌더라도 그 코드가 어떻게 작동하는지 알아야한다. 직관적으로 이해하기 쉽게 리팩토링 되었는지 자문자답하면서 해보기. - 버그를 수정해야 할 때 Refactoring을 하라
버그 리포트를 받으면, 그것은 Refactoring이 필요하다는 신호인데, 왜냐하면 버그가 있었다는 것을 몰랐을 정도로 코드가 명확하지 않았다는 뜻이기 때문이다. - 코드 검토(Code Review)를 할 때 Refactoring을 하라
Refactoring은 다른 사람의 코드를 검토하는데 도움이 된다. 이렇게 함으로써, 코드가 어떻게 보일지 더욱 명확하게 알 수 있다.
ref.
https://ehsangazar.com/what-is-refactoring-d141abf596d1
1. 데이터의 수집
import pandas as pd
# 타이타닉 데이터 셋을 불러온다
url = "https://biostat.app.vumc.org/wiki/pub/Main/DataSets/titanic3.xls"
df = pd.read_excel(url)
orig_df = df
df.columns
Index(['pclass', 'survived', 'name', 'sex', 'age', 'sibsp', 'parch', 'ticket', 'fare', 'cabin', 'embarked', 'boat', 'body', 'home.dest'], dtype='object')
# 결측치 부분 마스크 처리 하기
mask = df.isnull().any(axis=1)
mask.head()
0 True
1 True
2 True
3 True
4 True
dtype: bool
# body 컬럼의 결측값
df[mask].body.head()
0 NaN
1 NaN
2 NaN
3 135.0
4 NaN
5 NaN
6 NaN
7 NaN
8 NaN
9 22.0
Name: body, dtype: float64
df.sex.value_counts(dropna=False)
male 843
female 466
Name: sex, dtype: int64
df.embarked.value_counts(dropna=False)
S 914
C 270
Q 123
NaN 2
Name: embarked, dtype: int64
2. 특징생성
name = df.name
name.head(3)
0 Allen, Miss. Elisabeth Walton
1 Allison, Master. Hudson Trevor
2 Allison, Miss. Helen Loraine
Name: name, dtype: object
df = df.drop(
columns=["name",
"ticket",
"home.dest",
"boat",
"body",
"cabin"]
)
df.columns
Index(['pclass', 'survived', 'sex', 'age', 'sibsp', 'parch', 'fare', 'embarked'], dtype='object')
y = df.survived
X = df.drop(columns="survived")
print(X, y)
pclass sex age sibsp parch fare embarked
0 1 female 29.0000 0 0 211.3375 S
1 1 male 0.9167 1 2 151.5500 S
2 1 female 2.0000 1 2 151.5500 S
3 1 male 30.0000 1 2 151.5500 S
4 1 female 25.0000 1 2 151.5500 S
... ... ... ... ... ... ... ...
1304 3 female 14.5000 1 0 14.4542 C
1305 3 female NaN 1 0 14.4542 C
1306 3 male 26.5000 0 0 7.2250 C
1307 3 male 27.0000 0 0 7.2250 C
1308 3 male 29.0000 0 0 7.8750 S
[1309 rows x 7 columns]
0 1
1 1
2 0
3 0
4 0
..
1304 0
1305 0
1306 0
1307 0
1308 0
Name: survived, Length: 1309, dtype: int64
3. 샘플 데이터
from sklearn.model_selection import train_test_split
X_train1, X_test1, y_train1, y_test1 = train_test_split(X, y, test_size=0.3, random_state=42)
X_train1.shape, X_test1.shape, y_train1.shape, y_test1.shape
((916, 7), (393, 7), (916,), (393,))
4. 리팩터링
import numpy as np
from sklearn.experimental import enable_iterative_imputer
from sklearn.preprocessing import StandardScaler
from sklearn.impute import IterativeImputer
#특징 생성의 부분 리팩터링
def tweak_titanic(df):
df = df.drop(
columns=[
"name",
"ticket",
"home.dest",
"boat",
"body",
"cabin",
]
).pipe(pd.get_dummies, drop_first=True)
return df
# 샘플데이터 생성 부분 리팩터링
def get_train_test_X_y(df, y_col, size=0.3, std_cols=None):
y = df[y_col]
X = df.drop(columns=y_col)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=size, random_state=42
)
cols = X.columns
num_cols = [
"pclass",
"age",
"sibsp",
"parch",
"fare",
]
fi = IterativeImputer()
X_train.loc[:, num_cols] = fi.fit_transform(X_train[num_cols])
X_test.loc[:, num_cols] = fi.transform(X_test[num_cols])
if std_cols:
std = StandardScaler()
X_train.loc[:, std_cols] = std.fit_transform(X_train[std_cols])
X_test.loc[:, std_cols] = std.transform(X_test[std_cols])
return X_train, X_test, y_train, y_test
ti_df = tweak_titanic(orig_df)
std_cols = "pclass,age,sibsp,fare".split(",")
X_train, X_test, y_train, y_test = get_train_test_X_y(ti_df, "survived", std_cols=std_cols)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
((916, 8), (393, 8), (916,), (393,))
5. 모델 만들기
from sklearn import ensemble
rf = ensemble.RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None, criterion='gini', max_depth=None, max_features='auto', max_leaf_nodes=None, max_samples=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_jobs=None, oob_score=False, random_state=42, verbose=0, warm_start=False)
6. 모델의 평가
rf.score(X_test, y_test)
0.7837150127226463
from sklearn import metrics
metrics.precision_score(y_test, rf.predict(X_test))
0.7916666666666666
for col, val in sorted(zip(X_train.columns,
rf.feature_importances_),
key=lambda x: x[1],
reverse=True)[:5]:
print(f"{col:10}{val:10.3f}")
age 0.285
fare 0.262
sex_male 0.241
pclass 0.089
sibsp 0.050
7. 모델의 최적화
from sklearn import model_selection
rf4 = ensemble.RandomForestClassifier()
params = {
"max_features": [0.4, "auto"],
"n_estimators": [15, 200],
"min_samples_leaf": [1, 0.1],
"random_state": [42],
}
cv = model_selection.GridSearchCV(rf4, params, n_jobs=-1).fit(X_train, y_train)
print(cv.best_params_)
{'max_features': 0.4, 'min_samples_leaf': 1, 'n_estimators': 200, 'random_state': 42}
rf5 = ensemble.RandomForestClassifier(
**{
"max_features": "auto",
"min_samples_leaf": 0.1,
"n_estimators": 200,
"random_state": 42,
}
)
rf5.fit(X_train, y_train)
rf5.score(X_test, y_test)
0.7073791348600509
마무리
- 중요한 것은 단순한 파이썬 코드작성이 아닌 특정 목적을 위한 복합적인 활용을 해야 한다는 것입니다.
- 애플리케이션 개발을 위한 코드작성이 아닌 데이터를 잘 다루기 위한 코드개선을 생각하셔야 합니다.
- 위의 내용은 메소드와 최적화에 집중한 코드를 담았습니다. 추가적인 학습을 원하시는 분들은 아래 사이트에서 학습을 진행하시길 바랍니다 :
- 머신러닝을 위한 메소드
'Computer Science' 카테고리의 다른 글
[Computer Science] 자료구조 - 트리 tree, 순회 traversal 알고리즘 (0) | 2021.10.04 |
---|---|
[Computer Science] 자료구조 - ADT(추상자료형) / linked-list/ Stack / Queue !!! (0) | 2021.10.04 |
[Computer Science] 예외처리(exception handling) - if ~else / try~except (0) | 2021.09.22 |
[Computer Science] 변수설계 - 지역변수와 전역변수 (0) | 2021.09.21 |
[Computer Science] 컴프리헨션(comprehension) (0) | 2021.09.21 |