태그 보관물: 파이썬 라이브러리를 활용한 머신러닝

“(번역개정판) 파이썬 라이브러리를 활용한 머신러닝” 주피터 노트북 업데이트 및 에러타 안내

<파이썬 라이브러리를 활용한 머신러닝>의 주피터 노트북을 사이킷런 0.24.1 버전에 맞추어 모두 재실행하여 깃허브에 업데이트했습니다. 또 사이킷런 버전 변화에 따른 에러타를 새로 추가했습니다. 아래 목록을 참고해 주세요.

이 책은 2017년에 처음 번역서가 출간되었고 2019년에 개정판을 냈습니다. 처음 출간 시에는 흑백이었지만 개정판을 내면서 컬러를 입혔습니다. 이렇게 오랫동안 생명력을 유지할 수 있었던 것은 많은 독자들 덕분입니다. 다시 한번 이 책을 선택해 주신 독자들에게 감사드립니다. 책을 읽은 시간이 결코 아깝지 않기를 바랄 뿐입니다.

감사합니다.

  1. (p29) Enthought Canopy 항목을 다음으로 교체합니다.
    ActivePython (https://www.activestate.com/products/python/)
    또 다른 범용 파이썬 배포판입니다. NumPy, SciPy, matplotlib, pandas, Jupyter, scikit-learn을 포함하고 있습니다. 무료로 사용할 수 있는 Community Edition과 기업을 위한 유료 버전도 있습니다. ActivePython은 파이썬 2.7, 3.5, 3.6을 지원하며 macOS, 윈도우, 리눅스에서 사용할 수 있습니다.
  2. (p34) 위에서 3번째 줄 “%matplotlib inline을 사용합니다” 뒤에 주석을 추가합니다. <주석>옮긴이_ IPython kernel 4.4.0부터는 %matplotlib inline 매직 명령을 사용하지 않더라도 맷플롯립 1.5 이상에서는 주피터 노트북에 바로 이미지가 출력됩니다.</주석>
  3. (p36) <노트>의 마지막 줄 “만약 이런 매직 커맨드를 사용하지 않는다면 이미지를 그리기 위해 plt.show 명령을 사용해야 합니다”를 “또는 IPython kernel 4.4.0과 맷플롯립 1.5 버전 이상을 사용한다고 가정합니다.”로 수정합니다.
  4. (p37) 1.6절 바로 위 문장 끝에서 “파이썬 3.7 업그레이드하세요”를 “파이썬 3.7 이상으로 업그레이드하세요”로 수정합니다.
  5. (p38) 주석에 포함된 블로그 링크 goo.gl/FYjbK3 을 bit.ly/2K73mA4 로 수정합니다.
  6. (p65) In [14] 코드 블럭 위 문장 끝 “이웃의 수를 3으로 지정합니다”에 주석을 추가합니다. <주석>옮긴이_ KNeighborsClassifier 클래스의 n_neighbors 매개변수 기본값은 5입니다.</주석>
  7. (p87) 22번 주석에서 “LogisticRegression의 solver 매개변수를 지정하지 않으면 scikit-learn 0.22 버전부터 기본값 이 liblinear에서 lbfgs로 변경된다는 경고 메세지가 출력됩니다.”를 삭제합니다. 23번 주석에서 “liblinear를 사용하는 LogisticRegression 과 LinearSVC는”를 “LogisticRegression 과 LinearSVC는”로 수정합니다.
  8. (p94) 28번 주석에서 마지막 문장 “multi_class 매개변수를 지정하지 않으면 0.22 버전부터 기본값이 ovr에서 auto로 변경된다는 경고가 출력됩니다“를 “0.22 버전부터는 multi_class의 기본값이 ‘ovr’에서 ‘auto’로 바뀌었습니다“로 수정합니다.
  9. (p106) 페이지 중간에서 “scikit-learn은 사전 가지치기만 지원합니다” 끝에 주석을 추가합니다. <주석>옮긴이_ 사이킷런 0.22 버전에서 비용 복잡도 기반의 사후 가지치기를 위한 ccp_alpha 매개변수가 추가되었습니다.</주석>
  10. (p113) In [67] 코드 블럭에서 X_train = data_train.date[:, np.newaxis]를 X_train = data_train.date.to_numpy()[:, np.newaxis]로 수정하고 X_all = ram_prices.date[:, np.newaxis]를 X_all = ram_prices.date.to_numpy()[:, np.newaxis]로 수정합니다.
  11. (p115) 42번 주석 끝에서 “0.25 버전에서는 삭제됩니다”를 “1.0 버전에서는 삭제됩니다”로 수정합니다.
  12. (p116) 44번 주석 “옮긴이_ n_estimators 매개변수의 기본값은 10입니다. n_estimators 매개변수를 지정하지 않으면 scikit-learn 0.22 버전부터 기 본값이 100으로 바뀐다는 경고가 출력됩니다”를 “scikit-learn 0.22 버전부터 n_estimators의 기본값이 10에서 100으로 바뀌었습니다.”로 수정합니다.
  13. (p142) Out [84] 에서 “훈련 세트 정확도: 1.00“을 “훈련 세트 정확도: 0.90“으로 수정하고 “테스트 세트 정확도: 0.63“을 “테스트 세트 정확도: 0.94“로 수정합니다. 그 아래 문장에서 “훈련 세트에는 완벽한 점수를 냈지만 테스트 세트에는 63% 정확도라서 이 모델은 상당히 과대적합되었습니다”를 “훈련 세트에는 90% 정확도를 냈지만 테스트 세트에는 94% 정확도라서 이 모델은 상당히 과소적합되었습니다”로 수정합니다.
  14. (p144) Out [88]에서 “훈련 세트 정확도: 0.948 테스트 세트 정확도: 0.951“를 “훈련 세트 정확도: 0.984 테스트 세트 정확도: 0.972“로 수정합니다. 그 아래 문단에서 “훈련 세트와 테스트 세트의 정확도가 100%에서는 조금 멀어졌지만 매우 비슷해서 확실히 과소적합된 상태입니다“를 “훈련 세트와 테스트 세트의 정확도가 모두 상승하여 과소적합이 많이 해소되었습니다“로 수정합니다. In [89] 코드 블럭에서 svc = SVC(C=1000)을 svc = SVC(C=20)으로 수정합니다.
  15. (p145) Out [89]에서 “테스트 세트 정확도: 0.972“를 “테스트 세트 정확도: 0.979“로 수정합니다. 그 아래 문장에서 “C 값을 증가시켰더니 모델의 성능이 97.2%로 향상되었습니다”를 “C 값을 증가시켰더니 모델의 성능이 97.9%로 향상되었습니다”로 수정합니다.
  16. (p152) In [96] 코드에서 mlp = MLPClassifier(solver='lbfgs', random_state=0, hidden_layer_size=[10, 10])를 mlp = MLPClassifier(solver='lbfgs', random_state=0, hidden_layer_size=[10, 10], max_iter=1000)로 수정합니다.
  17. (p159) 75번 주석에서 “『핸즈온 머신러닝』 (한빛미디어, 2018)”을 “『핸즈온 머신러닝 2판』 (한빛미디어, 2020)”로 수정합니다.
  18. (p170) In [122] 코드에서 logreg=LogisticRegression()을 logreg=LogisticRegression(max_iter=1000)로 수정합니다.
  19. (p191) In [11] 코드에서 svm = SVC(C=100)을 svm = SVC(gamma='auto')로 수정합니다.
  20. (p213) 주석 25번을 “NMF에서 초기화 방식을 지정하는 init 매개변수의 기본값은 None으로 n_components가 샘플이나 특성 개수보다 작으면 ‘nndsvd’를 사용하고 그렇지 않으면 ‘random’을 사용합니다. ‘nndsvd’는 특잇값 분해로 얻은 U와 V 행렬의 절댓값에 S 행렬의 제곱근을 곱해 W와 H 행렬을 만듭니다. 그다음 W와 H 행렬에서 1e-6 보다 작은 값은 0으로 만듭니다. ‘nndsvda’는 0을 입력 행렬의 평균값으로 바꿉니다. scikit-learn 1.1 버전부터는 ‘nndsvd’에서 ‘nndsvda’로 기본값이 바뀝니다. ‘random’은 데이터 평균을 성분의 개수로 나눈 후 제곱근을 구하고, 그런 다음 정규분포의 난수를 발생시켜 앞에서 구한 제곱근을 곱하여 H와 W 행렬을 만듭니다. 이는 데이터 평균값을 각 성분과 두 개의 행렬에 나누어 놓는 효과를 냅니다.”로 바꿉니다.
  21. (p214) In [37] 코드에서 mglearn.plots.plot_nmf_faces(X_train, X_test, image_shape)을 mglearn.plots.plot_nmf_faces(X_train, X_test[:3], image_shape)로 수정합니다.
  22. (p215) In [38] 코드에서 nmf = NMF(n_components=15, random_state=0, max_iter=1000, tol=1e-2)를 nmf = NMF(n_components=15, init='nndsvd', random_state=0, max_iter=1000, tol=1e-2)로 수정합니다.
  23. (p218) In [42] 코드에서 nmf = NMF(n_components=3, random_state=42, max_iter=1000, tol=1e-2)를 nmf = NMF(n_components=3, init=’nndsvd’, random_state=42, max_iter=1000, tol=1e-2)로 수정합니다.
  24. (p234) In [50] 코드에서 nmf = NMF(n_components=100, random_state=0, max_iter=1000, tol=1e-2)를 nmf = NMF(n_components=100, init=’nndsvd’, random_state=0, max_iter=1000, tol=1e-2)로 수정합니다.
  25. (p238) 주석 35 끝에 다음 문장을 추가합니다. “scikit-learn 0.23 버전부터 KMeans 클래스는 OpenMP 기반의 병렬화를 제공합니다. 이 때문에 n_jobs 매개변수를 사용하면 경고가 발생하며 이 매개변수는 1.0 버전에서 삭제될 예정입니다.”
  26. (p284) 주석 10번에서 다음 문장을 삭제합니다. “0.20.1 버전 이상에서 (열_리스트, 변환기_객체) 로 전달하면 이와 관련된 경고가 발생하며 0.22 버전에서는 (열_리스트, 변환기_객체) 형식이 삭제될 예정입니다.”
  27. (p309) 주석 31번을 삭제하고 4.7.3절 아래 4번째 줄 “도달할 때까지 하나씩 추가하는 방법입니다.” 끝에 다음 주석을 추가합니다. <주석>옮긴이_ 이를 전진 선택법(foward stepwise selection)과 후진 선택법(backward stepwise selection)이라고도 부릅니다. scikit-learn 0.24 버전에서 추가된 SequentialFeatureSelector 클래스는 scoring 매개변수에 지정된 측정 지표의 교차 검증 점수를 기준으로 특성을 하나씩 추가하거나 제거합니다. scoring 매개변수의 기본값은 회귀일 경우에는 R^2, 분류일 경우에는 정확도입니다. direction 매개변수가 ‘forward’일 경우 전진 선택법, ‘backward’일 때 후진 선택법을 수행합니다. 기본값은 ‘forward’입니다.</주석>
  28. (p318) 주석 39번에서 다음 문장을 삭제합니다. “0.20 버전부터 정수형 데이터를 변환할 때 이와 관련된 경고가 출력됩니다.”
  29. (p325) Out [5]의 출력을 “[0.967 1. 0.933 0.967 1. ]”로 바꿉니다. 아래에서 3번째 줄에 “여기에서는 cross_val_score가 3-겹 교차 검증을 수행했기 때문에 3개의 점수가 반환되었습니다. 현재 scikit-learn의 기본값은 3-겹 교차 검증이이지만 scikit-learn 0.22 버전부터 5-겹 교차 검증으로 바뀔 것입니다”를 “여기에서는 cross_val_score가 5-겹 교차 검증을 수행했기 때문에 5개의 점수가 반환되었습니다. scikit-learn 0.22 버전부터 3-겹 교차 검증에서 5-겹 교차 검증으로 바뀌었습니다“로 수정합니다.
  30. (p326) In [6] 코드에서 scores = cross_val_score(logreg, iris.data, iris.target, cv=5)를 scores = cross_val_score(logreg, iris.data, iris.target, cv=10)로 수정합니다. Out [6]의 출력을 “교차 검증 점수: [1. 0.933 1. 1. 0.933 0.933 0.933 1. 1. 1. ]”로 바꿉니다. Out [7] 출력 아래 문장에서 “5-겹 교차 검증이 만든 다섯 개의 값을 모두 보면 100%에서 90%까지 폴드에 따라”를 “10-겹 교차 검증이 만든 다섯 개의 값을 모두 보면 100%에서 93%까지 폴드에 따라”로 수정합니다.
  31. (p346) 주석 14번을 삭제하고 주석 13번 끝에 다음 문장을 추가합니다. “사이킷런 0.24 버전에서는 SH(Successive Halving) 방식의 HalvingGridSearchCV가 추가되었습니다. 이 클래스는 모든 파라미터 조합에 대해 제한된 자원으로 그리드서치를 실행한 다음 가장 좋은 후보를 골라서 더 많은 자원을 투여하는 식으로 반복적으로 탐색을 수행합니다.”
  32. (p440, p441) In [43], In [45] 코드에서 spacy.load('en'을 spacy.load('en_core_web_sm'으로 수정합니다.
  33. (p458) 주석 35에서 “『텐서플로 첫걸음』(한빛미디어, 2016)”를 “『혼자 공부하는 머신러닝+딥러닝』(한빛미디어, 2020)”로 수정합니다.
  34. (p463) 위에서 2번째 줄에 “goo.gl/fkQWsN”을 “bit.ly/3c7ylYV”로 수정합니다.
  35. (p467) 주석 9번에서 “『핸즈온 머신러닝』 (한빛미디어, 2018)”를 “『핸즈온 머신러닝 2판』 (한빛미디어, 2020)”로 수정합니다.
  36. (p468) 위에서 2번째 줄에 “goo.gl/lQmL1X”을 “bit.ly/3qnikDx”로 수정합니다.

“파이썬 라이브러리를 활용한 머신러닝” 사이킷런 0.20 업데이트

사이킷런 0.20 버전이 릴리스되었습니다. <파이썬 라이브러리를 활용한 머신러닝> 도서에 영향을 미치는 부분을 정리하여 에러타로 등록하였습니다. 깃허브의 코드도 최신 라이브러리 버전에서 모두 재실행하여 커밋하였습니다. 자세한 변경 내용은 <파이썬 라이브러리를 활용한 머신러닝>의 에러타 페이지를 참고해 주세요. 다음은 주요 변경 내용입니다.

  • 사이킷런 0.19 버전 이하에서는 LinearSVC와 liblinear를 사용하는 LogisticRegression의 verbose 매개변수가 0이 아니고 max_iter 반복 안에 수렴하지 않을 경우 반복 횟수를 증가하라는 경고 메세지가 나옵니다. 사이킷런 0.20 버전부터는 verbose 매개변수에 상관없이 max_iter 반복 안에 수렴하지 않을 경우 반복 횟수 증가 경고가 나옵니다. 경고 메세지를 피하기 위해 max_iter 매개변수의 기본값을 증가시킵니다.
  • 향후 사이킷런 0.22 버전에서 LogisticRegression 클래스의 solver 매개변수 기본값이 liblinear에서 lbfgs로 변경될 예정입니다. 사이킷런 0.20 버전에서 solver 매개변수를 지정하지 않는 경우 이에 대한 경고 메세지를 출력합니다. 경고 메세지를 피하고 출력 결과를 일관되게 유지하기 위하여 solver 매개변수를 liblinear로 설정합니다.
  • 사이킷런 0.20 버전에서 LogisticRegression의 multi_class 매개변수 옵션에 auto가 추가되었습니다. auto로 설정하면 이진 분류이거나 solver가 liblinear일 경우에는 ovr을 선택하고 그 외에는 multinomial을 선택합니다. 사이킷런 0.22 버전부터는 multi_class 매개변수의 기본값이 ovr에서 auto로 변경됩니다. 경고 메세지를 피하기 위해 명시적으로 ovr 옵션을 지정합니다.
  • 사이킷런 0.20 버전에서 SVC ​클래스의 gamma 매개변수 옵션에 auto외에 scale이 추가되었습니다. auto는 1/n_features, 즉 특성 개수의 역수입니다. scale은 1/(n_features * X.std())로 스케일 조정이 되지 않은 특성에서 더 좋은 결과를 만듭니다. 사이킷런 0.22 버전부터는 gamma 매개변수의 기본값이 auto에서 scale로 변경됩니다. 서포트 벡터 머신을 사용하기 전에 특성을 표준화 전처리하면 scale과 auto는 차이가 없습니다. 경고를 피하기 위해 명시적으로 auto 옵션을 지정합니다.
  • 사이킷런 0.22 버전에서 OneHotEncoder 클래스가 데이터에서 정수 카테고리를 인식하는 방식이 변경될 예정입니다. 종전에는 훈련 데이터에 나타난 0~최댓값 사이 범위를 카테고리로 인식하여 원-핫 인코딩하지만 0.22 버전부터는 고유한 정수 값을 카테고리로 사용합니다. 후자의 경우 0~최댓값 사이의 정수라도 훈련 데이터에 없는 값을 변환하려면 에러가 발생합니다. 경고 메세지를 피하고 고유한 정수 값을 사용하는 방식을 선택하려면 categories 매개변수를 auto로 지정합니다.
  • 사이킷런 0.22 버전에서 cross_val_score 함수와 GridSearchCV 클래스의 cv 매개변수 기본값이 3에서 5로 바뀔 예정입니다. 0.20 버전에서 cv 매개변수를 지정하지 않는 경우 이에 관한 경고 메세지가 출력됩니다. 경고 메세지를 피하기 위해 cv 매개변수 값을 명시적으로 3으로 지정합니다.
  • 사이킷런 0.22 버전부터는 GridSearchCV와 RandomizedSearchCV의 iid 매개변수 기본값이 True에서 False로 바뀝니다. 0.24 버전에서는 이 매개변수가 아예 삭제될 예정입니다. iid 매개변수가 True이면 독립 동일 분포라고 가정하고 테스트 세트의 샘플 수로 폴드의 점수를 가중 평균합니다. False로 지정하면 단순한 폴드 점수의 평균입니다. False일 때 기본 교차 검증과 동작 방식이 같습니다. 사이킷런 0.20 버전에서 iid 매개변수가 기본값일 때 가중 평균과 단순 평균의 차이가 10^-4 이상이면 경고 메세지가 발생합니다. 경고 메세지를 피하기 위해 GridSearchCV의 iid 매개변수를 True로 설정합니다.

더욱 랜덤한 포레스트-익스트림 랜덤 트리(ExtraTreesClassifier)

파이썬 라이브러리를을 활용한 머신러닝‘ 2장의 지도학습에서 대표적인 앙상블 모델로 랜덤 포레스트를 소개하고 있습니다. 랜덤 포레스트는 부스트랩 샘플과 랜덤한 후보 특성들을 사용해 여러개의 결정 트리decision tree를 앙상블 합니다. 그래서 훈련 데이터에 과대적합을 막아주고 모델의 일반화 성능이 항상 단일 트리보다 높습니다. 랜덤 포레스트 모델의 변종으로 익스트림 랜덤 트리extremely randomized trees 혹은 엑스트라 트리ExtraTrees라 부르는 모델이 있습니다. 엑스트라 트리는 포레스트 트리의 각 후보 특성을 무작위로 분할하는 식으로 무작위성을 증가 시킵니다. Scikit-Learn은 앙상블 패키지 안에 엑스트라 트리 모델을 제공합니다.

from sklearn.ensemble import ExtraTreesClassifier

​RandomForestClassifier 클래스가 사용하는 결정 트리는 DecisionTreeClassifier입니다. 이에 반해 ExtraTreesClassifier가 사용하는 결정 트리는 ExtraTreeClassifier입니다. 이름이 매우 비슷하니 유의하세요. ExtraTreesClassifier의 매개변수는 RandomForestClassifier와 동일합니다. 책에서와 같이 make_moons 데이터셋에 엑스트라 트리를 학습시켜 보겠습니다.

X, y = make_moons(n_samples=100, noise=0.25, random_state=3)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, 
                                                    random_state=42)

xtree = ExtraTreesClassifier(n_estimators=5, random_state=2)
xtree.fit(X_train, y_train)

엑스트라 트리가 사용하는 ExtraTreeClassifier()의 기본값으로 베이스 트리가 만들어 집니다. 랜덤 포레스트와 같이 베이스 모델을 직접 만들어 주입할 수는 없습니다. 엑스트라 트리가 만든 베이스 트리와 전체의 결정 경계를 그려 보겠습니다.

extratrees

그래프에서 볼 수 있듯이 랜덤 포레스트가 만든 것보다 두 클래스의 경계를 잘 구분하고 있습니다. 사실 엑스트라 트리의 베이스 트리인 ExtraTreeClassifier는 DecisionTreeClassifier를 상속한 것이며 splitter=’best’가 아니고 splitter=’random’인 것과 max_features=’auto’인 것을 제외하고는 동일합니다.

이번에는 cancer 데이터셋에 적용해 보겠습니다.

X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, 
                                                    random_state=0)
xtree = ExtraTreesClassifier(n_estimators=100, random_state=0)
xtree.fit(X_train, y_train)

print("훈련 세트 정확도: {:.3f}".format(xtree.score(X_train, y_train)))
print("테스트 세트 정확도: {:.3f}".format(xtree.score(X_test, y_test)))

훈련 세트 정확도: 1.000
테스트 세트 정확도: 0.972

훈련 세트와 테스트 세트에서의 정확도는 랜덤 포레스트와 동일합니다. 하지만 특성 중요도를 그려보면 차이점을 발견할 수 있습니다.

extratree_feature_importance_

이 그래프에서 볼 수 있듯이 엑스트라 트리가 랜덤 포레스트 보다 전반적으로 특성의 중요도를 더 높게 평가하고 있습니다. 이는 엑스트라 트리가 더 폭넓은 시각으로 특성들을 평가한다고 생각할 수 있습니다. 단일 결정 트리에서는 ‘worst radius’가 거의 독점적으로 주요한 특성으로 평가되었지만 랜덤 포레스트는 ‘worst perimeter’가 더 높았고 ‘worst area’는 훨씬 더 낮게  나왔습니다. 이에 비해 엑스트라 트리는 ‘worst area’, ‘worst perimeter’, ‘worst radius’, ‘mean concavity’ 등의 특성 중요도가 비교적 고르게 나온 것을 볼 수 있습니다.

당연히 회귀에 대응하는 엑스트라 트리인 ExtraTreesRegressor도 있습니다. ExtraTreesClassifier와 ExtraTreesRegressor의 매개변수 기본값은 부스트랩 샘플을 사용하지 않도록 bootstrap=False인 것을 제외하고는 랜덤 포레스트와 동일합니다. 이 포스트의 코드는 깃허브(https://github.com/rickiepark/introduction_to_ml_with_python/blob/master/ExtraTreesClassifier.ipynb)에서 확인하실 수 있습니다.

‘파이썬 라이브러리를 활용한 머신러닝’ 1, 2장

번역서 “파이썬 라이브러리를 활용한 머신러닝“의 1장과 2장의 내용을 담은 파이썬 머신러닝 페이지를 올렸습니다! 공개를 허락해 주신 한빛미디어에 다시 한번 감사의 말씀을 드립니다.

이 책의 1장과 2장은 지도 학습에 관련된 scikit-learn의 주요 클래스들을 다루고 있습니다. 여러 사람에게 유용한 자료가 되었으면 좋겠습니다. 최대한 출판된 책과 동일하게 포스트를 만들었는데 혹시 에러타가 있다면 언제든지 알려 주세요. 그럼 재미있게 읽어 주세요! 🙂

‘파이썬 라이브러리를 활용한 머신러닝’ 출간

b6119391002_lscikit-learn의 코어 개발자이자 배포 관리자인 안드레아스 뮐러Andreas Mueller와 매쉬어블의 데이터 과학자인 세라 가이도Sarah Guido가 쓴 ‘Introduction to Machine Learning with Python‘를 번역한 ‘파이썬 라이브러리를 활용한 머신러닝‘을 출간하였습니다.

출간 직전에 원서가 새로 릴리즈되어서 한바탕 소동을 벌이기는 등 이런 저런 일들이 오랜 작업 기간동안 생겼던 것 같습니다. 추운 겨울에 시작한 일을 한 여름이 되어서야 내놓게 되었네요. 책은 출간이 새로운 시작인 것 같습니다. 에러타나 궁금한 점 등 어떤 이야기도 괜찮습니다. 도서 페이지에 있는 양식을 통해 자유롭게 보내 주세요.

그리고 혹, 서점에 가시면 잘 보이는 곳으로 옮겨놔 주세요! 🙂

(업데이트) 번역서의 1장, 2장 전체를 블로그에 공개할 예정입니다. 공개를 허락해 주신 한빛미디어에 깊이 감사드립니다. 원고를 정리해서 올릴려면 1주일 정도 걸릴 것 같습니다. 😀