Beispiel #1
0
autoPCA TableOfReal_to_PCA (I) {
	iam (TableOfReal);
	try {
		long m = my numberOfRows, n = my numberOfColumns;

		if (! TableOfReal_areAllCellsDefined (me, 0, 0, 0, 0)) {
			Melder_throw (U"Undefined cells.");
		}
		if (m < 2) {
			Melder_throw (U"There is not enough data to perform a PCA.\nYour table has less than 2 rows.");
		}
		if (m < n) {
			Melder_warning (U"The number of rows in your table is less than the \nnumber of columns. ");
		}
		if (NUMfrobeniusnorm (m, n, my data) == 0) {
			Melder_throw (U"All values in your table are zero.");
		}
		autoPCA thee = Thing_new (PCA);
		autoNUMmatrix<double> a (NUMmatrix_copy (my data, 1, m, 1, n), 1, 1);
		thy centroid = NUMvector<double> (1, n);

		for (long j = 1; j <= n; j++) {
			double colmean = a[1][j];
			for (long i = 2; i <= m; i++) {
				colmean += a[i][j];
			}
			colmean /= m;
			for (long i = 1; i <= m; i++) {
				a[i][j] -= colmean;
			}
			thy centroid[j] = colmean;
		}
		Eigen_initFromSquareRoot (thee.peek(), a.peek(), m, n);
		thy labels = NUMvector<char32 *> (1, n);

		NUMstrings_copyElements (my columnLabels, thy labels, 1, n);

		PCA_setNumberOfObservations (thee.peek(), m);

		/*
			The covariance matrix C = A'A / (N-1). However, we have calculated
			the eigenstructure for A'A. This has no consequences for the
			eigenvectors, but the eigenvalues have to be divided by (N-1).
		*/

		for (long i = 1; i <= thy numberOfEigenvalues; i++) {
			thy eigenvalues[i] /= (m - 1);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (me, U": PCA not created.");
	}
}
Beispiel #2
0
static autoPCA NUMdmatrix_to_PCA (double **m, long numberOfRows, long numberOfColumns, bool byColumns) {
	try {
		if (! NUMdmatrix_hasFiniteElements(m, 1, numberOfRows, 1, numberOfColumns)) {
			Melder_throw (U"At least one of the matrix elements is not finite or undefined.");
		}
		if (NUMfrobeniusnorm (numberOfRows, numberOfColumns, m) == 0.0) {
			Melder_throw (U"All values in your table are zero.");
		}
		autoNUMmatrix<double> mcopy;
		long numberOfRows2, numberOfColumns2;
		if (byColumns) {
			if (numberOfColumns < numberOfRows) {
				Melder_warning (U"The number of columns in your table is less than the number of rows. ");
			}
			numberOfRows2 = numberOfColumns, numberOfColumns2 = numberOfRows;
			mcopy.reset (1, numberOfRows2, 1, numberOfColumns2);
			for (long i = 1; i <= numberOfRows2; i ++) { // transpose
				for (long j = 1; j <= numberOfColumns2; j++) {
					mcopy [i] [j] = m [j] [i];
				}
			}
		} else {
			if (numberOfRows < numberOfColumns) {
				Melder_warning (U"The number of rows in your table is less than the number of columns. ");
			}
			numberOfRows2 = numberOfRows, numberOfColumns2 = numberOfColumns;
			mcopy.reset (1, numberOfRows2, 1, numberOfColumns2);
			NUMmatrix_copyElements<double>(m, mcopy.peek(), 1, numberOfRows2, 1, numberOfColumns2);
		}
		
		autoPCA thee = Thing_new (PCA);
		thy centroid = NUMvector<double> (1, numberOfColumns2);
		NUMcentreColumns (mcopy.peek(), 1, numberOfRows2, 1, numberOfColumns2, thy centroid);
		Eigen_initFromSquareRoot (thee.get(), mcopy.peek(), numberOfRows2, numberOfColumns2);
		thy labels = NUMvector<char32 *> (1, numberOfColumns2);

		PCA_setNumberOfObservations (thee.get(), numberOfRows2);

		/*
			The covariance matrix C = A'A / (N-1). However, we have calculated
			the eigenstructure for A'A. This has no consequences for the
			eigenvectors, but the eigenvalues have to be divided by (N-1).
		*/

		for (long i = 1; i <= thy numberOfEigenvalues; i++) {
			thy eigenvalues [i] /= (numberOfRows2 - 1);
		}
		return thee;
	} catch (MelderError) {
		Melder_throw (U"No PCA created from ", byColumns ? U"columns." : U"rows.");
	}	
}