---
title: "Creating FFTrees"
author: "Nathaniel Phillips"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Creating FFTrees}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---
```{r, echo = F, message = F, results = 'hide'}
library(FFTrees)
```

The `FFTrees()` function is at the heart of the `FFTrees` package. The function takes a training dataset as an argument, and generates several fast and frugal trees which attempt to classify cases into one of two classes based on cues.

## heartdisease example

Let's start with an example, we'll create FFTrees fitted to the `heartdisease` dataset. This dataset contains data from 202 patients suspected of having heart disease. Here's how the dataset looks:

```{r}
head(heartdisease)
```

The critical dependent variable is `diagnosis` which indicates whether a patient has heart disease or not. The other variables in the dataset (e.g.; sex, age, and several biological measurements) will be used as predictors.

Now we'll split the original dataset into a *training* dataset, and a *testing* dataset. We will create the trees with the training set, then test its performance in the test dataset:

```{r}
set.seed(100) # For replication
samples <- sample(c(T, F), size = nrow(heartdisease), replace = T)
heartdisease.train <- heartdisease[samples,]
heartdisease.test <- heartdisease[samples == 0,]
```

We'll create a new FFTrees object called `heart.fft` using the `FFTrees()` function. We'll specify `diagnosis` as the (binary) dependent variable, and include all independent variables with `formula = diagnosis ~ .`:

```{r}
heart.fft <- FFTrees(formula = diagnosis ~.,
                    data = heartdisease.train,
                    data.test = heartdisease.test
                    )
```

## Elements of an FFTrees object

`FFTrees()` returns an object with the FFTrees class. There are many elements in an FFTrees object, here are their names:

```{r}
names(heart.fft)
```


## Printing an FFTrees object

You can view basic information about the FFTrees object by printing its name. This will give you a quick summary of the object, including how many trees it has, which cues the tree(s) use, and how well they performed.

```{r}
heart.fft
```


### Cue accuracy statistics: cue.accuracies

You can obtain marginal cue accuracy statistics from the `cue.accuracies` list. The list contains dataframes with marginal cue accuracies. That is, for each cue, the threshold that maximizes the v-statistic (HR - FAR) in the training dataset is chosen. If the object has test data, you can see the marginal cue accuracies in the test dataset (using the thresholds calculated from the training data):

```{r}
heart.fft$cue.accuracies
```

You can also view the cue accuracies in an ROC-type plot with `showcues()`:

```{r fig.width = 8, fig.height = 8}
showcues(heart.fft, 
         main = "Heartdisease Cue Accuracy")
```


### Tree definitions and accuracy statistics

The `tree.definitions` dataframe contains definitions (cues, classes, exits, thresholds, and directions) of all trees in the object:

```{r}
heart.fft$tree.definitions
```

The `tree.stats` list contains classification statistics for all trees applied to both training `tree.stats$train` and test `tree.stats$test` data:

```{r}
heart.fft$tree.stats$train
```

### decision

The `decision` list contains the raw classification decisions for each tree for each training (and test) case.

Here are is how each tree classified the first five cases in the training data:

```{r}
heart.fft$decision$train[1:5,]
```

### levelout

The `levelout` list contains the levels at which each case was classified for each tree.

Here are the levels at which the first 5 test cases were classified:

```{r}
heart.fft$levelout$test[1:5,]
```

### Predicting new data with predict()

Once you've created an FFTrees object, you can use it to predict new data using `predict()`. This will return a new FFTrees object with the new data used as test data. This will overwrite any existing test data in the FFTrees object but will save all training data. In this example, I'll use the `heart.fft` object to make predictions for cases 1 through 50 in the heartdisease dataset:

```{r}
heart.fft <- predict(heart.fft,
                     data.test = heartdisease[1:50,]
                     )
```

When you look at `heart.fft` now, you'll see that the new test data (with 50 cases) are stored as test data:

```{r}
heart.fft
```


## Visualising trees

Once you've created an FFTrees object using `FFTrees()` you can visualize the tree (and ROC curves) using `plot()`. The following code will visualize the best training tree (tree 2) applied to the test data:

```{r, fig.width = 6, fig.height = 6}
plot(heart.fft,
     main = "Heart Disease",
     decision.names = c("Healthy", "Disease")
     )
```

You can also visualize the individual cue accuracies with the `showcues()` function:

```{r fig.width = 5, fig.height = 5}
showcues(heart.fft)
```

See the vignette on plotting trees [here](FFTrees_plot.html) for more details on visualizing trees.

## Additional arguments

The `FFTrees()` function has several additional arguments than change how trees are built. Note: Not all of these arguments have fully tested yet!

- `train.p`: What percent of the data should be used for training? `train.p = .1` will randomly select 10% of the data for training and leave the remaining 90% for testing. Setting `train.p = 1` will fit the trees to the entire dataset (with no testing).

- `hr.weight`: How much weight should be given to maximizing hits versus avoiding false alarms when building the tree? The default is `hr.weight = .5` which treats both measures equally. However, if your decision problem strongly favors maximizing hits over avoiding false alarms, you may wish to set `hr.weight` to a higher value such as 0.75. When you do, the tree growth algorithm will favor using cues that maximize hits over those that minimize false-alarms.

- `rank.method`: As trees are being built, should cues be selected based on their marginal accuracy (`rank.method = "m"`) applied to the entire dataset, or on their conditional accuracy (`rank.method = "c"`) applied to all cases that have not yet been classified? Each method has potential pros and cons. The marginal method is much faster to implement and may be prone to less over-fitting. However, the conditional method could capture important conditional dependencies between cues that the marginal method misses. Additionally, the `rank.method = "c"` method allows the same cue to be used multiple times in the tree. When a cue has a strong non-monotonic relationship with the criterion, this can greatly improve performance.
