単回帰分析(最小二乗法, C++, 動的配列クラス)

C++による単回帰分析
x(横軸):身長、y(縦軸):体重で示された身2次元データの近似直線を最小二乗法を計算してみた。

```c++:clr.cpp
#include <iostream>
#include <vector>

#include <stdio.h>

using namespace std;

/* 平均・標準偏差を計算するStatisticsクラス */
class Statistics{

public:
	/* 平均を計算 */
	float average(vector<float> &f, int N){

		float ave = 0.0;

		for(int i = 0; i < N; i++) ave += f[i]/(float)N;

		return ave;
	
	}

	/* 2乗の平均を計算 */
	float average2(vector<float> &f, int N){

		float ave2 = 0.0;

		for(int i = 0; i < N; i++) ave2 += f[i]*f[i]/(float)N;

		return ave2;

	}

	/* 標準偏差を計算 */
	float variance(vector<float> &f, int N){

		float ave  = average(f, N);
		float ave2 = average2(f, N);

		float var = ave2 - ave*ave;

		return var;

	}

	/* 共分散を計算 */
	float covariance(vector<float> &f, vector<float> &g, int N){

		float cov = 0.0;

		for(int i = 0; i < N; i++) cov += f[i]*g[i]/(float)N;

		cov -= average(f, N) * average(g, N);

		return cov;

	}

};
```

クラスStatistics
平均(average関数)、2乗平均(average2関数)、分散(variance関数)、共分散(covariance関数)を計算

```c++:slr.cpp
/* Statisticsクラスを継承したクラス */
/* Least_squares_method (最小二乗法) クラスで
 * 近似直線を計算 */

class Least_squares_method : public Statistics{

public:
	/* 傾きを計算 */
	float slope(vector<float> &x, vector<float> &y, int N){

		float a = 0.0;
		float x_var = variance(x, N);
		float cov   = covariance(x, y, N);

		a = cov / x_var;

		return a;

	}

	/* 切片を計算 */
	float intercept(vector<float> &x, vector<float> &y, int N){

		float b = 0.0;
		float x_var = variance(x, N);
		float cov   = covariance(x, y, N);
		float x_ave = average(x, N);
		float y_ave = average(y, N);

		b = y_ave - (cov / x_var) * x_ave;

		return b;

	}

};
```
クラスStatisticsを継承したLeast_squares_methodクラスにより近似直線を計算

以下はファイル読み込み&書き込み

```c++:slr.cpp
/* ファイル読み込み */
int read_file(char *filename, vector<float> &x, vector<float> &y){

	int N = 0;
	float x_tmp = 0.0, y_tmp = 0.0;

	FILE *fp;

	fp = fopen(filename, "r");

	if(fp == NULL){
		cout << "can't open file ." << endl;
		exit(1);
	}

	while(true){

		if(fscanf(fp, "%f, %f\n", &x_tmp, &y_tmp) == EOF) break;
		x.push_back(x_tmp);
		y.push_back(y_tmp);
		N++;

	}

	fclose(fp);

	/* 要素数を返す */
	return(N);

}

/* ファイル書き出し */
int write_file(char *filename, vector<float> &x, vector<float> &y, vector<float> &y2, int N){

	FILE *fp;

	fp = fopen(filename, "w");

	if(fp == NULL){
		cout << "can't open file ." << endl;
		exit(1);
	}

	for(int i = 0; i < N; i++){
	       	fprintf(fp, "%f, %f, %f\n", x[i], y[i], y2[i]);

	fclose(fp);

	return(0);

}
```
main関数内で近似直線の傾きと切片を表示
ベクトルy2には近似直線を格納、write_file関数にてファイルに書き出される

```c++:slr.cpp
int main(void){

	vector<float> x, y, y2;
	char filename[30] = "height_weight.csv";

	/* ファイル読み込み */
	int N = read_file(filename, x, y);

	/* オブジェクトdata1を生成
	 * data1オブジェクトにより2次元データの近似直線を計算 */
	Least_squares_method data1;

	/* 近似直線を計算 */
	float a = data1.slope(x, y, N);
	float b = data1.intercept(x, y, N);

	cout << "slope : " << a << endl;
	cout << "intercept : " << b << endl;

	/* 近似直線の配列に格納 */
	for(int i = 0; i < N; i++)
		y2.push_back(a * x[i] + b);

	char filename2[30] = "height_weight_slr.csv";

	/* 近似直線のデータを出力 */
	write_file(filename2, x, y, y2, N);

	return(0);

}
```

![slr.png](https://qiita-image-store.s3.amazonaws.com/0/294396/d37b69dc-e602-7067-0c2f-b0debca8632b.png)
元の2次元データ(青点)と近似直線(赤線)