Example #1
0
autoClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable_dw (Discriminant me, TableOfReal thee, int poolCovarianceMatrices, int useAprioriProbabilities, double alpha, double minProb, autoTableOfReal *displacements) {
    try {
        long g = Discriminant_getNumberOfGroups (me);
        long p = Eigen_getDimensionOfComponents (my eigen.get());
        long m = thy numberOfRows;

        if (p != thy numberOfColumns) Melder_throw
            (U"The number of columns does not agree with the dimension of the discriminant.");

        autoNUMvector<double> log_p (1, g);
        autoNUMvector<double> log_apriori (1, g);
        autoNUMvector<double> ln_determinant (1, g);
        autoNUMvector<double> buf (1, p);
        autoNUMvector<double> displacement (1, p);
        autoNUMvector<double> x (1, p);
        autoNUMvector<SSCP> sscpvec (1, g);
        autoSSCP pool = SSCPList_to_SSCP_pool (my groups.get());
        autoClassificationTable him = ClassificationTable_create (m, g);
        NUMstrings_copyElements (thy rowLabels, his rowLabels, 1, m);
        autoTableOfReal adisplacements = Data_copy (thee);

        // Scale the sscp to become a covariance matrix.

        for (long i = 1; i <= p; i ++) {
            for (long k = i; k <= p; k ++) {
                pool -> data [k] [i] = pool -> data [i] [k] /= pool -> numberOfObservations - g;
            }
        }

        double lnd;
        autoSSCPList agroups;
        SSCPList groups;
        if (poolCovarianceMatrices) {
            // Covariance matrix S can be decomposed as S = L.L'. Calculate L^-1.
            // L^-1 will be used later in the Mahalanobis distance calculation:
            // v'.S^-1.v == v'.L^-1'.L^-1.v == (L^-1.v)'.(L^-1.v).

            NUMlowerCholeskyInverse (pool -> data, p, & lnd);
            for (long j = 1; j <= g; j ++) {
                ln_determinant [j] = lnd;
                sscpvec [j] = pool.get();
            }
            groups = my groups.get();
        } else {
            //Calculate the inverses of all group covariance matrices.
            // In case of a singular matrix, substitute inverse of pooled.

            agroups = Data_copy (my groups.get());
            groups = agroups.get();
            long npool = 0;
            for (long j = 1; j <= g; j ++) {
                SSCP t = groups->at [j];
                long no = (long) floor (SSCP_getNumberOfObservations (t));
                for (long i = 1; i <= p; i ++) {
                    for (long k = i; k <= p; k ++) {
                        t -> data [k] [i] = t -> data [i] [k] /= no - 1;
                    }
                }
                sscpvec [j] = groups->at [j];
                try {
                    NUMlowerCholeskyInverse (t -> data, p, & ln_determinant [j]);
                } catch (MelderError) {
                    // Try the alternative: the pooled covariance matrix.
                    // Clear the error.

                    Melder_clearError ();
                    if (npool == 0) {
                        NUMlowerCholeskyInverse (pool -> data, p, & lnd);
                    }
                    npool ++;
                    sscpvec [j] = pool.get();
                    ln_determinant [j] = lnd;
                }
            }
            if (npool > 0) {
                Melder_warning (npool, U" groups use pooled covariance matrix.");
            }
        }

        // Labels for columns in ClassificationTable

        for (long j = 1; j <= g; j ++) {
            const char32 *name = Thing_getName (my groups->at [j]);
            if (! name) {
                name = U"?";
            }
            TableOfReal_setColumnLabel (him.get(), j, name);
        }

        // Normalize the sum of the apriori probabilities to 1.
        // Next take ln (p) because otherwise probabilities might be too small to represent.

        double logg = log (g);
        NUMvector_normalize1 (my aprioriProbabilities, g);
        for (long j = 1; j <= g; j ++) {
            log_apriori[j] = ( useAprioriProbabilities ? log (my aprioriProbabilities[j]) : - logg );
        }

        // Generalized squared distance function:
        // D^2(x) = (x - mu)' S^-1 (x - mu) + ln (determinant(S)) - 2 ln (apriori)

        for (long i = 1; i <= m; i ++) {
            SSCP winner;
            double norm = 0, pt_max = -1e308;
            long iwinner = 1;
            for (long k = 1; k <= p; k ++) {
                x [k] = thy data [i] [k] + displacement [k];
            }
            for (long j = 1; j <= g; j ++) {
                SSCP t = groups->at [j];
                double md = mahalanobisDistanceSq (sscpvec [j] -> data, p, x.peek(), t -> centroid, buf.peek());
                double pt = log_apriori [j] - 0.5 * (ln_determinant [j] + md);
                if (pt > pt_max) {
                    pt_max = pt;
                    iwinner = j;
                }
                log_p [j] = pt;
            }
            for (long j = 1; j <= g; j ++) {
                norm += log_p [j] = exp (log_p [j] - pt_max);
            }

            for (long j = 1; j <= g; j ++) {
                his data [i] [j] = log_p [j] / norm;
            }

            // Save old displacement, calculate new displacement

            winner = groups->at [iwinner];
            for (long k = 1; k <= p; k ++) {
                adisplacements -> data [i] [k] = displacement [k];
                if (his data [i] [iwinner] > minProb) {
                    double delta_k = winner -> centroid [k] - x [k];
                    displacement [k] += alpha * delta_k;
                }
            }
        }
        *displacements = adisplacements.move();
        return him;
    } catch (MelderError) {
        Melder_throw (U"ClassificationTable for Weenink procedure not created.");
    }
}
Example #2
0
ClassificationTable Discriminant_and_TableOfReal_to_ClassificationTable (Discriminant me, TableOfReal thee,
        int poolCovarianceMatrices, int useAprioriProbabilities) {
	try {
		long g = Discriminant_getNumberOfGroups (me);
		long p = Eigen_getDimensionOfComponents (me);
		long m = thy numberOfRows;

		if (p != thy numberOfColumns) Melder_throw
			(U"The number of columns does not agree with the dimension of the discriminant.");

		autoNUMvector<double> log_p (1, g);
		autoNUMvector<double> log_apriori (1, g);
		autoNUMvector<double> ln_determinant (1, g);
		autoNUMvector<double> buf (1, p);
		autoNUMvector<SSCP> sscpvec (1, g);
		autoSSCP pool = SSCPs_to_SSCP_pool (my groups);
		autoClassificationTable him = ClassificationTable_create (m, g);
		NUMstrings_copyElements (thy rowLabels, his rowLabels, 1, m);

		// Scale the sscp to become a covariance matrix.

		for (long i = 1; i <= p; i++) {
			for (long k = i; k <= p; k++) {
				pool -> data[k][i] = (pool -> data[i][k] /= (pool -> numberOfObservations - g));
			}
		}

		double lnd;
		autoSSCPs agroups = 0; SSCPs groups;
		if (poolCovarianceMatrices) {
			/*
				Covariance matrix S can be decomposed as S = L.L'. Calculate L^-1.
				L^-1 will be used later in the Mahalanobis distance calculation:
				v'.S^-1.v == v'.L^-1'.L^-1.v == (L^-1.v)'.(L^-1.v).
			*/

			NUMlowerCholeskyInverse (pool -> data, p, &lnd);
			for (long j = 1; j <= g; j++) {
				ln_determinant[j] = lnd;
				sscpvec[j] = pool.peek();
			}
			groups = (SSCPs) my groups;
		} else {
			// Calculate the inverses of all group covariance matrices.
			// In case of a singular matrix, substitute inverse of pooled.

			agroups.reset (Data_copy ( (SSCPs) my groups)); groups = agroups.peek();
			long npool = 0;
			for (long j = 1; j <= g; j++) {
				SSCP t = (SSCP) groups -> item[j];
				long no = (long) floor (SSCP_getNumberOfObservations (t));
				for (long i = 1; i <= p; i++) {
					for (long k = i; k <= p; k++) {
						t -> data[k][i] = (t -> data[i][k] /= (no - 1));
					}
				}
				sscpvec[j] = (SSCP) groups -> item[j];
				try {
					NUMlowerCholeskyInverse (t -> data, p, &ln_determinant[j]);
				} catch (MelderError) {
					// Try the alternative: the pooled covariance matrix.
					// Clear the error.

					Melder_clearError ();
					if (npool == 0) {
						NUMlowerCholeskyInverse (pool -> data, p, &lnd);
					}
					npool++;
					sscpvec[j] = pool.peek();
					ln_determinant[j] = lnd;
				}
			}
			if (npool > 0) {
				Melder_warning (npool, U" groups use pooled covariance matrix.");
			}
		}

		// Labels for columns in ClassificationTable

		for (long j = 1; j <= g; j++) {
			const char32 *name = Thing_getName ( (Thing) my groups -> item[j]);
			if (! name) {
				name = U"?";
			}
			TableOfReal_setColumnLabel (him.peek(), j, name);
		}

		// Normalize the sum of the apriori probabilities to 1.
		// Next take ln (p) because otherwise probabilities might be too small to represent.

		NUMvector_normalize1 (my aprioriProbabilities, g);
		double logg = log (g);
		for (long j = 1; j <= g; j++) {
			log_apriori[j] = useAprioriProbabilities ? log (my aprioriProbabilities[j]) : - logg;
		}

		// Generalized squared distance function:
		// D^2(x) = (x - mu)' S^-1 (x - mu) + ln (determinant(S)) - 2 ln (apriori)

		for (long i = 1; i <= m; i++) {
			double norm = 0, pt_max = -1e38;
			for (long j = 1; j <= g; j++) {
				SSCP t = (SSCP) groups -> item[j];
				double md = mahalanobisDistanceSq (sscpvec[j] -> data, p, thy data[i], t -> centroid, buf.peek());
				double pt = log_apriori[j] - 0.5 * (ln_determinant[j] + md);
				if (pt > pt_max) {
					pt_max = pt;
				}
				log_p[j] = pt;
			}
			for (long j = 1; j <= g; j++) {
				norm += (log_p[j] = exp (log_p[j] - pt_max));
			}
			for (long j = 1; j <= g; j++) {
				his data[i][j] = log_p[j] / norm;
			}
		}
		return him.transfer();
	} catch (MelderError) {
		Melder_throw (U"ClassificationTable from Discriminant & TableOfReal not created.");
	}
}