Exemplo n.º 1
0
    def _fa_paf(self, smc = True):
        cor = self.cor.copy()
        if smc:
            np.fill_diagonal(cor, utils.SMC(cor))
        eig_val1 = la.eigvalsh(self.cor)
        eig_val1.sort()
        comm = np.sum(np.diag(cor))
        err = comm
        comm_list = []
        i = 0
        while err > self.lower:
            eig_val, eig_vec = utils.eigenh_sorted(cor)
            if (self.n_factors > 1):
                loadings = eig_vec[:, :self.n_factors].dot(
                    np.diag(np.sqrt(eig_val[:self.n_factors])))
            else:
                loadings = eig_vec[:, 0] * np.sqrt(eig_val[0])

            model = loadings.dot(loadings.T)
            new = np.diag(model)
            comm1 = np.sum(new)
            np.fill_diagonal(cor, new)
            err = np.abs(comm - comm1)
            if np.iscomplex(err):
                print('Imaginary eigenvalue condition'
                      ' occurred!')
                break
            comm = comm1
            comm_list.append(comm1)
            i += 1
            if i > 1000:
                print('maximum iteration exceeded')
                err = 0

        self.loadings = loadings
Exemplo n.º 2
0
    def _fa_out(self, Psi, S, q):
        sc = np.diag(1 / np.sqrt(Psi))
        Sstar = sc.dot(S).dot(sc)
        eig_val, eig_vec = utils.eigenh_sorted(Sstar)
        L = eig_vec[:, :q]
        load = L.dot(np.diag(np.sqrt(np.maximum(eig_val[:q] - 1, 0))))

        return np.diag(np.sqrt(Psi)).dot(load)
Exemplo n.º 3
0
        def ml_gradient(Psi, S, q):
            sc = np.diag(1 / np.sqrt(Psi))
            Sstar = sc.dot(S).dot(sc)
            eig_val, eig_vec = utils.eigenh_sorted(Sstar)
            L = eig_vec[:, :q]
            load = L.dot(np.diag(np.sqrt(np.maximum(eig_val[:q] - 1, 0))))
            load = np.diag(np.sqrt(Psi)).dot(load)
            g = load.dot(load.T) + np.diag(Psi) - S

            return np.diag(g) / (Psi ** 2)
Exemplo n.º 4
0
        def residual_gradient(Psi, S, n_factors, Sinv, method, obs):
            sc = np.diag(1 / np.sqrt(Psi))
            Sstar = sc.dot(S).dot(sc)
            eig_val, eig_vec = utils.eigenh_sorted(Sstar)
            L = eig_vec[:, :n_factors]
            load = L.dot(np.diag(np.sqrt(np.fmax(eig_val[:n_factors] - 1, 0))))
            load = np.diag(np.sqrt(Psi)).dot(load)
            g = load.dot(load.T) + np.diag(Psi) - S

            return np.diag(g) / Psi ** 2
Exemplo n.º 5
0
    def _fa_stats(self):
        X = self.cor.copy()
        loadings = self.loadings.copy()
        if self.Phi is None:
            model = loadings.dot(loadings.T)
        else:
            Phi = self.Phi.copy()
            model = loadings.dot(Phi).dot(loadings.T)
        obs = self.n_obs
        pairwise_obs = self.pairwise_obs
        alpha = self.conf_int

        var = X.shape[1]
        n_factors = loadings.shape[1]

        residual = X - model
        self.residual = residual.copy()
        X2 = np.sum(X ** 2)
        Xstar2 = np.sum(residual ** 2)

        self.dof = var * (var - 1) / 2 - var * n_factors + (
            n_factors * (n_factors - 1) / 2)
        X2_off = X2 - np.trace(X)
        np.fill_diagonal(residual, 0)

        if self.pairwise_obs is None:
            Xstar_off = np.sum(residual ** 2)
            self.ENull = X2_off * obs
            self.chi = Xstar_off * obs
            self.rms = np.sqrt(Xstar_off / (var * (var - 1)))
            self.harmonic = obs

        else:
            Xstar_off = np.sum(residual ** 2 * pairwise_obs)
            X2_off = (X * X * pairwise_obs)
            X2_off = np.sum(X2_off) - np.trace(X2_off)
            self.chi = Xstar_off
            self.harmonic = utils.harmonic_mean(np.hstack(pairwise_obs.T))
            self.rms = np.sqrt(Xstar_off / (self.harmonic * var * (var - 1)))

            if self.dof > 0:
                self.EPVAL = sp.stats.chi2.sf(self.chi, self.dof)
                self.crms = np.sqrt(Xstar_off / (2 * self.harmonic * self.dof))
                self.EBIC = self.chi - self.dof * np.log(obs)
                self.ESABIC = self.chi - self.dof * np.log(
                    (self.harmonic + 2) / 24)

            else:
                self.EPVAL = None
                self.crms = None
                self.EBIC = None
                self.ESABIC = None

        self.fit_result = 1 - Xstar2 / X2
        self.fit_off = 1 - Xstar_off / X2_off
        self.sd = np.std(residual, ddof = 1)
        self.complexity = np.apply_along_axis(
            lambda x: np.sum(x ** 2), 1, loadings) ** 2 \
            / np.apply_along_axis(lambda x: np.sum(x ** 4), 1, loadings)
        model[np.diag_indices_from(model)] = np.diag(X)
        model = utils.smooth_corrcoef(model)
        X = utils.smooth_corrcoef(X)
        model_inv = la.solve(model, X)
        self.objective = np.sum(np.diag(model_inv)) \
                         - np.log(la.det(model_inv)) - var
        chisq = self.objective * ((obs - 1) - (2 * var + 5) / 6 \
                                  - (2 * n_factors) / 3)
        if chisq < 0:
            self.statistic = 0

        else:
            self.statistic = chisq

        if self.dof > 0:
            self.PVAL = sp.stats.chi2.sf(self.statistic, self.dof)
        else:
            self.PVAL = None

        F0 = np.sum(np.diag(X)) - np.log(la.det(X)) - var
        Fm = self.objective
        Mm = Fm / (var * (var - 1) / 2 - var * n_factors + \
                   (n_factors * (n_factors - 1) / 2))
        M0 = F0 * 2 / (var * (var - 1))
        nm = (obs - 1) - (2 * var + 5) / 6 - (2 * n_factors) / 3
        self.null_model = F0
        self.null_dof = var * (var - 1) / 2
        self.null_chi2 = F0 * ((obs - 1) - (2 * var + 5) / 6)
        self.TLI = (M0 - Mm) / (M0 - 1 / nm)
        if not np.isnan(self.TLI) and self.TLI > 1:
            self.F0 = 1

        if self.dof > 0 and not np.isnan(self.objective):
            RMSEA = np.sqrt(
                np.max(self.objective / self.dof - 1 / (obs - 1), 0))
            tail = alpha / 2
            chi_max = max(obs, chisq) + 2 * obs

            while chi_max > 1:
                opt_res = sp.optimize.minimize_scalar(
                    lambda x: \
                    (tail - sp.stats.ncx2.cdf(chisq, self.dof, x)) ** 2,
                    bracket = (0, chi_max))

                if np.sqrt(opt_res.fun) < tail / 100:
                    break

                chi_max = chi_max / 2

            if chi_max <= 1:
                lamU = np.nan
                chi_max = np.nan

            else:
                lamU = opt_res.x
                chi_max = lamU

            while (chi_max > 1):
                opt_res = sp.optimize.minimize_scalar(
                    lambda x: \
                    (1 - tail - sp.stats.ncx2.cdf(chisq, self.dof, x)) ** 2,
                    bracket = (0, chi_max))

                if np.sqrt(opt_res.fun) < tail / 100:
                    break

                chi_max = chi_max / 2

            if chi_max <= 1:
                lamL = np.nan

            else:
                lamL = opt_res.x

            RMSEA_U = np.sqrt(lamU / (obs * self.dof))
            RMSEA_L = min(np.sqrt(lamL / (obs * self.dof)), RMSEA)

            self.RMSEA = [RMSEA, RMSEA_L, RMSEA_U, alpha]
            self.BIC = chisq - self.dof * np.log(obs)
            self.SABIC = chisq - self.dof * np.log((obs + 2) / 24)

        if self.Phi is not None:
            loadings = loadings.dot(Phi)

        try:
            W = la.solve(X, loadings)

        except la.LinAlgError:
            print('Correlation matrix is singular; approximation used')

            eigval, eigvec = utils.eigenh_sorted(X)
            if np.sum(np.iscomplex()) == 0:
                print('Complex eigenvalues are detected. results are suspect.')

            else:
                eigval[eigval < np.finfo(np.float64).eps] = 100 * np.finfo(
                    np.float64).eps
                X = eigvec.dot(np.diag(eigval)).dot(eigvec.T)
                np.fill_diagonal(X, 1)

                try:
                    W = la.solve(X, loadings)

                except la.LinAlgError:
                    print('Failed to calculate the beta weights'
                          ' for factor score estimates')
                    W = np.diag(np.ones((var, )))

        R2 = np.diag(W.T.dot(loadings))
        if np.prod(R2) < 0:
            print('Factor scoring weights matrix is probably singular;'
                  ' Factor score estimate results are likely to incorrect.'
                  ' Try a different factor extraction method.')
            R2[np.abs(R2) > 1] = np.nan
            R2[R2 <= 0] = np.nan

        if np.nanmax(R2) > (1 + np.finfo(np.float64).eps):
            print('The estimated weights for the factor scores'
                  ' are probably incorrect.'
                  'Try a different factor extraction method.')

        self.Rscores = utils.cov_to_cor(W.T.dot(X).dot(W))
        self.R2 = R2

        keys = utils.factor_to_cluster(loadings)
        covar = keys.T.dot(X).dot(keys)

        if n_factors > 1 and covar.shape[1] > 1:
            sdinv = np.diag(1 / np.sqrt(np.diag(covar)))
            cluster_corr = sdinv.dot(covar).dot(sdinv)
            valid = loadings.T.dot(keys).dot(sdinv)
            self.valid = np.diag(valid)
            self.score_corr = cluster_corr

        else:
            sdinv = 1 / np.sqrt(covar)
            if (sdinv.shape[0] == 1):
                sdinv = np.diag(sdinv)
                self.valid = loadings.T.dot(keys).dot(sdinv)

        self.weights = W