pastas/metran

Velicer's MAP Test results in 0 factors for Dynamic Factor Model notebook

martinvonk opened this issue · 1 comments

David and I get different results dependent on our machines. They get 0 factors with Velicer's MAP test while I get 1 (as intended originally). Velicer's MAP test code:

def _maptest(cov, eigvec, eigval):
"""Internal method to run Velicer's MAP test.
Determines the number of factors to be used. This method includes
two variations of the MAP test: the orginal and the revised MAP test.
Parameters
----------
cov : numpy.ndarray
Covariance matrix.
eigvec : numpy.ndarray
Matrix with columns eigenvectors associated with eigenvalues.
eigval : numpy.ndarray
Vector with eigenvalues in descending order.
Returns
-------
nfacts : integer
Number factors according to MAP test.
nfacts4 : integer
Number factors according to revised MAP test.
References
----------
The original MAP test:
Velicer, W. F. (1976). Determining the number of components
from the matrix of partial correlations. Psychometrika, 41, 321-327.
The revised (2000) MAP test i.e., with the partial correlations
raised to the 4rth power (rather than squared):
Velicer, W. F., Eaton, C. A., and Fava, J. L. (2000). Construct
explication through factor or component analysis: A review and
evaluation of alternative procedures for determining the number
of factors or components. Pp. 41-71 in R. D. Goffin and
E. Helmes, eds., Problems and solutions in human assessment.
Boston: Kluwer.
"""
nvars = len(eigval)
fm = np.array([np.arange(nvars, dtype=float), np.arange(nvars, dtype=float)]).T
np.put(
fm,
[0, 1],
((np.sum(np.sum(np.square(cov))) - nvars) / (nvars * (nvars - 1))),
)
fm4 = np.copy(fm)
np.put(
fm4,
[0, 1],
(
(np.sum(np.sum(np.square(np.square(cov)))) - nvars)
/ (nvars * (nvars - 1))
),
)
for m in range(nvars - 1):
biga = np.atleast_2d(eigvec[:, : m + 1])
partcov = cov - np.dot(biga, biga.T)
# exit function with nfacts=1 if diag partcov contains negatives
if np.amin(np.diag(partcov)) < 0:
return 1, 1
d = np.diag((1 / np.sqrt(np.diag(partcov))))
pr = np.dot(d, np.dot(partcov, d))
np.put(
fm,
[m + 1, 1],
((np.sum(np.sum(np.square(pr))) - nvars) / (nvars * (nvars - 1))),
)
np.put(
fm4,
[m + 1, 1],
(
(np.sum(np.sum(np.square(np.square(pr)))) - nvars)
/ (nvars * (nvars - 1))
),
)
minfm = fm[0, 1]
nfacts = 0
minfm4 = fm4[0, 1]
nfacts4 = 0
for s in range(nvars):
fm[s, 0] = s
fm4[s, 0] = s
if fm[s, 1] < minfm:
minfm = fm[s, 1]
nfacts = s
if fm4[s, 1] < minfm4:
minfm4 = fm4[s, 1]
nfacts4 = s
return nfacts, nfacts4

On my device:

eigvec = array([[ 0.96750358, -0.25285732],  [ 0.96750358,  0.25285732]])
eigvec[0,0] = 0.9675035797467857
eigvec[0,1] = -0.25285731782401605
eigvec[1,0] = 0.9675035797467855
eigvec[1,1] = 0.2528573178240161

Later on this results in:

minfm = 1.000000000000007
minfm4 = 1.0000000000000142

which yields True for (if s = 1):

if fm[s, 1] < minfm:`

with fm[s, 1] = 1.0

Resolved. Reinstalling the environment on Davíd's machine solved the issue.