/// <summary> /// Learns a model that can map the given inputs to the given outputs. /// </summary> /// <param name="x">The model inputs.</param> /// <param name="y">The desired outputs associated with each <paramref name="x">inputs</paramref>.</param> /// <param name="weights">The weight of importance for each input-output pair (if supported by the learning algorithm).</param> /// <returns> /// A model that has learned how to produce <paramref name="y" /> given <paramref name="x" />. /// </returns> /// public Pipeline Learn(double[][] x, int[] y, double[] weights = null) { if (weights != null) { throw new ArgumentException(Accord.Properties.Resources.NotSupportedWeights, "weights"); } Init(x, y); // Create the Gram (Kernel) Matrix var K = kernel.ToJagged(x); // Compute entire data set measures base.Means = Measures.Mean(K, dimension: 0); base.StandardDeviations = Measures.StandardDeviation(K, Means); // Initialize the kernel analogous scatter matrices //int dimension = x.Columns(); double[][] Sb = Jagged.Zeros(NumberOfSamples, NumberOfSamples); double[][] Sw = Jagged.Zeros(NumberOfSamples, NumberOfSamples); // For each class for (int c = 0; c < Classes.Count; c++) { var idx = Matrix.Find(y, y_i => y_i == c); // Get the Kernel matrix class subset double[][] Kc = K.Get(idx); int count = Kc.Rows(); // Get the Kernel matrix class mean double[] mean = Measures.Mean(Kc, dimension: 0); // Construct the Kernel equivalent of the Within-Class Scatter matrix double[][] Swi = Measures.Scatter(Kc, dimension: 0, means: mean); Swi.Divide((double)count, result: Swi); Sw.Add(Swi, result: Sw); // Sw = Sw + Swi // Construct the Kernel equivalent of the Between-Class Scatter matrix double[] d = mean.Subtract(base.Means); double[][] Sbi = Jagged.Outer(d, d); Sbi.Multiply((double)NumberOfSamples, result: Sbi); Sb.Add(Sbi, result: Sb); // Sb = Sb + Sbi // Store additional information base.ClassScatter[c] = Swi; base.ClassCount[c] = count; base.ClassMeans[c] = mean; base.ClassStandardDeviations[c] = Measures.StandardDeviation(Kc, mean); } // Add regularization to avoid singularity Sw.AddToDiagonal(regularization, result: Sw); // Compute the generalized eigenvalue decomposition var gevd = new JaggedGeneralizedEigenvalueDecomposition(Sb, Sw, sort: true); if (gevd.IsSingular) // check validity of the results { throw new SingularMatrixException("One of the matrices is singular. Please retry " + "the method with a higher regularization constant."); } // Get the eigenvalues and corresponding eigenvectors double[] evals = gevd.RealEigenvalues; double[][] eigs = gevd.Eigenvectors; // Eliminate unwanted components int nonzero = x.Columns(); if (Threshold > 0) { nonzero = Math.Min(gevd.Rank, GetNonzeroEigenvalues(evals, Threshold)); } if (NumberOfInputs != 0) { nonzero = Math.Min(nonzero, NumberOfInputs); } if (NumberOfOutputs != 0) { nonzero = Math.Min(nonzero, NumberOfOutputs); } eigs = eigs.Get(null, 0, nonzero); evals = evals.Get(0, nonzero); // Store information this.input = x; base.Eigenvalues = evals; base.DiscriminantVectors = eigs.Transpose(); base.ScatterBetweenClass = Sb; base.ScatterWithinClass = Sw; base.NumberOfOutputs = evals.Length; // Compute feature space means for later classification for (int c = 0; c < Classes.Count; c++) { ProjectionMeans[c] = ClassMeans[c].Dot(eigs); } // Computes additional information about the analysis and creates the // object-oriented structure to hold the discriminants found. CreateDiscriminants(); this.Classifier = CreateClassifier(); return(Classifier); }
/// <summary> /// Learns a model that can map the given inputs to the given outputs. /// </summary> /// <param name="x">The model inputs.</param> /// <param name="y">The desired outputs associated with each <paramref name="x">inputs</paramref>.</param> /// <param name="weights">The weight of importance for each input-output pair.</param> /// <returns> /// A model that has learned how to produce <paramref name="y" /> given <paramref name="x" />. /// </returns> public Pipeline Learn(double[][] x, int[] y, double[] weights = null) { Init(x, y); // Compute entire data set measures Means = Measures.Mean(x, dimension: 0); StandardDeviations = Measures.StandardDeviation(x, Means); // Initialize the scatter matrices var Sw = Jagged.Zeros(NumberOfInputs, NumberOfInputs); var Sb = Jagged.Zeros(NumberOfInputs, NumberOfInputs); // For each class for (int c = 0; c < Classes.Count; c++) { int[] idx = Matrix.Find(y, y_i => y_i == Classes[c].Number); // Get the class subset double[][] subset = x.Get(idx); int count = subset.GetLength(0); // Get the class mean double[] mean = Measures.Mean(subset, dimension: 0); // Continue constructing the Within-Class Scatter Matrix double[][] Swi = Measures.Scatter(subset, mean, (double)count); Sw.Add(Swi, result: Sw); // Sw = Sw + Swi // Continue constructing the Between-Class Scatter Matrix double[] d = mean.Subtract(Means); double[][] Sbi = Jagged.Outer(d, d); Sbi.Multiply((double)NumberOfInputs, result: Sbi); Sb.Add(Sbi, result: Sb); // Sb = Sb + Sbi // Store some additional information this.classScatter[c] = Swi; this.classCount[c] = count; this.classMeans[c] = mean; this.classStdDevs[c] = Measures.StandardDeviation(subset, mean); } // Compute the generalized eigenvalue decomposition var gevd = new JaggedGeneralizedEigenvalueDecomposition(Sb, Sw, sort: true); // Get the eigenvalues and corresponding eigenvectors double[] evals = gevd.RealEigenvalues; double[][] eigs = gevd.Eigenvectors; // Eliminate unwanted components int nonzero = x.Columns(); if (Threshold > 0) { nonzero = Math.Min(gevd.Rank, GetNonzeroEigenvalues(evals, Threshold)); } if (NumberOfInputs != 0) { nonzero = Math.Min(nonzero, NumberOfInputs); } if (NumberOfOutputs != 0) { nonzero = Math.Min(nonzero, NumberOfOutputs); } eigs = eigs.Get(null, 0, nonzero); evals = evals.Get(0, nonzero); // Store information this.Eigenvalues = evals; this.DiscriminantVectors = eigs.Transpose(); base.ScatterBetweenClass = Sb; base.ScatterWithinClass = Sw; base.NumberOfInputs = x.Columns(); base.NumberOfOutputs = evals.Length; // Compute feature space means for later classification for (int c = 0; c < projectedMeans.Length; c++) { projectedMeans[c] = classMeans[c].Dot(eigs); } // Computes additional information about the analysis and creates the // object-oriented structure to hold the discriminants found. CreateDiscriminants(); this.Classifier = CreateClassifier(); return(Classifier); }