Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
전산물리학:선형_회귀_분석_linear_regression_analysis [2022/01/15 00:09] – created jonghoon | 전산물리학:선형_회귀_분석_linear_regression_analysis [2023/09/05 15:46] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
선형 회귀 분석(Linear regression analysis)은 $x$와 $y$의 값을 알고 있을 때, $y = ax +b$의 꼴에서 $a$와 $b$의 값을 추측하는데 사용하는 방법이다. | 선형 회귀 분석(Linear regression analysis)은 $x$와 $y$의 값을 알고 있을 때, $y = ax +b$의 꼴에서 $a$와 $b$의 값을 추측하는데 사용하는 방법이다. | ||
+ | 데이터 포인트 하나만 가지고는 $a$와 $b$값을 추론할 수 없기 때문에 $x$에 대한 $y$ 데이터가 많이 있을 때 함수 형태가 어떻게 되는지 추론할 때 쓰인다. | ||
+ | 데이터의 수가 많기 때문에 아래와 같이 행렬 꼴로 많이 쓰인다. | ||
+ | $$ \mathbf{Y} = a\mathbf{X} + b $$ | ||
+ | |||
+ | 이 때, $\mathbf{Y} = (y_1, y_2, y_3, \ldots)^\intercal$, | ||
+ | |||
+ | 그 중 널리 쓰이는 방법이 최소제곱법(Least-square fitting)이다. 최소제곱법은 데이터로 얻은 $\mathbf{Y}$와 우리가 추론한 함수의 결과인 $f(\mathbf{X})$ 사이의 오차의 제곱을 최소화 하는 함수 $f(x)$를 찾는 방법이다. 즉, 다음의 식에서 $\chi^2$를 최소화하는 함수 $f(x)$를 찾는 것이다. | ||
+ | $$ \chi^2 = \sum_{i=1}^{N}\left(\frac{y_i - f(x_i)}{\sigma_i}\right)^2$$ | ||
+ | |||
+ | Python의 경우 scipy의 curve_fitting 함수를 사용할 수 있고, C/C++의 경우 gsl(gnu scientific library)의 gsl_fit_linear 혹은 gsl_fit_wlinear를 사용할 수 있다. 데이터에 표준오차가 포함되어 있는 경우에는 wlinear를, 포함되지 않은 경우에는 linear를 사용한다. wlinear를 쓸 때는 표준오차 값의 제곱의 역수를 w값으로 넣어줘야 한다. gsl의 경우 | ||
+ | $$\chi^2 = w(y-f(x))^2; | ||
+ | 으로 계산하기 때문이다. | ||
+ | |||
+ | scipy를 쓸 때는 표준오차가 포함되어 있는 경우에는 absolute_sigma 옵션을 True로 줘야 한다. | ||
+ | ====== 실습 ======= | ||
+ | 다음의 데이터를 예로 각 언어로 적합(fitting)해보자. | ||
+ | |||
+ | ^ x ^ y ^ $\sigma$ ^ | ||
+ | | 0.0 | 1.5891700001638700 | 0.5320185951347170 | | ||
+ | | 0.25 | 1.2046979031630900 | 0.45427229254919400 | | ||
+ | | 0.5 | 2.598484110379440 | 0.5077027054798450 | | ||
+ | | 0.75 | 2.2043375760987900 | 0.5205826529502230 | | ||
+ | | 1.0 | 3.002229375836470 | 0.4698090780151540 | | ||
+ | | 1.25 | 2.928655222350250 | 0.4773624121076510 | | ||
+ | | 1.5 | 3.4769844321649000 | 0.5018787752525470 | | ||
+ | | 1.75 | 4.007335261529810 | 0.4897362325985810 | | ||
+ | | 2.0 | 4.534192485682100 | 0.49462141854510300 | | ||
+ | | 2.25 | 5.76185759925369 | 0.5405394898833090 | | ||
+ | | 2.5 | 6.41954394976063 | 0.4523449367708450 | | ||
+ | | 2.75 | 6.023919923933230 | 0.48898047501417500 | | ||
+ | | 3.0 | 7.443742735575060 | 0.5342659697011440 | | ||
+ | | 3.25 | 7.870686775946450 | 0.4730380798563350 | | ||
+ | | 3.5 | 8.022587710435350 | 0.4572104512757930 | | ||
+ | | 3.75 | 9.395420889477870 | 0.49902577926821200 | | ||
+ | | 4.0 | 9.948288024421440 | 0.530527413902035 | | ||
+ | | 4.25 | 9.986332770533490 | 0.48969676619036700 | | ||
+ | | 4.5 | 9.694674681091840 | 0.5443240285483060 | | ||
+ | | 4.75 | 10.519384785632700 | 0.47616567472190800 | | ||
+ | |||
+ | ===== Python ===== | ||
+ | 먼저 Python 코드는 아래와 같다. | ||
+ | |||
+ | < | ||
+ | import numpy as np | ||
+ | from scipy.optimize import curve_fit | ||
+ | |||
+ | func = lambda x, a, b: a*x + b #f(x) = ax + b | ||
+ | |||
+ | x = np.linspace(0, | ||
+ | |||
+ | y = np.array([1.5891700001638700, | ||
+ | |||
+ | sig = np.array([0.5320185951347170, | ||
+ | |||
+ | #if saved file is existed | ||
+ | """ | ||
+ | x, y, err = np.loadtxt(' | ||
+ | """ | ||
+ | |||
+ | NDF = x.size - 2 # # of Degree of Freedom | ||
+ | popt, pcov = curve_fit(func, | ||
+ | perr = np.sqrt(np.diag(pcov))# | ||
+ | chi2 = np.sum((y - func(x, | ||
+ | |||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | ===== C++ ===== | ||
+ | 다음은 C++에서 gsl을 이용한 코드이다. | ||
+ | < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | using std::cout; | ||
+ | using std::pow; | ||
+ | using std::sqrt; | ||
+ | |||
+ | // #include < | ||
+ | // #include < | ||
+ | // #include < | ||
+ | // #include < | ||
+ | |||
+ | //using std:: | ||
+ | //using std:: | ||
+ | //using std:: | ||
+ | //using std:: | ||
+ | //using std::stod; | ||
+ | //using std::copy; | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | double x[] = {0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75}; | ||
+ | double y[] = {1.5891700001638700, | ||
+ | double sig[] = {0.5320185951347170, | ||
+ | | ||
+ | //if saved file is existed | ||
+ | /* | ||
+ | string tmp; | ||
+ | std:: | ||
+ | fin.open(" | ||
+ | | ||
+ | vector< | ||
+ | vector< | ||
+ | vector< | ||
+ | vector< | ||
+ | string sbf; | ||
+ | | ||
+ | while(!fin.eof()) | ||
+ | { | ||
+ | getline(fin, | ||
+ | if(tmp == "" | ||
+ | istringstream ss(tmp); | ||
+ | while(getline(ss, | ||
+ | { | ||
+ | sv.emplace_bacK(); | ||
+ | } | ||
+ | sv.shrink_to_fit(); | ||
+ | | ||
+ | xv.emplace_back(stod(sv[0])); | ||
+ | yv.emplace_back(stod(sv[1])); | ||
+ | sigv.emplace_back(stod(sv[2])); | ||
+ | | ||
+ | sv.clear(); | ||
+ | sv.shrink_to_fit(); | ||
+ | } | ||
+ | xv.shrink_to_fit(); | ||
+ | yv.shrink_to_fit(); | ||
+ | sigv.shrink_to_fit(); | ||
+ | | ||
+ | double x[xv.capacity()]; | ||
+ | double y[yv.capacity()]; | ||
+ | double sig[sig.capacity()]; | ||
+ | | ||
+ | copy(xv.begin(), | ||
+ | copy(yv.begin(), | ||
+ | copy(sigv.begin(), | ||
+ | */ | ||
+ | |||
+ | for(int i = 0; i < sizeof(sig)/ | ||
+ | { | ||
+ | sig[i] = 1/sig[i]; | ||
+ | } | ||
+ | |||
+ | double a, b, cov00, cov01, cov11, chisq; | ||
+ | gsl_fit_wlinear(x, | ||
+ | cout << "y = " << a << "x + "<< | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== 결과 ===== | ||
+ | 각각의 결과는 다음과 같다 | ||
+ | $$\text{Python: | ||
+ | $$\text{C++: | ||
+ | 유효숫자는 c++ cout의 기본 자릿수인 6자리에 맞췄다. |