EducationalTestingService / EducationalTestingService/factor_analyzer
random initial values for rotation matrix in GPA rotations
- Dominant language
- Python
- Stars
- 6
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
Hi all. First, thanks so much to the devs of `factor_analyzer`. It's a fantastic and much needed package!
**Is your feature request related to a problem? Please describe.**
As has been pointed out, the GPA rotation methods often converge to local minima ([Browne, 2001](https://doi.org/10.1207/S15327906MBR3601_05); [Bernaards & Jennrich, 2005](https://doi.org/10.1177/0013164404272507); [Nguyen & Waller, 2022](https://doi.org/10.1177/0013164404272507)). As such, it's been recommended researchers initialize the GPA from many starting values when searching for a global minimum. I'm wondering if the `Rotator` class could be amended in order to allow initializing the GPA from different starting values.
**Describe the solution you'd like**
One simple solution would be for the `Rotator` class to accept a new argument, `random_state`, which defaults to `None`. When `random_state = None`, the rotation matrix is initialized with `np.eye(n_cols)` as is currently implemented ([L326](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L326), [L416](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L416), [L493](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L493)). When a user specifies a seed, however, the rotation matrix is initialized as a random orthogonal matrix from [`scipy.stats.ortho_group`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ortho_group.html). That is,:
```python
# initialize the rotation matrix
_, n_cols = loadings.shape
if self.random_state == None:
rotation_matrix = np.eye(n_cols)
else:
rotation_matrix = sp.stats.ortho_group(dim=n_cols, seed=self.random_state).rvs()
```
A solution like the above could be added to the [`Rotator._oblique`](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L293), [`Rotator._orthogonal`](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L382), [`Rotator._varimax`](https://github.com/EducationalTestingService/factor_analyzer/blob/main/factor_analyzer/rotator.py#L462) methods (and any others that I missed).
Apologies in advance if the above is already possible and I've simply missed how. If the above sounds like it may be useful, I'd be happy to attempt a PR.
All the best,
Sam (@szorowi1)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.