KAHIBARO
Discord Login Register

18.1. Introduction to RDataFrame

Why RDataFrame?

RDataFrame is a high level interface in ROOT that lets you analyze columnar data in a clear, compact, and declarative way. Instead of writing long C++ event loops that manually read branches, apply selections, and fill histograms, you describe what you want to compute and RDataFrame builds and executes the processing pipeline for you.

The central idea is that a TTree or a similar dataset is treated as a table. Each branch is a column, each entry is a row, and you define operations on columns. Typical operations are filtering rows, defining new columns from existing ones, and creating histograms or other statistics from selected columns. RDataFrame takes care of looping over the data efficiently in the background.

You usually create a RDataFrame from a TTree or directly from a ROOT file. Conceptually it looks like this:

cpp
ROOT::RDataFrame df("Events", "data.root");
auto df_selected = df.Filter("energy > 1.0", "Energy cut");
auto df_with_var = df_selected.Define("p2", "px*px + py*py + pz*pz");
auto h_energy = df_selected.Histo1D("energy");
auto h_p2     = df_with_var.Histo1D("p2");

Here you never write an explicit event loop. You describe a chain of operations that starts from a dataset called "Events" in the file "data.root". The expression strings refer directly to branch names or previously defined columns.

RDataFrame is especially useful in analyses where you want to iterate on your selection and definitions many times. The code is shorter and easier to read, so it is simpler to modify cuts, add new variables, and produce new histograms as your analysis evolves.

Another key feature is that RDataFrame can transparently use multiple CPU cores. The same analysis code can run single threaded or multithreaded. When ROOT implicit multithreading is enabled, RDataFrame automatically splits the dataset among threads and merges the results at the end. This is particularly important for large datasets that are typical in particle and nuclear physics.

RDataFrame is not limited to TTrees on disk. You can also use it with chains of trees, with datasets in memory, and with different types of backends. For a beginner working with ROOT, it provides a modern and consistent way to do data analysis that is closer to concepts from data frames in other environments, while still using all the ROOT classes and file formats.

RDataFrame lets you write analysis code without explicit event loops. You describe operations on columns, and RDataFrame handles the looping, filtering, and histogram filling internally, with optional automatic multithreading.

RDataFrame vs traditional TTree loops

Traditional ROOT analysis code is usually written as an explicit event loop over a TTree. In that style, you open a file, get a TTree, set branch addresses, then write a for loop that calls GetEntry for each event, applies if statements for cuts, and fills histograms manually.

Conceptually, a simple traditional loop looks like this:

cpp
TFile *f = TFile::Open("data.root");
TTree *t = (TTree*)f->Get("Events");
float energy;
t->SetBranchAddress("energy", &energy);
TH1F h("h_energy", "Energy", 100, 0, 10);
Long64_t nEntries = t->GetEntries();
for (Long64_t i = 0; i < nEntries; ++i) {
    t->GetEntry(i);
    if (energy > 1.0) {
        h.Fill(energy);
    }
}

The same operation with RDataFrame is much more compact:

cpp
ROOT::RDataFrame df("Events", "data.root");
auto h_energy = df.Filter("energy > 1.0").Histo1D("energy");

In both cases you open the same file, use the same branch, and fill a histogram with the same selection. The difference is in how you express the analysis.

Traditional TTree loops are imperative. You tell the computer step by step how to do the work: get this entry, read these branches, check this condition, then fill that histogram. You are responsible for all control flow.

RDataFrame is declarative. You describe what operations should be performed on columns: filter by this condition, define this new quantity, then build this histogram. The control flow is hidden, and RDataFrame decides how to process the data efficiently.

This difference has several practical consequences. RDataFrame code is typically shorter and easier to read. You can modify cuts and definitions in a single place without changing a long loop. The analysis steps are captured as a chain of transformations on a dataset, which matches how physicists often think about analysis: starting with raw events, applying selections, computing derived quantities, and finally producing results.

Another important difference is how RDataFrame handles performance and scheduling. In a traditional loop, you must manually enable multithreading, manage thread safe objects, and control how entries are distributed. With RDataFrame, multithreading is built in. Once ROOT implicit multithreading is enabled, the same RDataFrame script can run on multiple cores. The framework splits the dataset into ranges, processes them in parallel, and combines results at the end.

Traditional loops also tend to spread analysis logic across many lines of code. Selection cuts, variable definitions, and histogram filling can be interleaved with technical details such as branch address setup. With RDataFrame, selections and definitions are tied directly to the dataset in a linear chain of calls. This helps keep analysis and technical details better separated.

Despite these advantages, RDataFrame does not replace all uses of traditional loops. If you need very custom control over entry access, complex state machines across events, or highly optimized specialized code, a manual loop can still be useful. RDataFrame is designed for common analysis workflows where you operate on events independently, which covers most physics analyses at the level of histograms and derived quantities.

When comparing both styles, remember that the underlying data structures are the same. RDataFrame still reads TTrees and uses ROOT I/O. The difference is the programming model. As you progress in this course, you will see that many of the tasks that would require explicit branches, loops, and histogram management can be expressed more clearly with RDataFrame, while still allowing you to use all your existing knowledge of ROOT classes and C++.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!