Model or dataset
easystats/performance avatar
easystats/performance

performance picks one r-squared and leaves the choice to you

:muscle: Models' quality and performance metrics (R2, ICC, LOO, AIC, BF, ...)

1,158 stars109 forksRGPL-3.0

At a glance

What is it?
An R package that answers a narrow question: how good is this model. It computes fit indices and goodness-of-fit measures that were previously scattered across packages, and its central design decision is that a single generic function returns a list rather than picking one number for you. The newest release is 0.18.2 from 2026-09-10 and the last push is 2026-10-01.
Who is it for?
Use performance if you write regression models in R and keep having the same argument with a colleague about which fit statistic to report, because that is the gap it was built for and it resolves the ambiguity by returning every relevant measure rather than picking one. Two things to know before you rely on it.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly R, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 4, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One generic function, and it hands back a list rather than a number

The design decision worth understanding before anything else is that the generic r-squared function returns a list. It computes the measure the package considers most appropriate for whatever model you gave it, and it gives you that value under a label naming the variant, rather than flattening everything into one column. The three examples on the page show the same call producing three different answers. A linear model on a car data set gives a plain R-squared and an adjusted one. A logistic model gives a measure named for its author, not the plain value at all. An ordered model gives a third, named measure, and its value is small because that is what the measure does. The same call, three meanings, three labels. That is the package's contribution: not a new statistic, but a rule for which one to quote and a printed name so you cannot quote it without saying which.

Mixed models get two numbers, and the difference is the fixed effects

For mixed models the package returns both a conditional and a marginal value, and the documentation explains the distinction rather than leaving you to infer it. The marginal value considers only the variance of the fixed effects, so it answers how much of the variance the fixed part alone explains. The conditional value takes the fixed and random effects together and answers how much the complete model explains. On the page's two examples the gap is large. A Bayesian mixed model gives a conditional value near 0.95 and a marginal value near 0.41. A frequentist mixed model on a sleep data set gives a conditional near 0.80 and a marginal near 0.28. Reporting only the conditional number makes the model look far better than the fixed-effects-only part justifies. The page also names the citations behind the frequentist calculation and notes that the same function handles random slopes and nested random effects.

The intraclass coefficient comes in adjusted and unadjusted, too

The grouping-structure measure follows the same pattern of returning two numbers, and the same warning applies. The page frames the measure as the proportion of variance explained by the grouping structure in the population, credited to a cited source, and computes it for mixed models and for one class of fitted objects from another package. On the sleep data set the adjusted value comes out near 0.72 and the unadjusted near 0.52. On a model from a different fitting engine the pair is higher still, near 0.93 adjusted and 0.77 unadjusted. The unadjusted number is the raw ratio, and the adjustment is the one that accounts for the finite number of groups. Both are printed with their names. A reader who quotes the larger of the two without saying which is which is doing the same thing the package was built to prevent.

Diagnostics cover overdispersion, zero-inflation, convergence and singularity

Beyond fit indices the package checks models for four specific problems, and each check comes with the documented fix. Overdispersion is where observed variance exceeds what the model's assumption expects, which for a count model means variance above the mean; the check reports a dispersion ratio and a test, and the documented remedies are to model the dispersion parameter where the fitting engine allows it or to move to a different family such as quasi-Poisson or negative binomial. Zero-inflation is the mirror case, where observed zeros outnumber predicted ones and the model is underfitting the zeros; the recommendation is a negative binomial or zero-inflated model instead. Convergence and singularity checks complete the set. That last combination is what turns the package from a numbers generator into a diagnostic pass you run before believing any of the numbers.

The named functions exist when you want a specific measure on purpose

The generic function is the front door, but there is a second door behind it. Any of the individual measures can be requested directly by name, and the page names three of them plus the full list is linked. That distinction matters for reproducibility and for review. If your analysis plan says a particular measure, calling the named function makes the choice visible in the code rather than something the package decided on your behalf. If you are exploring, the generic function is right. The mixed-model function is also named separately from the generic one, so a reader who wants the frequentist calculation without the generic dispatch can have it. The page is explicit that the generic function returns a list of values related to the most appropriate measure, which is a contract rather than a guarantee that one number is the right one for your field.

Install from two sources, and the family has a shared loader

There are two install routes and they are for different purposes. The release line is on CRAN with a single install call. The development line is on a separate binary package service run by a research organisation, and the command adds a repository argument rather than a version pin, so it tracks that service's current state.

r
install.packages("performance")
install.packages("performance", repos = "https://easystats.r-universe.dev")

The page then recommends neither over the other: load the single package if you only want these measures, or load the shared meta-package if you want every feature of the wider ecosystem, and keep it current with the ecosystem's own update helper. The badges at the top give the canonical archive, the package registry, and a dependency-log service, and there is a peer-reviewed software citation for the package itself, which for a statistics package is a normal mark of maturity rather than a novelty.

The repository holds a journal paper, vignettes and a directory named WIP

The tree explains the shape of the project better than the readme does. There is the usual package skeleton, plus a directory of vignettes, a directory named for the journal paper, a bibliography file, a package-submission marker, release notes, a code workspace file, and a site configuration directory for the documentation. Two entries stand out. There is a readme source file alongside the generated readme, which is the ordinary pattern but does mean the readme you read is built from something else. And there is a directory whose name is a three-letter abbreviation for work in progress, sitting in a published package. A lint configuration and a formatter configuration are both committed, so the style rules are in the repository rather than in a contributor's head. The last push is dated 2026-10-01 and the newest release is 0.18.2 from 2026-09-10.

Editorial conclusion

Use performance if you write regression models in R and keep having the same argument with a colleague about which fit statistic to report, because that is the gap it was built for and it resolves the ambiguity by returning every relevant measure rather than picking one. Two things to know before you rely on it. The R-squared it returns is not always the one your field quotes: for a mixed model you get both a conditional and a marginal value, and for a logistic model you get a pseudo-measure named for its author, so read the label on the output rather than assuming the number means what you think. And the package is one of a family, with a shared meta-package that loads all of them and a shared documentation site, so the question of which measure to report is partly a question of which packages you have installed.

Frequently asked questions

What does the performance R package do?

It computes indices of model quality and goodness of fit, and checks models for overdispersion, zero-inflation, convergence and singularity. Its stated purpose is to fill a gap: functions for diagnostic plots and fit measures already existed but were spread across different packages with no consistent approach across model types.

Why does r2() in performance return a list instead of one number?

Because the appropriate r-squared differs by model type. The page's examples show a linear model returning a plain and an adjusted value, a logistic model returning one measure named for its author, and an ordered model returning another. The package returns the most appropriate value for the model you gave it, labelled, rather than flattening the choice into a single number.

What is the difference between conditional and marginal R-squared in performance?

The marginal value considers only the variance of the fixed effects, so it says how much the fixed part alone explains. The conditional value takes fixed and random effects together and says how much the complete model explains. On the page's examples the two differ substantially, with a conditional value near 0.95 against a marginal near 0.41 for one Bayesian model.

How does performance check for overdispersion and zero-inflation?

check_overdispersion() reports a dispersion ratio and a test for count models, including mixed models, where observed variance exceeds the expected. check_zeroinflation() checks the mirror case, where observed zeros outnumber predicted ones. The documented fixes are to model the dispersion parameter where possible or to move to a different family such as quasi-Poisson, negative binomial, or a zero-inflated model.

How do I install the performance package for development?

The release line is installed from CRAN with install.packages("performance"). The development line uses the same call with a repositories argument pointing at the easystats universe service, which tracks that service's current state rather than a pinned version. The page also suggests loading the shared meta-package instead if you want the whole ecosystem, and keeping it current with the ecosystem's update helper.

Official sources

  1. easystats/performance on GitHub
  2. License: GPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/easystats-performance.svg)](https://hysenlabs.com/projects/easystats-performance)