def calc_fpca(self, no=3): """ This function calculates horizontal functional principal component analysis on aligned data :param no: number of components to extract (default = 3) :type no: int :rtype: fdahpca object of numpy ndarray :return q_pca: srsf principal directions :return f_pca: functional principal directions :return latent: latent values :return coef: coefficients :return U: eigenvectors """ # Calculate Shooting Vectors gam = self.warp_data.gam mu, gam_mu, psi, vec = uf.SqrtMean(gam) tau = np.arange(1, 6) TT = self.warp_data.time.shape[0] # TFPCA K = np.cov(vec) U, s, V = svd(K) vm = vec.mean(axis=1) gam_pca = np.ndarray(shape=(tau.shape[0], mu.shape[0], no), dtype=float) psi_pca = np.ndarray(shape=(tau.shape[0], mu.shape[0], no), dtype=float) for j in range(0, no): for k in tau: v = (k - 3) * np.sqrt(s[j]) * U[:, j] vn = norm(v) / np.sqrt(TT) if vn < 0.0001: psi_pca[k-1, :, j] = mu else: psi_pca[k-1, :, j] = np.cos(vn) * mu + np.sin(vn) * v / vn tmp = cumtrapz(psi_pca[k-1, :, j] * psi_pca[k-1, :, j], np.linspace(0,1,TT), initial=0) gam_pca[k-1, :, j] = (tmp - tmp[0]) / (tmp[-1] - tmp[0]) N2 = gam.shape[1] c = np.zeros((N2,no)) for k in range(0,no): for i in range(0,N2): c[i,k] = np.sum(dot(vec[:,i]-vm,U[:,k])) self.gam_pca = gam_pca self.psi_pca = psi_pca self.U = U self.coef = c self.latent = s self.gam_mu = gam_mu self.psi_mu = mu self.vec = vec self.no = no return
def horizfPCA(gam, time, no, showplot=True): """ This function calculates horizontal functional principal component analysis on aligned data :param gam: numpy ndarray of shape (M,N) of N warping functions :param time: vector of size M describing the sample points :param no: number of components to extract (default = 1) :param showplot: Shows plots of results using matplotlib (default = T) :type showplot: bool :type no: int :rtype: tuple of numpy ndarray :return q_pca: srsf principal directions :return f_pca: functional principal directions :return latent: latent values :return coef: coefficients :return U: eigenvectors """ # Calculate Shooting Vectors mu, gam_mu, psi, vec = uf.SqrtMean(gam) tau = np.arange(1, 6) TT = time.shape[0] # TFPCA K = np.cov(vec) U, s, V = svd(K) vm = vec.mean(axis=1) gam_pca = np.ndarray(shape=(tau.shape[0], mu.shape[0] + 1, no), dtype=float) psi_pca = np.ndarray(shape=(tau.shape[0], mu.shape[0], no), dtype=float) for j in range(0, no): for k in tau: v = (k - 3) * np.sqrt(s[j]) * U[:, j] vn = norm(v) / np.sqrt(TT) if vn < 0.0001: psi_pca[k-1, :, j] = mu else: psi_pca[k-1, :, j] = np.cos(vn) * mu + np.sin(vn) * v / vn tmp = np.zeros(TT) tmp[1:TT] = np.cumsum(psi_pca[k-1, :, j] * psi_pca[k-1, :, j]) gam_pca[k-1, :, j] = (tmp - tmp[0]) / (tmp[-1] - tmp[0]) hfpca_results = collections.namedtuple('hfpca', ['gam_pca', 'psi_pca', 'latent', 'U', 'gam_mu']) hfpca = hfpca_results(gam_pca, psi_pca, s, U, gam_mu) if showplot: CBcdict = { 'Bl': (0, 0, 0), 'Or': (.9, .6, 0), 'SB': (.35, .7, .9), 'bG': (0, .6, .5), 'Ye': (.95, .9, .25), 'Bu': (0, .45, .7), 'Ve': (.8, .4, 0), 'rP': (.8, .6, .7), } fig, ax = plt.subplots(1, no) for k in range(0, no): axt = ax[k] axt.set_color_cycle(CBcdict[c] for c in sorted(CBcdict.keys())) tmp = gam_pca[:, :, k] axt.plot(np.linspace(0, 1, TT), tmp.transpose()) axt.set_title('PD %d' % (k + 1)) axt.set_aspect('equal') plot.rstyle(axt) fig.set_tight_layout(True) cumm_coef = 100 * np.cumsum(s) / sum(s) idx = np.arange(0, TT-1) + 1 plot.f_plot(idx, cumm_coef, "Coefficient Cumulative Percentage") plt.xlabel("Percentage") plt.ylabel("Index") plt.show() return hfpca
def calc_fpca(self, no=3, stds=np.arange(-1., 2.), id=None, parallel=False, cores=-1): """ This function calculates joint functional principal component analysis on aligned data :param no: number of components to extract (default = 3) :param id: point to use for f(0) (default = midpoint) :param stds: number of standard deviations along gedoesic to compute (default = -1,0,1) :param parallel: run in parallel (default = F) :param cores: number of cores for parallel (default = -1 (all)) :type no: int :type id: int :type parallel: bool :type cores: int :rtype: fdajpca object of numpy ndarray :return q_pca: srsf principal directions :return f_pca: functional principal directions :return latent: latent values :return coef: coefficients :return U: eigenvectors """ fn = self.warp_data.fn time = self.warp_data.time qn = self.warp_data.qn q0 = self.warp_data.q0 gam = self.warp_data.gam M = time.shape[0] if id is None: mididx = int(np.round(M / 2)) else: mididx = id Nstd = stds.shape[0] # set up for fPCA in q-space mq_new = qn.mean(axis=1) m_new = np.sign(fn[mididx, :]) * np.sqrt(np.abs(fn[mididx, :])) mqn = np.append(mq_new, m_new.mean()) qn2 = np.vstack((qn, m_new)) # calculate vector space of warping functions mu_psi, gam_mu, psi, vec = uf.SqrtMean(gam, parallel, cores) # joint fPCA C = fminbound(find_C, 0, 1e4, (qn2, vec, q0, no, mu_psi, parallel, cores)) qhat, gamhat, a, U, s, mu_g, g, cov = jointfPCAd( qn2, vec, C, no, mu_psi, parallel, cores) # geodesic paths q_pca = np.ndarray(shape=(M, Nstd, no), dtype=float) f_pca = np.ndarray(shape=(M, Nstd, no), dtype=float) for k in range(0, no): for l in range(0, Nstd): qhat = mqn + np.dot(U[0:(M + 1), k], stds[l] * np.sqrt(s[k])) vechat = np.dot(U[(M + 1):, k], (stds[l] * np.sqrt(s[k])) / C) psihat = geo.exp_map(mu_psi, vechat) gamhat = cumtrapz(psihat * psihat, np.linspace(0, 1, M), initial=0) gamhat = (gamhat - gamhat.min()) / (gamhat.max() - gamhat.min()) if (sum(vechat) == 0): gamhat = np.linspace(0, 1, M) fhat = uf.cumtrapzmid(time, qhat[0:M] * np.fabs(qhat[0:M]), np.sign(qhat[M]) * (qhat[M] * qhat[M]), mididx) f_pca[:, l, k] = uf.warp_f_gamma(np.linspace(0, 1, M), fhat, gamhat) q_pca[:, l, k] = uf.warp_q_gamma(np.linspace(0, 1, M), qhat[0:M], gamhat) self.q_pca = q_pca self.f_pca = f_pca self.latent = s[0:no] self.coef = a self.U = U[:, 0:no] self.mu_psi = mu_psi self.mu_g = mu_g self.id = mididx self.C = C self.time = time self.g = g self.cov = cov self.no = no self.stds = stds return