# RANDOMNESS CONTROL AND REPRODUCIBILITY STUDY OF RANDOM FOREST ALGORITHM IN R AND Python

Louisa Camadini, Yanis Bouzid, Maeva Merlet, Léopold Carron

► To cite this version:

Louisa Camadini, Yanis Bouzid, Maeva Merlet, Léopold Carron. RANDOMNESS CONTROL AND REPRODUCIBILITY STUDY OF RANDOM FOREST ALGORITHM IN R AND Python. 2024. [https://hal.science/hal-04666905v1](https://hal.science/hal-04666905v1)

HAL Id: hal-04666905

[https://hal.science/hal-04666905v1](https://hal.science/hal-04666905v1)

Preprint submitted on 21 Aug 2024

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
RANDOMNESS CONTROL AND REPRODUCIBILITY STUDY OF
RANDOM FOREST ALGORITHM IN R AND PYTHON

Louisa Camadini

l.camadini@itm-stats.com

Yanis Bouzid

Maeva Merlet

m.merlet@itm-stats.com

Léopold Carron

leopold.carron@loreal.com

August 2, 2024

ABSTRACT

When it comes to the safety of cosmetic products, compliance with regulatory standards is crucial to guarantee consumer protection against the risks of skin irritation. Toxicologists must therefore be fully conversant with all risks. This applies not only to their day-to-day work, but also to all the algorithms they integrate into their routines. Recognizing this, ensuring the reproducibility of algorithms becomes one of the most crucial aspects to address.

However, how can we prove the robustness of an algorithm such as the random forest, that relies heavily on randomness? In this report, we will discuss the strategy of integrating random forest into ocular tolerance assessment for toxicologists.

We will compare four packages: randomForest and Ranger (R packages), adapted in Python via the SKRanger package, and the widely used Scikit-Learn with the `RandomForestClassifier()` function. Our goal is to investigate the parameters and sources of randomness affecting the outcomes of Random Forest algorithms.

By setting comparable parameters and using the same Pseudo-Random Number Generator (PRNG), we expect to reproduce results consistently across the various available implementations of the random forest algorithm. Nevertheless, this exploration will unveil hidden layers of randomness and guide our understanding of the critical parameters necessary to ensure reproducibility across all four implementations of the random forest algorithm.

# 1 Introduction

The role of cosmetics toxicological evaluation is to guarantee the safety of consumer products. This involves substantial investments in time and financial resources for product evaluation. To reduce these investments, machine learning is one of the keys to help toxicologists in decision-making. Over recent years, several models have been developed to compute risk assessment metrics.

In a safety context, machine learning is actively used to develop predictive models that can replace animal testing. Various methods have been developed over the past four decades to address increasingly complex needs such as general systemic toxicology or skin sensitization, as mentioned in Burbank, Gautier, and Hewitt 2023 and retrieved from EU. (2009) *Regulation (EC) No 1223/2009 of the European Parliament and of the Council of 30 November 2009 on cosmetic products*. N.d. and EU. (2010) *Directive 2010/63/EU of the European Parliament and of the Council of 22 September 2010 on the protection of animals used for scientific purposes (Text with EEA relevance)*. n.d.

To ensure that a new tool can be integrated into risk assessment strategy, the first and crucial step is the adoption by the community. Given the significant responsibility inherent in every cosmetic product safety report submitted to health authorities, this adoption process necessitates thorough testing of any new model that may be developed. If any doubts
regarding the reproducibility of the algorithm’s implementation arise, a toxicologist may request an evaluation of its impact on risk assessment.

Upon initial observation, the use of random forests may seem unsettling. As of now, there is a lack of evidence regarding the reproducibility of this method across the most popular programming languages – such as R and Python – despite widespread discussions on performance comparisons as exemplified in Marchese Robinson et al. 2017. To bridge this gap, our study aims to compare four random forest packages in R and Python, thereby assessing the reproducibility of their outcomes.

The article will begin with a brief section on random forests, as understanding how they work is essential for revealing sources of randomness. This will be followed by a review of existing packages, then the methods for deciphering the differences between them and the associated results. At the end of the article, a clear procedure will enable us to achieve perfect reproducibility between the studied packages.

## 2 Random forest algorithm

The random forest algorithm combines the concepts of CART (Classification and Regression Trees) and bagging (bootstrap aggregation), whose concepts are fully detailed in Biau and Scornet 2015.

Bagging uses the bootstrap method to train decision trees on different samples of the dataset, then aggregates their predictions to make a final decision. This approach improves model stability and robustness by reducing variance and over-fitting. However, it adds an extra layer of randomness to the construction of each tree, making model reproducibility challenging.

In addition, the random forest introduces randomness by selecting only a subset of candidate features (m candidates among the total number of features available p) at each node split, instead of considering all features. This random selection helps decorrelate the individual trees, making them more diverse and less prone to overfitting. This split is typically determined using a criterion, such as the Gini index to minimize:

$$Gini = 1 - \sum_{i=1}^{c} p_i^2 \qquad (1)$$

c is the number of classes in the classification problem and each $p_i$ represents the proportion of samples that belong to class i (see Daniya, Geetha, and Kumar 2020).

Then the algorithm constructs a forest of decision trees, where each tree is trained on a bootstrap data sample and selects the best split among a random subset of features at each node. By averaging the predictions of multiple trees, random forests provide robust and accurate predictions. If necessary, Fig. ?? in appendix provides a clear summary of this approach.

Algorithm 1 describes how random forests work:

**Algorithm 1: Random forest**

**Input:** x observation to predict

**Input:** $D_{n \times p}$ data

**Input:** $m \in \mathbb{N}$ number of candidate variables for node splitting

**Input:** B number of trees in the forest

**for** k ← 1 **to** B **do**

1. Draw $\theta_k$ a bootstrap sample in $D_{n \times p}$;

2. Build a tree on $\theta_k$;

Each split is selected by minimizing the Gini impurity on a set of m variables randomly drawn from the p;

This tree is denoted $h(., \theta_k)$;

**Output:** $h(x) = \frac{1}{B} \sum_{k=1}^{B} h(x, \theta_k)$

To summarize, up to now we have identified two main sources of randomness in the random forest algorithm, making model reproducibility challenging:

1. Bootstrap sampling: involves randomly sampling observations from the dataset.
<table><caption>Table 1: Main parameters of the random forest functions in the four packages (purpose discussed in 5.3.3)</caption><thead><tr><th>Purpose</th><th>Scikit-Learn</th><th>SKRanger</th><th>Ranger</th><th>randomForest</th></tr></thead><tbody><tr><td>Number of trees in the forest</td><td>n_estimators</td><td>n_estimators</td><td>num.trees</td><td>ntree</td></tr><tr><td>Min node size to split at</td><td>min_sample Split</td><td>min_node_size</td><td>min.node.size</td><td>nodesize</td></tr><tr><td>Min size of leaf node</td><td>min_sample_Leaf</td><td>max_depth</td><td>max depth</td><td>nodesize</td></tr><tr><td>Max depth of the tree</td><td>max_depth</td><td>max_depth</td><td>max depth</td><td>nodesize</td></tr><tr><td>Number of features to (randomly) consider when splitting on nodes</td><td>max_features</td><td>mtry</td><td>mtry</td><td>mtry</td></tr><tr><td>Bootstrap (sample with replacement)</td><td>bootstrap</td><td>replace</td><td>replace</td><td>replace</td></tr><tr><td>Size of sample to draw</td><td>max_sample</td><td>sample_fra</td><td>sample.fraction</td><td>sampsize</td></tr><tr><td>Splitting rule</td><td>criterion</td><td>split_rule</td><td>split.rule</td><td></td></tr></tbody></table>

2. Random selection of features: at each node split, the algorithm randomly selects a subset of *m* candidates features to consider when looking for the best split.

## 3 Existing Packages

We are going to study the characteristics of four packages implementing the random forest algorithm, two from R and two from Python, then compare them.

The reproducibility of random forest models represents a significant challenge due to the variations between different implementations in R and Python. This discrepancy can be attributed to differences in the algorithms, randomization processes and optimization techniques used by the different software packages. Addressing this issue is essential to ensure the reliability and applicability of random forest models in the context of studies requiring compliance validations.

### R packages

* **randomForest**: a standard R package that provides an implementation of the random forest algorithm, written in C and Fortran.

Version: 4.7.1.1, function: "randomForest()"

* **Ranger**: an R package written in C++, providing a faster implementation.

Version: 0.12.1, function: "ranger()"

### Python packages

* **SKRanger**: a Python compatible version of the Ranger R package, offering a Scikit-Learn interface and built on top of the Ranger library, which is written in Python/Cython and C++. Ranger and SKRanger share the same C++ code, the difference being in the way it is called.

Version: 0.8.0, function: "RangerForestClassifier()"

* **Scikit-Learn**: a package primarily written in Python with some parts optimized using Cython.

Version: 1.1.2, function: "RangerForestClassifier()"

**Parameter comparison** Table 1 summarizes the comparable function parameters of these packages and their purpose. Parameters in black are classified according to the documentation (*SKlearn RandomForestClassifier documentation* n.d., *SKranger RandomForestClassifier documentation* n.d., *Ranger R documentation* n.d. and *RandomForest R documentation* n.d.), but *nodesize*’s action is questioned in 5.3.3, leading to the blue correction.

## 4 Methods

To establish the common features and differences between Scikit-Learn, SKRanger, Ranger, and randomForest, we will implement a random forest model using each package and compare the outputs of the four models.

SKRanger and Ranger share the same underlying C++ code but interact with it differently. SKRanger utilizes Cython for C++ function calls instead of R’s. As they both rely on the same Pseudo-Random Number Generator (PRNG), with a fixed random seed their outputs should be identical.
However, to ensure consistency in our experiments, we employed the *rpy2* package, enabling the execution of R code directly within a Python environment and facilitating comparisons. It is noteworthy that *rpy2* utilizes the R kernel installed on the machine, meaning that R-based code executed through *rpy2* will utilize R's random number generator rather than Python's.

## Data

Based on over a century of knowledge in cosmetics, L'Oréal has a huge history in assessing the risk of his product for local tolerance. To avoid any hazard to the consumer without using animal tests (which are not allowed since 2013), we have a wide variety of in vitro tests, giving each product an associated irritation score.

Among this palette of in vitro tests, there is a method for assessing ocular irritation, which returns the irritation class of a formula. In this test, each formula is classified as *non-irritant* (encoded 0), *moderately irritant* (1) or *severely irritant* (2).

We consider a dataset containing *N* = 4598 rows corresponding to different formulas (tested product). A formula is the sum of ingredient concentrations, with each of the *p* = 87 columns corresponding to a single ingredient contributing to the composition. The values indicate the percentage concentration in the formula, meaning that the sum of each row equals 100.

The random forest procedure is used to predict the irritation class from the dataset. First, this dataset is split into training and testing sets, following the common practice of allocating 80% of the dataset to the training set and reserving the remaining 20% for testing, using the `train_test_split()` Python function. Results will be displayed on this test dataset, composed of 920 rows corresponding to formulas and 87 columns which are the ingredients. Train and test datasets are now fixed for the rest of the testing process.

## 4.1 First implementation

For this first random forest implementation, we leave the default values of parameters to all four packages and run the random forest on 5000 trees. To do so, only the parameters in Table 2 are fixed.

All other parameters are not specified meaning that default values apply, which may vary between packages. This results (in 5.1) will serve as a basis for comparing metrics and highlighting the need to control the randomness of algorithms, in addition to parameters.

## 4.2 Eliminating sources of randomness

As mentioned in 2, randomness is introduced at two stages in the model: if using bootstrap sampling, and at each node split when we randomly draw *m* candidate variables from the *p* variables in our data. For the four packages, these phenomena can be controlled by setting model parameters as in Table 3.

In this test, we will not perform bagging. Instead, models are trained on the entire train set defined beforehand, thus limiting the randomness of data allocation. All *p* = 87 variables are considered at each node division (meaning all available variables).

**Note:** Only one tree is needed, because considering all variables when dividing each node, and not doing bootstrap sampling would mean making the same decision tree every time.

<table><caption>Table 2: Parameters set to be identical between packages (others take their default values)</caption><thead><tr><td>Scikit-Learn</td><td>SKRanger</td><td>Ranger</td><td>randomForest</td><td>Value</td></tr></thead><tbody><tr><td>n_estimators</td><td>n_estimators</td><td>num.trees</td><td>ntree</td><td>5000</td></tr></tbody></table>
# 5 Results

All four models were pre-trained on the dedicated data, as explained above. This section presents the results of models' predictions on the previously defined test dataset.

## 5.1 First implementation

Table 4 shows the number of divergent classifications between each package on the test set, containing 920 observations (formulas).

These results and the similarities in the source code allow us to conjecture that the algorithm implementations of the randomForest, Scikit Learn and Ranger packages are broadly similar. However, discrepancies are observed in the outputs obtained with SKRanger. The reasons are not obvious, and the aim is to clarify them in order to achieve perfect reproducibility between packages.

## 5.2 Eliminating sources of randomness

In this test, no bootstrap is performed, and all variables are considered when searching for the best division. Table 5 presents the number of divergent classifications.

Variations in classification remain between the four models. To better understand them, next section (5.3) is intended to analyse the trees returned by the models. In theory, only one tree is required in this context.

## 5.3 Analysis of generated trees

In the following, we will impose a strict limit of 5 on the depth of trees, to ensure clear graphical representation. However, all observations concerning these trees have also been validated using trees without depth restrictions. Except for the depth, trees are generated as in 5.2 where sources of randomness are eliminated. Four fundamental results emerge from the tree-by-tree analysis and are presented in the following subsections.

### 5.3.1 1st finding: Randomness in splitting variables drawing

For the packages randomForest, Scikit-Learn and Ranger, generated trees are almost identical, but there are a few nodes for which the splitting variables are not. Indeed, by running the codes of these three packages several times, some splitting variables change. This is not the case for SKRanger, which uses a random seed set at 42 by default.

However, utilizing the Scikit-Learn package, which records tree details, we observe that while the splitting variables of specific nodes vary across executions, the Gini criterion of the node remains the same.

This phenomenon is simply due to the random drawing of variables: although all variables are candidates in a node cut, they are drawn in random order. Thus, even if an equivalent cut is possible, it could be ignored, as a cut variable is only chosen if it strictly reduces the impurity criterion.

So, tree analysis reveals another source of randomness: for equal impurity criteria, the choice of variable splitting is random. Finally, by using the value of the Gini impurity criterion to compare the trees, the ones generated by the Scikit-Learn, randomForest and Ranger packages are identical.

<table><caption>Table 3: Parameters set to manage randomness (others take their default values)</caption><thead><tr><th>Scikit-Learn</th><th>SKRanger</th><th>Ranger</th><th>randomForest</th><th>Value</th></tr></thead><tbody><tr><td>n_estimators</td><td>n_estimators</td><td>num.trees</td><td>ntree</td><td>1</td></tr><tr><td>max_features</td><td>mtry</td><td>mtry</td><td>mtry</td><td>87 (all)</td></tr><tr><td>bootstrap</td><td>replace</td><td>replace</td><td>replace</td><td>False</td></tr><tr><td>max_sample</td><td>sample_fra</td><td>sample.fraction</td><td>sampsize</td><td>1 (none)</td></tr></tbody></table>
### 5.3.2 2<sup>nd</sup> finding: min_node_size, a key parameter to set to ensure reproducibility with SKRanger

The tree generated by SKRanger has terminal node higher than the three other packages. Both Ranger and SKRanger use Ranger's C++ code to build the trees, and with identical PRNG, the outputs should be perfectly similar.

With SKRanger, if a node contains less than 10 observations, it is not split. Research revealed that this was due to an unexpected overwrite of the *min_node_size* default value (not fixed in 3), which is the minimum number of observations required in a node before it can be split. Even though both R and Python packages rely on the same underlying C++ library, apparently, they can independently adjust default parameter values. This flexibility leads to variations in the default *min_node_size* parameter between implementations (set to 10 by SKRanger, 1 by others), resulting in discrepancies in output trees.

To ensure efficient reproducibility between R and Python, it is advisable to set *min_node_size* to 1. Doing this, the trees generated by the four studied packages are now identical.

### 5.3.3 3<sup>rd</sup> finding: Parameter nodesize (randomForest) corresponds to the minimum node size to split at

To ensure the robustness of the results, we systematically varied the model parameters, leading to another crucial discovery.

According to the Scikit-Learn and randomForest packages documentation, the *minSamplesLeaf* and *nodesize* parameters are defined as the "minimum size of leaf node": a split point at any depth will only be considered if it leaves at least the number of samples in each of the left and right branches.

We have then compared the trees obtained by varying the parameters *nodesize* of randomForest (Fig. 1), as well as *minSamplesLeaf* and *minSamplesSplit* of Scikit-Learn (Fig. 2), with the reproducibility procedures explained so far (5.2 and 5.3.2).

Clearly, *nodesize* acts as a *minSamplesSplit*, contradicting what is found in the documentation. Considering this, it is now possible to obtain similar trees for all four studied packages.

### 5.3.4 4<sup>rd</sup> finding: Differences in aggregation methods (Ranger, SKRanger)

Preceding steps make it possible to obtain identical trees by generating just one. This time, the aim is to extend the tree's reproducibility to the whole forest and compare the irritation score classifications on the test dataset containing 920 rows.

Nevertheless, when implementing random forests with both SKRanger and Ranger to predict the irritation class of the formulas – taking care to set the parameters just as before – this leads to 897/920 equal classifications.

<table><caption>Table 4: Number of divergent classifications between packages (5.1)</caption><thead><tr><th></th><th>SKRanger</th><th>Ranger</th><th>randomForest</th></tr></thead><tbody><tr><th>Scikit-Learn</th><td>20</td><td>5</td><td>6</td></tr><tr><th>SKRanger</th><td></td><td>19</td><td>20</td></tr><tr><th>Ranger</th><td></td><td></td><td>1</td></tr></tbody></table>
<figure><img src="image_2.png" /><figcaption>Figure 1: Package randomForest, nodesize = 1000
Leaf nodes do not respect the minimum sample size set at 1000 by nodesize.</figcaption></figure>

It turned out that SKRanger employs a different approach than Ranger: SKRanger does not rely on majority class voting mechanism to derive final predictions. Instead, it relies on predicting probabilities for each class through the predict() function. These probabilities represent the averaged values obtained by aggregating probabilities assigned to each class across all individual trees. In contrast, the majority class voting involves each tree voting for a class, with the class receiving the most votes being chosen as the final prediction. Classifications may vary slightly between these two approaches, as discussed in greater detail in Breiman 2001.

To match the predictions of both forests, it is possible to manually select the class associated with the highest probability for each Ranger prediction. When doing this, reproducibility is finally achieved by obtaining 920/920 consistent classifications.

It is worth noting that SKRanger (v0.8.0) uses Ranger (v0.12.1) code, suggesting possible implementation differences in newer Ranger versions (v0.15.1).

# 6 Discussion

The thorough analysis conducted confirmed the ability to generate identical decision trees across various implementations. However, locking in hyperparameters for reproducibility might not always be necessary in practical applications. Reproducibility is primarily a regulatory requirement, ensuring methodological integrity from input to output.

<table><caption>Table 5: Number of divergent classifications between packages (5.2)</caption><thead><tr><th></th><th>SKRanger</th><th>Ranger</th><th>randomForest</th></tr></thead><tbody><tr><th>Scikit-Learn</th><td>7</td><td>8</td><td>7</td></tr><tr><th>SKRanger</th><td></td><td>3</td><td>0</td></tr><tr><th>Ranger</th><td></td><td></td><td>3</td></tr></tbody></table>
<figure><img src="image_3.png" /><figcaption>Figure 2: Package Scikit-Learn, `minSamplesLeaf` = 1000</figcaption></figure>

An example of how the `nodesize` parameter should work, in theory equivalent to `minSamplesLeaf`: leaf nodes both contain more than 1000 samples.

Nevertheless, when setting `minSamplesSplit` = 1000, Scikit-Learn returns the same tree than in Fig. 1.

Although our approach is based on several tests on a single tree, all observations can be extended to a forest. While this starting point may not represent the most optimized implementation, the aim was to highlight the divergences between the four packages in a comprehensive way.

Similarly, some demonstrations have been made with a limited tree depth, in order to better understand the side effects that can modify the result between the two languages. As the difference in reproducibility can be observed at different depths, this choice does not affect our overall observation.

Therefore, we deliberately chose this comprehensive testing methodology to ensure the robustness and reliability of our analyses.

In this article, we have delved into the R and Python implementations of random forests, and should emphasize two points. First, only R and Python packages are studied, whereas most articles comparing random forest performance usually include a third programming language. This choice stems from the fact that these are the two most widely used languages in data science.

Second, we demonstrate how an internal effect of randomness can affect the overall robustness of an algorithm. Dealing with the reproducibility and robustness of randomness is a common problem in computer science, widely discussed in L'Ecuyer 2006.

Despite the subtle differences we have found, they will have no impact on the use that most users have of random forests. This analysis focuses on reproducibility between several implementations and not on the internal reproducibility of a code, which can be dealt with by conventional guidelines Peng 2011.

From a broad perspective, it is clear that this small effect of variability will not be detected by a classical optimization of the model hyperparameter, and that most of the community has no need to evaluate the safety of their algorithm. With this analysis, our confidence in random forests is guaranteed for use in safety regulation, which was the objective of our research.

# 7 Conclusions

In conclusion, achieving perfect reproducibility between Scikit-Learn, SKRanger, Ranger and randomForest packages involves several key steps.

Firstly, common elements such as the random seed generator and environment parameters need to be standardized.

Additionally, parameters with differing default values, such as the number of trees, should be set uniformly. Furthermore, meticulous adjustments are necessary to manage sources of randomness. This includes implementing models without bootstrapping and avoiding random variable selection during the search for the best split. Ensuring a consistent approach to sampling training and testing data is also essential.
Studying consistency at the individual level has revealed some crucial mechanisms. The choice of the splitting variable is random with equal impurity criterion, so based on the Gini criterion it is possible to obtain identical trees in all packages when taking special care to set *min_node_size* to 1 in SKRanger.

Furthermore, the *nodesize* randomForest parameter does not act as in the documentation, but as the minimum node size to split at.

Finally, the reproducibility of the entire forest is studied, by evaluating the number of matching classifications. This highlighted the differences between aggregation methods, providing further insights on why overall classifications may still slightly vary between packages.

## Acknowledgments

The authors would like to thank L'Oréal for enabling us to carry out this research. Special thanks to Marie Thomas, Caroline Rouas, Elise Warcoin and Sophie Loisel Joubert for paving the way for this project. Another important person to mention is Luc Souverain for encouraging us to publish this article.

## Author contribution

Y.B produced all the analyses, Le.C lead the project, Lo.C, Le.C and M.M wrote the paper.

## References

* Biau, G. and E. Scornet (2015). "A Random Forest Guided Tour". In: *arXiv.org*. URL: https://arxiv.org/abs/1511.05741.

* Breiman, L. (2001). "Random forests". In: *Machine learning* 45.1, pp. 5–32. URL: https://link.springer.com/article/10.1023/A:1010933404324.

* Burbank, M., F. Gautier, and N. Hewitt (2023). "Advancing the use of new approach methodologies for assessing teratogenicity: Building a tiered approach". In: *Science Direct* 120. URL: https://doi.org/10.1016/j.reprotox.2023.108454.

* Daniya, T., M. Geetha, and K. S. Kumar (2020). "Classification and regression trees with gini index". In: *Advances in Mathematics: Scientific Journal* 9.10, pp. 8237–8247.

* EU. (2009) *Regulation (EC) No 1223/2009 of the European Parliament and of the Council of 30 November 2009 on cosmetic products*. (N.d.). URL: https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32009R1223 (visited on 06/18/2024).

* EU. (2010) *Directive 2010/63/EU of the European Parliament and of the Council of 22 September 2010 on the protection of animals used for scientific purposes (Text with EEA relevance)*. (n.d.). URL: https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:32017R0735&qid=1718716041218 (visited on 06/18/2024).

* L'Ecuyer, P. (2006). "Uniform random number generation". In: *Generation*. URL: https://www.academia.edu/20779319/Uniform_random_number_generation.

* Marchese Robinson, R. L. et al. (2017). "Comparison of the predictive performance and interpretability of random forest and linear models on benchmark data sets". In: *Journal of chemical information and modeling* 57.8, pp. 1773–1792.

* Peng, R. D. (2011). "Reproducible research in computational science". In: *Science* 334.6060, pp. 1226–1227. URL: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3383002/.

* **RandomForest R documentation** (n.d.). URL: https://www.r documentation.org/packages/randomForest/versions/4.7-1.1/topics/randomForest (visited on 04/15/2024).

* **Ranger R documentation** (n.d.). URL: https://www.r documentation.org/packages/ranger/versions/0.16.0/topics/ranger (visited on 04/15/2024).

* **SKlearn RandomForestClassifier documentation** (n.d.). URL: https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html (visited on 04/15/2024).

* **SKranger RandomForestClassifier documentation** (n.d.). URL: https://skranger.readthedocs.io/en/stable/ranger_forest Classfier.html (visited on 04/15/2024).