Model fitting by python

python을 활용한 model fitting 하기

pythonscipy 라이브러리를 이용해 model fitting을 해보겠습니다. scipy.optimize.curve_fit 기능을 사용할때는 두가지가 필요합니다.

  1. 실제의 데이터
  2. model로 사용할 방정식

말로 설명하는 것 보다는 예를 들어가면서 살펴보도록 하죠.

  • 먼저 다양한 수학적 도구와 자료구조를 위해 numpy
  • Model fitting을 위해 scipy.optimize에서 curve_fit을 불러옵니다.
  • 마지막으로 시각화를 위해 matplotlib을 사용했습니다.
In [2]:
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

# notebook 안에 plot을 표시하는 매직명령어
%matplotlib inline

선형 회귀

간단한 선형회귀의 예를 들어보겠습니다.

선형 회귀(linear regression)는 종속 변수 y와 한 개 이상의 독립 변수 (또는 설명 변수) X와의 선형 상관 관계를 모델링하는 회귀분석 기법이다. 한 개의 설명 변수에 기반한 경우에는 단순 선형 회귀, 둘 이상의 설명 변수에 기반한 경우에는 다중 선형 회귀라고 한다. -- wikipedia

먼저 모델로 사용할 방정식을 python function으로 구현합니다.

In [3]:
## 일차방정식
def func(x, a, b):
    return a * x + b

이제 model fitting을 할 데이터가 필요한데요. 여기서는 numpy를 이용해 가상의 데이터를 만들어 보겠습니다.

In [4]:
# 0부터 10까지 100개의 구간으로 나눔
x = np.linspace(0, 10, 100)
print(x)
[  0.           0.1010101    0.2020202    0.3030303    0.4040404
   0.50505051   0.60606061   0.70707071   0.80808081   0.90909091
   1.01010101   1.11111111   1.21212121   1.31313131   1.41414141
   1.51515152   1.61616162   1.71717172   1.81818182   1.91919192
   2.02020202   2.12121212   2.22222222   2.32323232   2.42424242
   2.52525253   2.62626263   2.72727273   2.82828283   2.92929293
   3.03030303   3.13131313   3.23232323   3.33333333   3.43434343
   3.53535354   3.63636364   3.73737374   3.83838384   3.93939394
   4.04040404   4.14141414   4.24242424   4.34343434   4.44444444
   4.54545455   4.64646465   4.74747475   4.84848485   4.94949495
   5.05050505   5.15151515   5.25252525   5.35353535   5.45454545
   5.55555556   5.65656566   5.75757576   5.85858586   5.95959596
   6.06060606   6.16161616   6.26262626   6.36363636   6.46464646
   6.56565657   6.66666667   6.76767677   6.86868687   6.96969697
   7.07070707   7.17171717   7.27272727   7.37373737   7.47474747
   7.57575758   7.67676768   7.77777778   7.87878788   7.97979798
   8.08080808   8.18181818   8.28282828   8.38383838   8.48484848
   8.58585859   8.68686869   8.78787879   8.88888889   8.98989899
   9.09090909   9.19191919   9.29292929   9.39393939   9.49494949
   9.5959596    9.6969697    9.7979798    9.8989899   10.        ]
In [5]:
y = func(x, 1, 2)
# np.random.normal을 통해 0.9×N(0,1)의 난수를 특정 개수만큼 발생시켜서 y값에 더해주겠습니다.
np.random.seed(1)
yn = y + 0.9 * np.random.normal(size=len(x))

다음으로 curve_fit 기능을 사용해 model fitting을 합니다.

In [6]:
popt, pcov = curve_fit(func, x, yn)
# popt는 주어진 func 모델에서 가장 최고의 fit values를 보여줍니다.
# pcov의 대각성분들은 각 parameter들의 variances 입니다.
In [7]:
plt.scatter(x, yn, marker=".")
plt.plot(x, y, linewidth=2)
plt.plot(x, func(x, *popt), color="red", linewidth=2)
plt.legend(["not fit", "fitting"], loc=2)
plt.show()
No description has been provided for this image

빨간색으로 표현된것이 curve_fit을 통한 선형 회귀입니다.

Gaussian model을 fitting하는 것을 알아봅시다.

다른 예시로 가우시안 모델을 살펴 보겠습니다.

가우시안 모델(Gaussian model)은 자연적인 현상을 표현하기에 좋은 모델이기 때문에, 많은 분야에서 가우시안 모델이 사용될 수 있다. --wikipedia

전과 동일하게

  1. Model을 생성하고
  2. 실험데이터를 만든뒤
  3. curve_fit 기능을 사용합니다.
In [8]:
# Gaussian model을 생성합니다.
def func(x, a, b, c):
    return a * np.exp(-((x - b) ** 2) / (2 * c**2))


# 마찬가지로 0~10까지 100개 구간으로 나눈 x를 가지고
x = np.linspace(0, 10, 100)
y = func(x, 1, 5, 2)  # 답인 y들과
yn = y + 0.2 * np.random.normal(size=len(x))  # noise가 낀 y값들을 만듭니다.
## 그런 후에 curve_fit을 하고 best fit model의 결과를 출력합니다.
popt, pcov = curve_fit(func, x, yn)
In [9]:
plt.scatter(x, yn, marker=".")
plt.plot(x, y, linewidth=2, color="blue")
plt.plot(x, func(x, *popt), color="red", linewidth=2)
plt.legend(["Original", "Best Fit"], loc=2)
plt.show()
No description has been provided for this image

6~8 사이에서는 조금 차이가 나는 것을 확인할 수 있죠.

마지막으로 2개의 독립적인 Gaussian함수로 fitting하는 예제입니다.

방법은 동일합니다. 모델만 다를뿐이죠.

In [10]:
def func(x, a0, b0, c0, a1, b1, c1):
    return a0 * np.exp(-((x - b0) ** 2) / (2 * c0**2)) + a1 * np.exp(
        -((x - b1) ** 2) / (2 * c1**2)
    )


x = np.linspace(0, 20, 200)
y = func(x, 1, 3, 1, -2, 15, 0.5)
yn = y + 0.2 * np.random.normal(size=len(x))

# p0=Initial guess는 초기에 이 값들을 기준으로 optimal value를 찾으라는 설정값입니다.
initial_guess = [1, 3, 1, 1, 15, 1]
popt, pcov = curve_fit(func, x, yn, p0=initial_guess)

plt.scatter(x, yn, marker=".")
plt.plot(x, y, linewidth=2)
plt.plot(x, func(x, *popt), color="red", linewidth=2)
plt.legend(["Original", "Best Fit"], loc=2)
plt.show()
No description has been provided for this image

마치며

scipy로 model fitting하는 방법을 간단히 알아보았습니다. 먼저 Model을 생성하고 실험데이터에 curve_fit 기능을 사용한다는 것을 꼭 기억해주세요.

파이썬으로 랜덤 포레스트 분석

원문 출처

이 글에서는 기계학습의 알고리즘 중의 하나인 Random forest을 간략하게 사용해보도록 하겠습니다. 그래서 구체적인 Random forest의 이론은 생략하도록 할게요. 대신에 저와 같이 기계학습을 배우려는 초보자가 흥미를 느낄 방법론 위주로 작성했습니다.

파이썬의 유명 라이브러리인 Scikit-learn을 이용할거에요.

예제 데이터

Scikit-learn에는 예제로 사용할 수 있는 데이터가 이미 포함되어 있습니다. 가짜가 아닌 진짜 데이터들이고, 몇몇은 아주 유명한 것이죠. 여기서는 Iris 데이터를 써볼거에요.

In [2]:
import numpy as np
import pandas as pd
import seaborn as sns

%matplotlib inline

from sklearn import datasets

iris = datasets.load_iris()

Random forest으로 데이터 분류하기

첫번째로 우리는 아주 간단한 분류작업을 해보겠습니다. Iris데이터를 pandasdataframe으로 만들고 시각화 라이브러리인 seaborn으로 그림을 그려볼게요.

In [3]:
df = pd.DataFrame(iris.data, columns=iris.feature_names)

# sklearn provides the iris species as integer values since this is required for classification
# here we're just adding a column with the species names to the dataframe for visualisation
df["species"] = np.array([iris.target_names[i] for i in iris.target])

sns.pairplot(df, hue="species")
Out[3]:
<seaborn.axisgrid.PairGrid at 0x7f716547fd30>
No description has been provided for this image

그림이 아주 멋집니다. 자세히 살펴보면 파란색의 setosapetal lengthpetal width에서 다른것들과 구별이 되는것을 알 수 있구요. 다른 두 종은 구별이 쉬워 보이지는 않아 보입니다. 이 정도면 분석에 앞서 충분히 살펴본것 같군요.

본격적으로, 분석을 시작하도록 하죠. 먼저 데이터를 trainingtest 세트로 나누겠습니다. 보통 75/25의 비율로 나누기 때문에 우리도 일단은 그렇게 하도록 하겠습니다.

파이썬에서는 다음과 같이 한줄의 코드로 해결 할 수 있죠.

In [17]:
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    df[iris.feature_names],
    iris.target,
    test_size=0.25,
    stratify=iris.target,
    random_state=123456,
)

traning세트가 준비가 되었으니 Scikit-learn을 사용해 모델을 만들어 볼게요. 대부분의 설정은 기본값으로 두지만 out-of-bag estimateTrue 값으로 변경하겠습니다.

out-of-bag score은 예측이 얼마나 정확한가에 대한 추정을 수치로 나타낸 것입니다.

실제 예측의 정확도를 계산해서 두개의 값이 얼마나 비슷한지 보도록 할게요.

In [6]:
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_estimators=100, oob_score=True, random_state=123456)
rf.fit(X_train, y_train)
Out[6]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_split=1e-07, min_samples_leaf=1,
            min_samples_split=2, min_weight_fraction_leaf=0.0,
            n_estimators=100, n_jobs=1, oob_score=True,
            random_state=123456, verbose=0, warm_start=False)

이제 우리가 만든 모델을 가지고 test 세트를 분류해보겠습니다.

In [8]:
from sklearn.metrics import accuracy_score

predicted = rf.predict(X_test)
accuracy = accuracy_score(y_test, predicted)

print(f"Out-of-bag score estimate: {rf.oob_score_:.3}")
print(f"Mean accuracy score: {accuracy:.3}")
Out-of-bag score estimate: 0.973
Mean accuracy score: 0.933

두개의 값이 서로 비슷하네요. 하지만 주의할 점이 있습니다. 이러한 간단한 비교는 진짜로 우리가 제대로된 모델을 사용 하고 있다는 것을 의미 하지는 않습니다. 시각화를 통해 보다 구체적으로 보도록 하겠습니다.

In [11]:
from sklearn.metrics import confusion_matrix

cm = pd.DataFrame(
    confusion_matrix(y_test, predicted),
    columns=iris.target_names,
    index=iris.target_names,
)
sns.heatmap(cm, annot=True)
Out[11]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f70f7448320>
No description has been provided for this image

마치며

시각화를 통해 우리의 모델이 setosa는 정확히 분류해 내고 있지만, versicolorvirginica를 구별하는데는 애를 먹고 있다는 것을 알 수 있습니다.

이렇게 간단하게 파이썬으로 Random forest를 하는 방법을 알아 보았습니다. 다음에는 더 구체적이고 심화된 내용으로 찾아 뵙겠습니다.