---
title: "Getting Started with Text Classification"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with Text Classification}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

## Overview

Text classification assigns documents to predefined categories. In
organizational research, documents might be vacancy sentences, employee
comments, reports, or interview excerpts. This tutorial develops a transparent
workflow from raw HTML to predictions.

```{r}
library(textclassificationtutorial)
```

## Extract text from HTML

The package includes the nursing-vacancy page used by the original tutorial.

```{r}
html_file <- system.file(
  "extdata", "sample_nursing_vacancy.html",
  package = "textclassificationtutorial"
)
vacancy_text <- extract_html_text(html_file)
substr(vacancy_text, 1, 200)
```

To process a folder, use `extract_html_dir()`. The result keeps a document ID,
the source path, and extracted text together.

```{r, eval = FALSE}
pages <- extract_html_dir("inst/extdata/vacancypages")
```

CSS and XPath selection are available when `xml2` is installed:

```{r, eval = FALSE}
extract_html_text(html_file, selector = "div.content")
extract_html_text(html_file, xpath = "//div[@class='content']")
```

## Segment and normalize

The unit of analysis should follow the research question. Here, each sentence
is treated as one document.

```{r}
sentences <- split_sentences(vacancy_text)
head(sentences)
```

Preprocessing choices are analytical decisions, not housekeeping. Removing
numbers may discard years of experience, and removing stopwords may discard
meaningful negation. Make each choice explicit.

```{r}
german_stopwords <- c(
  "der", "die", "das", "den", "dem", "des", "und", "oder", "mit",
  "für", "von", "zu", "im", "in", "auf", "ein", "eine"
)

clean <- preprocess_text(
  sentences,
  lowercase = TRUE,
  remove_punctuation = TRUE,
  remove_numbers = TRUE,
  stopwords = german_stopwords,
  min_token_length = 2
)
clean <- clean[nzchar(clean)]
head(clean)
```

## Create document features

```{r}
dtm <- document_term_matrix(
  clean,
  min_doc_freq = 2,
  max_doc_prop = 0.95
)
dtm
```

Rows represent documents, columns represent terms, and cells contain counts.
Use `binary = TRUE` when presence is more appropriate than frequency.

TF-IDF increases the weight of terms that are frequent in a particular
document but uncommon across the collection.

```{r}
weighted <- tf_idf(dtm)
keywords <- extract_keywords(dtm, n = 3)
head(keywords, 12)
```

## Explore similarity

Cosine similarity compares the orientation of two feature vectors while
reducing the influence of document length.

```{r}
similarity <- cosine_similarity(weighted)
round(similarity[1:min(5, nrow(similarity)),
                 1:min(5, ncol(similarity))], 2)
```

## Train a classifier

For a compact illustration, use synthetic documents with known labels.

```{r}
training_text <- c(
  "analyze data statistical model",
  "build predictive model data",
  "create dashboard analyze metrics",
  "provide nursing care patient",
  "support patient clinical care",
  "coordinate nurse patient treatment"
)
training_labels <- c("data", "data", "data", "care", "care", "care")

training_dtm <- document_term_matrix(training_text)
model <- fit_naive_bayes(training_dtm, training_labels, laplace = 1)
model

predicted <- predict(model, training_dtm)
classification_metrics(training_labels, predicted, positive = "data")
```

This training-set result demonstrates mechanics, not generalization. The next
vignette shows out-of-sample evaluation.

## Reproducible research checklist

- Preserve IDs and labels through every transformation.
- Define the unit of analysis before tokenization.
- Fit vocabulary and feature transformations on training data only.
- Prevent sentences from the same source document leaking across folds.
- Report preprocessing, class balance, tuning, and all evaluation metrics.
- Inspect errors and subgroup performance, not only aggregate accuracy.
