/// <summary> /// 線形判別分析 /// </summary> /// <param name="Xs"> /// <para>各郡の Matrix オブジェクト (行がデータ,列が変数に対応する) の配列</para> /// <para> /// 1 つの群データは 1 つの Matrix で表される. /// 本処理により書き換えられることはない (read-only). /// </para> /// </param> public static Lda Lda(Matrix[] Xs) { int C = Xs.Length; // 群数 int[] ns = new int[C]; // 各群のデータ数 int p = Xs[0].ColumnSize; // 次元数 // 各郡のデータ数を取得 for (int k = 0; k < C; ++k) { ns[k] = Xs[k].RowSize; } Vector tAvg = new Vector(new Size(p)); // 全データにおける各次元の平均値 tAvg.Zero(); int tN = 0; // 全データ数 Vector[] avgs = new Vector[C]; // 各群における各次元の平均値 for (int k = 0; k < C; ++k) { tN += Xs[k].RowSize; avgs[k] = Xs[k].ColumnAverages; tAvg.Apply((int i, double val) => val + Xs[k].Columns[i].Sum); } tAvg /= tN; Matrix B = new Matrix(p, p); for (int k = 0; k < C; ++k) { IVector dv = avgs[k] - tAvg; B += (ns[k] * new ColumnVector(dv) * new RowVector(dv)); } B /= (C - 1); Matrix W = new Matrix(p, p); for (int k = 0; k < C; ++k) { for (int i = 0; i < ns[k]; ++i) { IVector dv = Xs[k].Rows[i] - avgs[k]; W += (new ColumnVector(dv) * new RowVector(dv)); } } W /= (tN - C); Eigen evd = Eigen(Matrix.Inverse(W) * B); evd.Sort(KrdLab.Lisys.Eigen.SortOrder.Descending); return(new Lda(evd.RealEigenvalues, evd.RealEigenvectors, avgs.ToList())); }
/// <summary> /// 主成分分析 /// </summary> /// <param name="data"> /// [n, d] の行列(データ数:n,次元数:d,書き換えられることはない) /// </param> /// <param name="cor"> /// 相関行列で分析するかどうか (デフォルトは <c>false</c> = 分散・共分散行列) /// </param> public static Pca Pca(Matrix data, bool cor = false) { Matrix x = new Matrix(data); Matrix s; if (cor) { s = Correlate(x, Target.EachColumn); } else { // 各変数の平均値を 0 にする Vector colAvgs = x.ColumnAverages; x.Columns.ForEach((c, vec) => vec.Apply((i, val) => val - colAvgs[c])); // 分散・共分散行列 s = Matrix.Transpose(x) * x / (x.RowSize - 1); } // 固有値分解 Eigen evd = Eigen(s); evd.Sort(KrdLab.Lisys.Eigen.SortOrder.Descending); // 対称行列の固有値は全て実数 return(new Pca(evd.RealEigenvalues, evd.RealEigenvectors)); }