Open-source project
grf-labs/grf avatar
grf-labs/grf

grf-labs/grf: causal forests for treatment effect estimation in R

Generalized Random Forests

1,109 stars283 forksC++GPL-3.0

At a glance

What is it?
GRF is an R package with a C++ core that estimates heterogeneous treatment effects and other forest-based quantities, with honest splitting and confidence intervals. It is built for researchers and analysts who need non-parametric effect estimates with uncertainty, not for teams looking for a general purpose ML library.
Who is it for?
Adopt GRF if you are estimating heterogeneous treatment effects or other forest-based quantities in R and you need honest splitting and confidence intervals as part of the estimate. Do not adopt it if you want a general purpose random forest for prediction, or if you need a Python-first workflow, since the package is distributed through CRAN and conda-forge as an R package.
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 138 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

What GRF estimates that a standard random forest does not

A standard random forest predicts an outcome. GRF is aimed at a different question: how does the effect of a treatment vary across units. The README describes the package as providing non-parametric methods for heterogeneous treatment effects estimation, optionally with right-censored outcomes, multiple treatment arms or outcomes, or instrumental variables. It also covers least-squares regression, quantile regression, and survival regression, all with support for missing covariates. The intended user is someone doing causal or econometric analysis in R who needs an effect estimate per unit rather than a single average effect, and who needs an interval around that estimate. The README example fits a causal forest on simulated data where the treatment probability depends on X[, 1], the outcome depends on several covariates, and the true effect is pmax(X[, 1], 0), then plots the predicted effects against that known curve. That is the shape of the workflow: you supply covariates X, outcome Y and treatment W, and you get back predictions of the conditional average treatment effect. This is a narrower audience than a general ML package serves, and that narrowness is the point.

Honest splitting and the leaf population step

The mechanism the README singles out is honesty. GRF supports honest estimation, where one subset of the data is used for choosing splits and another for populating the leaves of the tree. Splitting and leaf value estimation are separated. The practical consequence is that the leaf estimates are not fitted on the same observations that determined the partition, which is what allows the package to attach confidence intervals to least-squares regression and treatment effect estimation. The README states that confidence intervals are available for those two cases, and the example shows the corresponding call: predict(tau.forest, X.test, estimate.variance = TRUE) returns variance.estimates, and the example takes their square root to get sigma.hat. Note the comment in the example that growing more trees is now recommended once you ask for intervals, and the example refits with num.trees = 4000. Variance estimation is not free, and the default tree count is not sized for it. The same example builds normal-approximation bands as predictions plus and minus 1.96 times sigma.hat. Nothing in the README claims those intervals are exact in small samples, so treat them as the package's stated output rather than a guarantee.

The nuisance step: W.hat and Y.hat

The second README example is the one worth reading closely, because it shows where most of the modelling judgement sits. Rather than passing X, Y and W straight to causal_forest, it first fits regression_forest on W and on Y separately, predicts W.hat and Y.hat, and then passes those as arguments to causal_forest along with the selected covariates. The README notes that pre-fitting models for Y and W separately may be helpful, for instance if different models use different covariates, and that in some applications one may want Y.hat and W.hat from a completely different method such as boosting. That is a real degree of freedom and a real place to get things wrong: the propensity and outcome models are your responsibility, and the forest's behaviour depends on them. The example also filters covariates using variable_importance, keeping variables whose importance exceeds 0.2 times the mean, with an explicit warning that forests may struggle when trained on very few variables such as one, two or three columns, and a recommendation not to be too aggressive in selection. Both ends of that range are hazards, and the README flags them rather than resolving them for you.

Installing from CRAN, conda-forge or source

The release path is short. From CRAN: install.packages("grf"). For conda users, the README gives conda install -c conda-forge r-grf. The development version comes from source with devtools::install_github("grf-labs/grf", subdir = "r-package/grf"). That last command carries a build requirement stated in the README: a compiler implementing C++17 or later, and on Windows the RTools toolchain as well. The C++17 requirement is the practical gate for source installs on older systems, and it is the reason a CRAN or conda binary is the lower-friction choice for most users. The package is GPL-3.0, and the README states the repository began as a fork of ranger, with thanks to the ranger authors. If you are distributing GRF inside a product, that lineage and licence are worth checking against your own distribution terms before you build on it. Nothing here is legal advice; the licence text is the authority.

Tuning, and the parts the README leaves to you

The README shows tune.parameters = "all" on the regression_forest calls that produce W.hat and Y.hat, and on the final causal_forest call. It does not show tuning on the first, simplest causal_forest example, and it does not give a default tuning strategy for every forest type. The reference document linked from the README is where the algorithm is described in detail and where troubleshooting suggestions live, which is a signal that the README is a starting point and not a complete manual. Two limitations are visible from the material itself. First, the honest splitting and variance estimation come with a tree-count cost, as the 4000-tree refit in the example shows; that is compute you have to plan for. Second, the package is an R package with a C++ core, so the interface you write against is R. If your pipeline is Python, the README offers no Python binding here, and you would be calling R from outside or reimplementing. Neither point is a defect, but both shape where GRF fits.

Checking whether the forest found anything: TOC and AUTOC

The README includes a validation step that many users skip, and it is the most useful part of the example. It splits the data, fits a causal forest on the training half, fits another on the evaluation half, and then calls rank_average_treatment_effect on the evaluation forest using predictions from the training forest on the held-out covariates. The result is plotted, and the example prints the AUTOC with a 95 percent interval: paste("AUTOC:", round(rate$estimate, 2), "+/-", round(1.96 * rate$std.err, 2)). This is a test of whether the estimated effects actually rank units usefully, not merely whether the forest converged. If that interval covers zero, the forest has not shown that it can order units by treatment effect, and a targeting rule built from it has no demonstrated basis. The README frames the plot as a way to see if a causal forest succeeded in capturing heterogeneity, which is exactly the question a practitioner should answer before acting on the predictions.

How GRF differs from ranger and from a generic ML stack

The obvious comparison is ranger, which the README credits as the fork origin. Ranger is a fast random forest implementation for prediction and classification; it does not estimate treatment effects and does not provide the honest-splitting machinery or the variance estimates that GRF exposes through estimate.variance. If your task is to predict Y from X, ranger is the simpler tool and GRF's causal machinery is overhead with no payoff. A second comparison is a generic ML stack where you fit a model for Y, a model for W, and take a difference. That approach can produce a number per unit, but it does not give you the honest leaf construction or the built-in interval, and the README's own example shows GRF expecting you to supply W.hat and Y.hat from regression_forest or another method anyway. So GRF is not a replacement for the nuisance models; it is the layer that combines them into an effect estimate with uncertainty. If you want a single call that takes raw X, Y, W and returns intervals, the first causal_forest example is that, but the second example is the honest picture of what a careful analysis looks like.

Maintenance, funding and what to verify before adopting

The repository is not archived, and the last push recorded is 2026-04-30. The README lists funding from the National Institutes of Health, the National Science Foundation, the Sloan Foundation, the Office of Naval Research under Grant N00014-17-1-2131, and Schmidt Futures, and cites Athey and Wager on estimating treatment effects with causal forests and Athey, Tibshirani and Wager on the general method. That is academic backing, which matters for a method whose correctness rests on published statistical results rather than on adoption. It also means the project's direction follows the research. For upgrade cost, the material supports one concrete point: the development version is installed from the r-package/grf subdirectory, so the R package is a subcomponent of the repository rather than the whole tree, and source builds need C++17. Beyond that, the README does not describe a deprecation policy or API stability commitments, so pin a version and read the release notes before moving. Verify on your own data that average_treatment_effect with target.sample = "all" and target.sample = "treated" give intervals you can act on, and that the rank_average_treatment_effect curve separates from the diagonal. Those two checks, not the README examples, decide whether GRF is the right tool for your study.

Editorial conclusion

Adopt GRF if you are estimating heterogeneous treatment effects or other forest-based quantities in R and you need honest splitting and confidence intervals as part of the estimate. Do not adopt it if you want a general purpose random forest for prediction, or if you need a Python-first workflow, since the package is distributed through CRAN and conda-forge as an R package. Before committing, verify two things on your own data: that average_treatment_effect on your target sample returns an interval narrow enough to be useful, and that rank_average_treatment_effect shows a TOC curve that separates from the diagonal. If the AUTOC interval spans zero, the forest has not demonstrated heterogeneity and the causal_forest output should not be read as a targeting rule.

Official sources

  1. grf-labs/grf on GitHub
  2. Issues
  3. License: GPL-3.0
  4. Project website
  5. README
Community notes

Community notes