5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

単回帰分析(最小二乗法) in C++

Last updated at Posted at 2018-09-23

概要

自作したデータで最小二乗法(単回帰分析)により近似直線を計算する。
x(横軸) : 身長 [cm]、y(縦軸) : 年収[万円] とする。

  • データ (左列x : 身長 [cm], 右列y : 年収 [万円])
height-income.csv
162,420
165,470
168,540
170,550
171,565
172,570
175,580
178,590
181,600
183,625
  • 身長と年収には正の相関があると聞いたことがある。確かに、特に男性だと体格の良い方が強くて頼もしく見えるから、結果的に仕事も上手くいきやすいのかもしれない...逆に小さいと舐められるケースもあるから、それで少し不利になるのかもしれない...
    とはいえ、上記のデータほどの差はないだろうけど。
  • 今回は可変長のデータを扱えるvectorを用いた。push_back()関数で要素を付け足すことができる

計算過程

  • フローチャート
  • ソースコード(main関数)
int main(void){

    int i;
    // x(身長), y(年収)
    // y_predictive(近似直線から予想される値), error(実際の値と予測値の誤差)
    vector<float> x, y, y_predictive, error;
    char inputFilename[30]  = "height-income.csv";
    char outputFilename[50] = "height-income-approximation.csv";

    // Load a file
    // ファイル読み込み
    readFile(inputFilename, x, y);

    // Calculate the approximate line
    // 近似直線を求める
    float a = calcSlope(x, y);
    float b = calcIntercept(x, y);

    // xとyの相関係数を求める
    float corre = calcCorrelationCoefficient(x, y);

    // 近似直線の傾き, 切片を表示する 
    printf("slope     : a = %f\n", a);
    printf("intercept : b = %f\n", b);
    printf("correlation coefficience : %5.4f\n", corre);
    printf("\n");

    // 近似直線による予測値を配列に格納する
    // 実際の値と予測値の誤差も配列の格納する
    for(i = 0; i < x.size(); i++){
        y_predictive.push_back(a*x[i]+b);
        error.push_back(y[i] - (a*x[i]+b));
    }

    // x, y, y(予測値), 誤差 すべてを表示
    for(i = 0; i < x.size(); i++){
        printf("No%3d : x = %6.2f, y = %6.2f, y(predictive) = %6.2f, error = %6.2f\n", i+1, x[i], y[i], y_predictive[i], error[i]);
    }

    // ファイル書き出し
    writeFile(outputFilename, x, y, y_predictive);

    return(0);

}

  • 近似直線の傾きの計算
float calcSlope(vector<float> &x, vector<float> &y){

    float Xdecentration = calcDecentration(x);
    float covariance    = calcCovariance(x, y);
    float slope         = covariance/Xdecentration;

    return slope;

}
  • 近似直線の切片の計算
float calcIntercept(vector<float> &x, vector<float> &y){

    float Xdecentration = calcDecentration(x);
    float covariance    = calcCovariance(x, y);
    float Xaverage      = calcAverage(x);
    float Yaverage      = calcAverage(y);
    float intercept     = Yaverage - (covariance/Xdecentration)*Xaverage;

    return intercept;

}
  • 傾きや切片を求めるために必要な関数一覧

    平均値
float calcAverage(vector<float> &f){

    float average = 0.0;
    for(int i = 0; i < f.size(); i++){
        average += f[i]/(float)(f.size());
    }

    return average;

}

2乗平均

float calcMeanSquare(vector<float> &f){

    float meanSquare = 0.0;
    for(int i = 0; i < f.size(); i++){
        meanSquare += f[i]*f[i]/(float)(f.size());
    }

    return meanSquare;

}

分散 (varianceのほうが正しいと思うが..)

float calcDecentration(vector<float> &f){

    float average      = calcAverage(f);
    float meanSquare   = calcMeanSquare(f);
    float decentration = meanSquare - average*average;

    return decentration;

}

共分散

float calcCovariance(vector<float> &f, vector<float> &g){

    float covariance = 0.0;
    for(int i = 0; i < f.size(); i++){
        covariance += f[i]*g[i]/(float)(f.size());
    }
    covariance -= calcAverage(f) * calcAverage(g);

    return covariance;

}

計算結果

  • 近似直線の式
y = 8.41x - 899
slope     : a = 8.408483
intercept : b = -899.463379
correlation coefficience : 0.9197
  • 元の2次元データ(青点)と近似直線(緑線)のグラフ
    height-income-slr.png
    近似直線と実際の値の誤差が大きく見えるが相関係数はとても高い
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?