---
title: "Getting Started with tidylearn"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with tidylearn}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5
)
```

## Introduction

Every machine learning package in R has its own API and its own output
format. tidylearn puts one signature over 20 of them: `tl_model()` picks the
underlying package from the `method` you name, and whatever comes back is a
tibble or a ggplot2 object.

The algorithms are untouched. glmnet, randomForest, xgboost, e1071, cluster
and dbscan do the fitting, and `model$fit` hands you the object they
returned — `model$fit$model` for an unsupervised method, whose `$fit` is
the list of tidied components — so nothing here closes off the package
underneath.

This vignette covers the shape of a workflow end to end. The articles listed
at the bottom go deeper on each step.

## Installation

```{r, eval = FALSE}
# From CRAN
install.packages("tidylearn")

# Development version
# devtools::install_github("ces0491/tidylearn") # nolint
```

```{r setup}
library(tidylearn)
library(dplyr)
```

## The Unified Interface

The core of tidylearn is the `tl_model()` function, which dispatches to the
appropriate underlying package based on the method you specify. The wrapped
packages include stats, glmnet, randomForest, xgboost, gbm, e1071, nnet, rpart,
cluster, and dbscan.

### Supervised Learning

#### Classification

Logistic regression handles two-class problems, so we take a binary subset
of iris here. For three or more classes use `"tree"`, `"forest"`, `"svm"`
or `"nn"`.

```{r}
# versicolor and virginica overlap, so this is a real classification
# problem -- setosa is linearly separable from the other two, which makes
# logistic regression fail to converge
iris_binary <- iris %>%
  filter(Species %in% c("versicolor", "virginica")) %>%
  mutate(Species = droplevels(Species))

model_logistic <- tl_model(iris_binary, Species ~ ., method = "logistic")
print(model_logistic)
```

Predictions come back as a tibble with a `.pred` column. What `.pred`
contains depends on `type`: `"class"` gives the predicted label, `"prob"`
gives one column per class.

```{r}
# Predicted class labels
predictions <- predict(model_logistic, type = "class")
head(predictions)
```

```{r}
# Class probabilities
head(predict(model_logistic, type = "prob"))
```

Note that the default `type = "response"` means different things across
methods — probabilities for logistic regression, class labels for trees and
forests. Ask for `type = "class"` explicitly when you want labels, or let
`tl_evaluate()` handle it:

```{r}
tl_evaluate(model_logistic, metrics = c("accuracy", "f1"))
```

#### Regression

```{r}
# Regression with linear model
model_linear <- tl_model(mtcars, mpg ~ wt + hp, method = "linear")
print(model_linear)
```

```{r}
# Predictions
predictions_reg <- predict(model_linear)
head(predictions_reg)
```

### Unsupervised Learning

#### Dimensionality Reduction

```{r}
# Principal Component Analysis
model_pca <- tl_model(iris[, 1:4], method = "pca")
print(model_pca)
```

```{r}
# Transform data
transformed <- predict(model_pca)
head(transformed)
```

#### Clustering

```{r}
# K-means clustering
model_kmeans <- tl_model(iris[, 1:4], method = "kmeans", k = 3)
print(model_kmeans)
```

```{r}
# Get cluster assignments
clusters <- model_kmeans$fit$clusters
head(clusters)
```

```{r}
# Compare with actual species
table(clusters$cluster, iris$Species)
```

## Data Preprocessing

`tl_prepare_data()` handles imputation, scaling and encoding in one call, and
records what it did so the same transformation can be replayed on new data:

```{r}
# Prepare data with multiple preprocessing steps
processed <- tl_prepare_data(
  iris,
  Species ~ .,
  impute_method = "mean",
  scale_method = "standardize",
  encode_categorical = FALSE
)
```

```{r}
# Check preprocessing steps applied
names(processed$preprocessing_steps)
```

```{r}
# Use processed data for modeling
model_processed <- tl_model(processed$data, Species ~ ., method = "forest")
```

## Train-Test Splitting

```{r}
# Simple random split
split <- tl_split(iris, prop = 0.7, seed = 123)

# Train model (three species, so a multiclass-capable method)
model_train <- tl_model(split$train, Species ~ ., method = "forest")

# Test predictions
predictions_test <- predict(model_train, new_data = split$test)
head(predictions_test)
```

```{r}
# Stratified split (maintains class proportions)
split_strat <- tl_split(iris, prop = 0.7, stratify = "Species", seed = 123)

# Check proportions are maintained
prop.table(table(split_strat$train$Species))
prop.table(table(split_strat$test$Species))
prop.table(table(iris$Species))
```

## Wrapped Packages

tidylearn provides a unified interface to these established R packages:

### Supervised Methods

| Method | Underlying Package | Function Called |
|--------|-------------------|-----------------|
| `"linear"` | stats | `lm()` |
| `"polynomial"` | stats | `lm()` with `poly()` |
| `"logistic"` | stats | `glm(..., family = binomial)` |
| `"ridge"`, `"lasso"`, `"elastic_net"` | glmnet | `glmnet()` |
| `"tree"` | rpart | `rpart()` |
| `"forest"` | randomForest | `randomForest()` |
| `"boost"` | gbm | `gbm()` |
| `"xgboost"` | xgboost | `xgb.train()` |
| `"svm"` | e1071 | `svm()` |
| `"nn"` | nnet | `nnet()` |
| `"deep"` | keras | `keras_model_sequential()` |

### Unsupervised Methods

| Method | Underlying Package | Function Called |
|--------|-------------------|-----------------|
| `"pca"` | stats | `prcomp()` |
| `"mds"` | stats, MASS, smacof | `cmdscale()`, `isoMDS()`, etc. |
| `"kmeans"` | stats | `kmeans()` |
| `"pam"` | cluster | `pam()` |
| `"clara"` | cluster | `clara()` |
| `"hclust"` | stats | `hclust()` |
| `"dbscan"` | dbscan | `dbscan()` |

### Accessing the Underlying Model

The raw model from the underlying package is reachable through `$fit`:

```{r}
# Example: Access the raw randomForest object
model_forest <- tl_model(iris, Species ~ ., method = "forest")
class(model_forest$fit)  # This is the randomForest object

# Use package-specific functions if needed
# randomForest::varImpPlot(model_forest$fit) # nolint
```

An unsupervised method returns tidied components as well, so its `$fit` is
the list holding them and the wrapped object sits at `$fit$model`:

```{r}
model_pca <- tl_model(iris, ~ ., method = "pca")
names(model_pca$fit)
class(model_pca$fit$model)  # This is the prcomp object
```

## The Whole Workflow

Split, fit, predict, score — the four steps this vignette covered, in the
order they run:

```{r}
# Quick example combining everything
data_split <- tl_split(iris, prop = 0.7, stratify = "Species", seed = 42)

# Random forests are scale-invariant, so no scaling is needed here. When a
# method does need scaled inputs, the same transformation has to be applied
# to the test set -- see the Supervised Learning vignette.
model_final <- tl_model(data_split$train, Species ~ ., method = "forest")
test_preds <- predict(model_final, new_data = data_split$test)

accuracy <- mean(test_preds$.pred == data_split$test$Species)
cat("Test accuracy:", round(accuracy * 100, 1), "%\n")
```

## Next Steps

- `vignette("data-ingestion")` — reading from files, databases and cloud
  sources
- `vignette("supervised-learning")` — classification and regression in depth,
  and how to replay preprocessing on a test set
- `vignette("unsupervised-learning")` — clustering, ordination, and choosing
  the number of clusters
- `vignette("market-basket")` — association rules
- `vignette("tuning-and-pipelines")` — hyperparameter search, and bundling a
  workflow you can save
- `vignette("automl")` — searching across methods under a time budget
- `vignette("diagnostics")` — assumptions, influence and model comparison
- `vignette("reporting")` — plots and formatted `gt` tables
- `vignette("integration-workflows")` — combining supervised and unsupervised
  steps
- `vignette("compute-backends")` — when a fit is too slow or too large for
  this machine: GPU routing, cost estimates, and the cloud safety model
