最適化最適化
重み付き直線フィッティング; 重み付き線形回帰; Weighted Linear Regression

概要
直線フィッティングとは独立変数\(x_i\)と従属変数\(y_i\)とフィッティングに対する重み\(w_i\)の組で表される\(N\)個のデータ\(i = 1 \cdots N \)があるとき、
直線\(\tilde{y_i} = a + b x_i\)または原点を通る直線\(\tilde{y_i} = a x_i\)と、\(y_i\)との誤差と重み\(w_i\)の積和を最小化する、\(a, b\)の組または\(a\)を求めることである。
誤差には2乗和が用いられる。
\(\quad \displaystyle E = \sum_{i=1}^{N} w_i (y_i - \tilde{y_i})^2 \)

なお、データの誤差の分散\(\sigma^2 \)が既知の場合、重み\(w\)は以下で与えられる。
\(\quad \displaystyle w = \frac{1}{{\sigma}^2} \)

重み付き直線フィッティング

誤差最小値における\(a, b\)の導出
最小化する対象である誤差の2乗和は以下である。
\(\begin{eqnarray} \quad \displaystyle E &=& \sum_{i=1}^{N} w_i (y_i - a - b x_i)^2 \\ \quad &=& \sum_{i=1}^{N} w_i y_i^2-2 b w_i x_i y_i-2 a w_i y_i+b^2 w_i x_i^2+2 a b w_i x_i+a^2 w_i \\ \quad &=& \sum_{i=1}^{N} w_i y_i^2-2 b \sum_{i=1}^{N} w_i x_i y_i-2 a \sum_{i=1}^{N} w_i y_i+b^2 \sum_{i=1}^{N} w_i x_i^2+2 a b \sum_{i=1}^{N} w_i x_i+ a^2 \sum_{i=1}^{N} w_i \\ \end{eqnarray} \)
\(E\)が最小化であるとき、\(a, b\)について偏微分はともに0になる。
\(\begin{eqnarray} \quad \displaystyle \frac{\partial E}{\partial a} &=& -2 \sum_{i=1}^{N} w_i y_i+2 b \sum_{i=1}^{N} w_i x_i+2 a \sum_{i=1}^{N} w_i = 0 \quad &\rightarrow& a \sum_{i=1}^{N} w_i + b \sum_{i=1}^{N} w_i x_i = \sum_{i=1}^{N} w_i y_i \\ \quad \displaystyle \frac{\partial E}{\partial b} &=& -2 \sum_{i=1}^{N} w_i x_i y_i + 2 b \sum_{i=1}^{N} w_i x_i^2 + 2 a \sum_{i=1}^{N} w_i x_i = 0 \quad &\rightarrow& a \sum_{i=1}^{N} w_i x_i + b \sum_{i=1}^{N} w_i x_i^2 = \sum_{i=1}^{N} w_i x_i y_i \\ \end{eqnarray}\)
2式を連立させて\(a, b\)について解く。
\(\quad \begin{pmatrix} \sum_{i=1}^{N} w_i & \sum_{i=1}^{N} w_i x_i \\ \sum_{i=1}^{N} w_i x_i & \sum_{i=1}^{N} w_i x_i^2 \end{pmatrix} \begin{pmatrix} a \\ b \end{pmatrix} = \begin{pmatrix} \sum_{i=1}^{N} w_i y_i \\ \sum_{i=1}^{N} w_i x_i y_i \end{pmatrix} \)
であるから
\( \begin{eqnarray} \quad a &=& \frac{ \displaystyle \sum_{i=1}^{N} w_i x_i \sum_{i=1}^{N} w_i x_i y_i - \sum_{i=1}^{N} w_i x_i^2 \sum_{i=1}^{N} w_i y_i }{ \left( \displaystyle \sum_{i=1}^{N} w_i x_i \right)^2 - \displaystyle \sum_{i=1}^{N} w_i \displaystyle \sum_{i=1}^{N} w_i x_i^2 } \\ \quad b &=& \frac{ \displaystyle \sum_{i=1}^{N} w_i x_i \sum_{i=1}^{N} w_i y_i - \sum_{i=1}^{N} w_i \sum_{i=1}^{N} w_i x_i y_i }{ \left( \displaystyle \sum_{i=1}^{N} w_i x_i \right)^2 - \displaystyle \sum_{i=1}^{N} w_i \displaystyle \sum_{i=1}^{N} w_i x_i^2 } \end{eqnarray}\)

誤差最小値における\(a\)の導出(原点を通る制約のもと)
最小化する対象である誤差の2乗和は以下である。
\(\begin{eqnarray} \quad \displaystyle E &=& \sum_{i=1}^{N} w_i (y_i - a x_i)^2 \\ \quad &=& \sum_{i=1}^{N} w_i y_i^2-2 a w_i x_i y_i+a^2 w_i x_i^2 \\ \quad &=& \sum_{i=1}^{N} w_i y_i^2-2 a \sum_{i=1}^{N} w_i x_i y_i+a^2 \sum_{i=1}^{N} w_i x_i^2 \end{eqnarray} \)
\(E\)が最小化であるとき、\(a\)について偏微分は0になる。
\( \quad \displaystyle \frac{\partial E}{\partial a} = -2 \sum_{i=1}^{N} w_i x_i y_i + 2 a \sum_{i=1}^{N} w_i x_i^2 = 0 \quad \rightarrow a = \displaystyle \sum_{i=1}^{N} w_i x_i y_i / \displaystyle \sum_{i=1}^{N} w_i x_i^2 \)

ソースコード

namespace DataFitting {

    /// <summary>重み付き線形フィッティング</summary>
    public class WeightedLinearFittingMethod : FittingMethod {

        readonly double[] weight_list;

        /// <summary>コンストラクタ</summary>
        public WeightedLinearFittingMethod(FittingData[] data_list, double[] weight_list, bool is_enable_section) : base(data_list, is_enable_section ? 2 : 1) {
            IsEnableSection = is_enable_section;

            if(weight_list == null) {
                throw new ArgumentNullException(nameof(weight_list));
            }

            if(data_list.Length != weight_list.Length) {
                throw new ArgumentException($"{nameof(data_list)},{nameof(weight_list)}");
            }

            foreach(var weight in weight_list) {
                if(!(weight >= 0)) {
                    throw new ArgumentException(nameof(weight_list));
                }
            }

            this.weight_list = weight_list;
        }

        /// <summary>y切片を有効にするか</summary>
        public bool IsEnableSection { get; private set; }

        /// <summary>重み付き誤差二乗和</summary>
        public double WeightedCost(Vector parameters) {
            if(parameters == null) {
                throw new ArgumentNullException(nameof(parameters));
            }
            if(parameters.Dim != ParametersCount) {
                throw new ArgumentException(nameof(parameters));
            }

            Vector errors = Error(parameters);
            double cost = 0;
            for(int i = 0; i < errors.Dim; i++) {
                cost += weight_list[i] * errors[i] * errors[i];
            }

            return cost;
        }

        /// <summary>フィッティング値</summary>
        public override double FittingValue(double x, Vector parameters) {
            if(parameters == null) {
                throw new ArgumentNullException(nameof(parameters));
            }
            if(parameters.Dim != ParametersCount) {
                throw new ArgumentException(nameof(parameters));
            }

            if(IsEnableSection) {
                return parameters[0] + parameters[1] * x;
            }
            else {
                return parameters[0] * x;
            }
        }

        /// <summary>フィッティング</summary>
        public Vector ExecureFitting() {
            if(weight_list == null) {
                throw new InvalidOperationException();
            }

            if(IsEnableSection) {
                FittingData data;
                double w, sum_w = 0, sum_wx = 0, sum_wy = 0, sum_wxx = 0, sum_wxy = 0;

                for(int i = 0; i < data_list.Length; i++) {
                    data = data_list[i];
                    w = weight_list[i];
                    sum_w += w;
                    sum_wx += w * data.X;
                    sum_wy += w * data.Y;
                    sum_wxx += w * data.X * data.X;
                    sum_wxy += w * data.X * data.Y;
                }

                double r = 1 / (sum_wx * sum_wx - sum_w * sum_wxx);
                double a = (sum_wx * sum_wxy - sum_wxx * sum_wy) * r;
                double b = (sum_wx * sum_wy - sum_w * sum_wxy) * r;

                return new Vector(a, b);
            }
            else {
                FittingData data;
                double w, sum_wxx = 0, sum_wxy = 0;

                for(int i = 0; i < data_list.Length; i++) {
                    data = data_list[i];
                    w = weight_list[i];
                    sum_wxx += w * data.X * data.X;
                    sum_wxy += w * data.X * data.Y;
                }

                return new Vector(sum_wxy / sum_wxx);
            }
        }
    }
}

関連項目
関数フィッティング手法基本クラス
ベクトルクラス
行列クラス
直線フィッティング
多項式フィッティング
非線形フィッティング Gauss-Newton法
非線形フィッティング Levenberg-Marquardt法
重み付き多項式フィッティング
最小二乗法におけるロバスト推定

ライブラリライブラリ
確率統計確率統計
線形代数線形代数
幾何学幾何学
最適化最適化
微分方程式微分方程式
画像処理画像処理
補間補間
機械学習機械学習
クラスタリングクラスタリング
パズルゲーム・パズル
未分類未分類