{"id":30855354,"url":"https://github.com/EducationalTestingService/factor_analyzer","last_synced_at":"2025-09-07T11:05:23.069Z","repository":{"id":27495889,"uuid":"113231437","full_name":"EducationalTestingService/factor_analyzer","owner":"EducationalTestingService","description":"A Python module to perform exploratory \u0026 confirmatory factor analyses.","archived":false,"fork":false,"pushed_at":"2025-01-21T16:22:09.000Z","size":5132,"stargazers_count":257,"open_issues_count":16,"forks_count":70,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-08-30T11:36:38.822Z","etag":null,"topics":["cfa","efa","factor-analysis","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EducationalTestingService.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-12-05T20:48:36.000Z","updated_at":"2025-08-15T01:46:58.000Z","dependencies_parsed_at":"2022-07-27T09:32:25.061Z","dependency_job_id":"174325d8-a6f9-4146-beac-51dac0ac21b2","html_url":"https://github.com/EducationalTestingService/factor_analyzer","commit_stats":{"total_commits":234,"total_committers":13,"mean_commits":18.0,"dds":0.2777777777777778,"last_synced_commit":"b59592d5ef014d6cd2e918bf1281b7368280b996"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/EducationalTestingService/factor_analyzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EducationalTestingService%2Ffactor_analyzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EducationalTestingService%2Ffactor_analyzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EducationalTestingService%2Ffactor_analyzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EducationalTestingService%2Ffactor_analyzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EducationalTestingService","download_url":"https://codeload.github.com/EducationalTestingService/factor_analyzer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EducationalTestingService%2Ffactor_analyzer/sbom","scorecard":{"id":44492,"data":{"date":"2025-08-11","repo":{"name":"github.com/EducationalTestingService/factor_analyzer","commit":"de933d26808039d965c117874c67260ec5149690"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":8,"reason":"Found 12/14 approved changesets -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"11 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2018-34 / GHSA-2fc2-6r4j-p65h","Warn: Project is vulnerable to: PYSEC-2021-856 / GHSA-5545-2q6w-2gh6","Warn: Project is vulnerable to: PYSEC-2019-108 / GHSA-9fq2-x9r6-wfmf","Warn: Project is vulnerable to: PYSEC-2018-33 / GHSA-cw6w-4rcx-xphc","Warn: Project is vulnerable to: PYSEC-2021-857 / GHSA-f7c7-j99h-c22f","Warn: Project is vulnerable to: GHSA-fpfv-jqm9-f5jm","Warn: Project is vulnerable to: PYSEC-2017-1 / GHSA-frgw-fgh6-9g52","Warn: Project is vulnerable to: PYSEC-2020-73","Warn: Project is vulnerable to: PYSEC-2019-156 / GHSA-xp76-357g-9wqq","Warn: Project is vulnerable to: PYSEC-2023-102","Warn: Project is vulnerable to: PYSEC-2023-114"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-14T22:23:49.672Z","repository_id":27495889,"created_at":"2025-08-14T22:23:49.672Z","updated_at":"2025-08-14T22:23:49.672Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274026718,"owners_count":25209740,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cfa","efa","factor-analysis","python"],"created_at":"2025-09-07T11:05:13.207Z","updated_at":"2025-09-07T11:05:23.047Z","avatar_url":"https://github.com/EducationalTestingService.png","language":"Python","readme":"FactorAnalyzer\n--------------\n\n.. image:: https://gitlab.com/EducationalTestingService/factor_analyzer/badges/main/pipeline.svg\n   :target: https://gitlab.com/EducationalTestingService/factor_analyzer/-/pipelines\n   :alt: Build status\n\n.. image:: https://codecov.io/gh/EducationalTestingService/factor_analyzer/branch/main/graph/badge.svg\n   :target: https://codecov.io/gh/EducationalTestingService/factor_analyzer\n   :alt: Code coverage\n\n.. image:: https://anaconda.org/ets/factor_analyzer/badges/version.svg\n   :target: https://anaconda.org/ets/factor_analyzer/\n   :alt: Conda version\n\n.. image:: https://img.shields.io/pypi/v/factor_analyzer\n   :target: https://pypi.org/project/factor-analyzer/\n   :alt: PyPI version\n\n.. image:: https://img.shields.io/readthedocs/factor_analyzer/latest.svg\n   :target: https://factor-analyzer.readthedocs.io/\n   :alt: Docs\n\n.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white\n   :target: https://github.com/pre-commit/pre-commit\n   :alt: Pre-commit checks\n\n\nThis is a Python module to perform exploratory and factor analysis (EFA), with several\noptional rotations. It also includes a class to perform confirmatory factor\nanalysis (CFA), with certain pre-defined constraints. In exploratory factor analysis,\nfactor extraction can be performed using a variety of estimation techniques. The\n``factor_analyzer`` package allows users to perform EFA using either (1) a minimum\nresidual (MINRES) solution, (2) a maximum likelihood (ML) solution, or (3) a principal\nfactor solution. However, CFA can only be performed using an ML solution.\n\nBoth the EFA and CFA classes within this package are fully compatible with `scikit-learn`.\nPortions of this code are ported from the excellent R library `psych`, and the `sem`\npackage provided inspiration for the CFA class.\n\nPlease see the `official documentation \u003chttps://factor-analyzer.readthedocs.io/en/latest/index.html\u003e`__ for additional details.\n\n\nDescription\n-----------\n\nExploratory factor analysis (EFA) is a statistical technique used to\nidentify latent relationships among sets of observed variables in a\ndataset. In particular, EFA seeks to model a large set of observed\nvariables as linear combinations of some smaller set of unobserved,\nlatent factors. The matrix of weights, or factor loadings, generated\nfrom an EFA model describes the underlying relationships between each\nvariable and the latent factors.\n\nConfirmatory factor analysis (CFA), a closely associated technique, is\nused to test an a priori hypothesis about latent relationships among sets\nof observed variables. In CFA, the researcher specifies the expected pattern\nof factor loadings (and possibly other constraints), and fits a model according\nto this specification.\n\nTypically, a number of factors (K) in an EFA or CFA model is selected\nsuch that it is substantially smaller than the number of variables. The\nfactor analysis model can be estimated using a variety of standard\nestimation methods, including but not limited MINRES or ML.\n\nFactor loadings are similar to standardized regression coefficients, and\nvariables with higher loadings on a particular factor can be interpreted\nas explaining a larger proportion of the variation in that factor. In the\ncase of EFA, factor loading matrices are usually rotated after the factor\nanalysis model is estimated in order to produce a simpler, more interpretable\nstructure to identify which variables are loading on a particular factor.\n\nTwo common types of rotations are:\n\n1. The **varimax** rotation, which rotates the factor loading matrix so\n   as to maximize the sum of the variance of squared loadings, while\n   preserving the orthogonality of the loading matrix.\n\n2. The **promax** rotation, a method for oblique rotation, which builds\n   upon the varimax rotation, but ultimately allows factors to become\n   correlated.\n\nThis package includes a ``factor_analyzer`` module with a stand-alone\n``FactorAnalyzer`` class. The class includes ``fit()`` and ``transform()``\nmethods that enable users to perform factor analysis and score new data\nusing the fitted factor model. Users can also perform optional rotations\non a factor loading matrix using the ``Rotator`` class.\n\nThe following rotation options are available in both ``FactorAnalyzer``\nand ``Rotator``:\n\n    (a) varimax (orthogonal rotation)\n    (b) promax (oblique rotation)\n    (c) oblimin (oblique rotation)\n    (d) oblimax (orthogonal rotation)\n    (e) quartimin (oblique rotation)\n    (f) quartimax (orthogonal rotation)\n    (g) equamax (orthogonal rotation)\n    (h) geomin_obl (oblique rotation)\n    (i) geomin_ort (orthogonal rotation)\n\nIn addition, the package includes a ``confirmatory_factor_analyzer``\nmodule with a stand-alone ``ConfirmatoryFactorAnalyzer`` class. The\nclass includes ``fit()`` and ``transform()``  that enable users to perform\nconfirmatory factor analysis and score new data using the fitted model.\nPerforming CFA requires users to specify in advance a model specification\nwith the expected factor loading relationships. This can be done using\nthe ``ModelSpecificationParser`` class.\n\nNote that the ``ConfirmatoryFactorAnalyzer`` class is very experimental at this point,\nso use it with caution, especially if your data are highly non-normal.\n\nExamples\n--------\n\nExploratory factor analysis example.\n\n.. code:: python\n\n  In [1]: import pandas as pd\n     ...: from factor_analyzer import FactorAnalyzer\n\n  In [2]: df_features = pd.read_csv('tests/data/test02.csv')\n\n  In [3]: fa = FactorAnalyzer(rotation=None)\n\n  In [4]: fa.fit(df_features)\n  Out[4]:\n  FactorAnalyzer(bounds=(0.005, 1), impute='median', is_corr_matrix=False,\n                 method='minres', n_factors=3, rotation=None, rotation_kwargs={},\n                 use_smc=True)\n\n  In [5]: fa.loadings_\n  Out[5]:\n  array([[-0.12991218,  0.16398151,  0.73823491],\n         [ 0.03899558,  0.04658425,  0.01150343],\n         [ 0.34874135,  0.61452341, -0.07255666],\n         [ 0.45318006,  0.7192668 , -0.0754647 ],\n         [ 0.36688794,  0.44377343, -0.01737066],\n         [ 0.74141382, -0.15008235,  0.29977513],\n         [ 0.741675  , -0.16123009, -0.20744497],\n         [ 0.82910167, -0.20519428,  0.04930817],\n         [ 0.76041819, -0.23768727, -0.12068582],\n         [ 0.81533404, -0.12494695,  0.17639684]])\n\n  In [6]: fa.get_communalities()\n  Out[6]:\n  array([0.5887579 , 0.00382308, 0.50452402, 0.72841182, 0.33184336,\n         0.66208429, 0.61911037, 0.73194557, 0.64929612, 0.71149718])\n\nConfirmatory factor analysis example.\n\n.. code:: python\n\n  In [1]: import pandas as pd\n\n  In [2]: from factor_analyzer import (ConfirmatoryFactorAnalyzer,\n     ...:                              ModelSpecificationParser)\n\n  In [3]: df_features = pd.read_csv('tests/data/test11.csv')\n\n  In [4]: model_dict = {\"F1\": [\"V1\", \"V2\", \"V3\", \"V4\"],\n     ...:               \"F2\": [\"V5\", \"V6\", \"V7\", \"V8\"]}\n  In [5]: model_spec = ModelSpecificationParser.parse_model_specification_from_dict(df_features,\n     ...:                                                                           model_dict)\n\n  In [6]: cfa = ConfirmatoryFactorAnalyzer(model_spec, disp=False)\n\n  In [7]: cfa.fit(df_features.values)\n\n  In [8]: cfa.loadings_\n  Out[8]:\n  array([[0.99131285, 0.        ],\n         [0.46074919, 0.        ],\n         [0.3502267 , 0.        ],\n         [0.58331488, 0.        ],\n         [0.        , 0.98621042],\n         [0.        , 0.73389239],\n         [0.        , 0.37602988],\n         [0.        , 0.50049507]])\n\n  In [9]: cfa.factor_varcovs_\n  Out[9]:\n  array([[1.        , 0.17385704],\n         [0.17385704, 1.        ]])\n\n  In [10]: cfa.transform(df_features.values)\n  Out[10]:\n  array([[-0.46852166, -1.08708035],\n         [ 2.59025301,  1.20227783],\n         [-0.47215977,  2.65697245],\n         ...,\n         [-1.5930886 , -0.91804114],\n         [ 0.19430887,  0.88174818],\n         [-0.27863554, -0.7695101 ]])\n\nRequirements\n------------\n\n-  Python 3.8 or higher\n-  ``numpy``\n-  ``pandas``\n-  ``scipy``\n-  ``scikit-learn \u003e= 1.6.0``\n\nContributing\n------------\n\nContributions to ``factor_analyzer`` are very welcome. Please file an issue\nin the repository if you would like to contribute.\n\nYou can install the development requirements in a virtual environment with:\n\n.. code-block:: bash\n\n   python -m pip install -e .[dev]\n   pre-commit install\n\nInstallation\n------------\n\nYou can install this package via ``pip`` with:\n\n``$ pip install factor_analyzer``\n\nAlternatively, you can install via ``conda`` with:\n\n``$ conda install -c ets factor_analyzer``\n\nLicense\n-------\n\nGNU General Public License (\u003e= 2)\n","funding_links":[],"categories":["🐍 Python"],"sub_categories":["Useful Python Tools for Data Analysis"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEducationalTestingService%2Ffactor_analyzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FEducationalTestingService%2Ffactor_analyzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FEducationalTestingService%2Ffactor_analyzer/lists"}