% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/foutliers.R
\name{f_outliers}
\alias{f_outliers}
\alias{f_outliers.numeric}
\alias{f_outliers.integer}
\alias{f_outliers.formula}
\alias{f_outliers.data.frame}
\title{Identify Outliers within Groups using Tukey's Fences}
\usage{
f_outliers(x, ...)

\method{f_outliers}{numeric}(x, ...)

\method{f_outliers}{integer}(x, ...)

\method{f_outliers}{formula}(formula, data, ...)

\method{f_outliers}{data.frame}(
  x,
  columns,
  group_vars = NULL,
  id_var = NULL,
  coef = 1.5,
  digits = NULL,
  export_to_excel = FALSE,
  close_generated_files = FALSE,
  open_generated_files = interactive(),
  save_as = NULL,
  save_in_wdir = FALSE,
  check_input = TRUE,
  digits_excel = NULL,
  allow_integer_decimal_mix = FALSE,
  ...
)
}
\arguments{
\item{x}{A data.frame or formula (dispatches to the right method).}

\item{...}{Further arguments forwarded to \code{f_outliers.data.frame}.}

\item{formula}{A formula specifying the columns (right hand side) to be checked per subgroup(s) (left hand side).
More columns or groups can be added using \code{-} or \code{+} (e.g., \code{col1 + col2 ~ group1 + group2})
to do a sequential analysis for each column parameter.}

\item{data}{A  \code{vector}, \code{data.frame},  \code{data.table}, or  \code{tibble}.}

\item{columns}{The numerical columns to analyze if no formula is used. Can be entered
as a single character string (e.g., \code{"weight"}) or as a character vector \code{c("weight", "length"}).}

\item{group_vars}{A character vector specifying the grouping variables in \code{data}
If \code{NULL} (default), the entire dataset is treated as one group (e.g., \code{c("species", "fertilizer")}).}

\item{id_var}{(Optional) A character string naming a user-specific ID columns (e.g., \code{"EmployeeID"}).
If provided, this columns is placed at the start of the output for easy identification.}

\item{coef}{A number indicating the IQR multiplier. Default is \code{1.5} (standard Tukey fence).
Common values:
\itemize{
  \item \code{1.5}: Standard outliers (approximately +/- 2.7 SD in normal distribution).
  \item \code{3.0}: Extreme outliers.
}}

\item{digits}{Integer. Number of decimal places for the R console output.
Default is \code{2}. If \code{NULL}, no rounding is applied.
(Note: This does not affect the raw numbers exported to Excel).}

\item{export_to_excel}{Logical. If \code{TRUE}, exports results to an 'Excel' file. Default \code{FALSE}.}

\item{close_generated_files}{Logical. If \code{TRUE}, forces Excel to close before saving (Windows only). Default \code{FALSE}.}

\item{open_generated_files}{Logical. Whether to open the generated output
files after creation. Defaults to \code{TRUE} in an interactive R session
and \code{FALSE} otherwise (e.g. in scripts or automated pipelines).
Set to \code{TRUE} or \code{FALSE} to override this behaviour explicitly.}

\item{save_as}{Character string. Custom path or filename for the Excel export.
\itemize{
  \item If full path: Saves to that location.
  \item If filename only: Saves to \code{tempdir()} (unless \code{save_in_wdir = TRUE}).
  \item If directory: Saves as "dataname_summary.xlsx" in that directory.
}}

\item{save_in_wdir}{Logical. If \code{TRUE}, saves to the current working directory. Default \code{FALSE}.}

\item{check_input}{Logical. If \code{TRUE}, performs validation checks on inputs. Default \code{TRUE}.}

\item{digits_excel}{Integer. Number of decimal places for the Excel file cells. Default \code{NULL} (no rounding). Defining \code{digits_excel}, sets \code{export_to_excel = TRUE} when excel output is not intended use: \code{digits} instead.}

\item{allow_integer_decimal_mix}{Logical. If \code{TRUE}, intergers in columns with a mix of integers and non-integers are displayed without decimals. Default \code{FALSE}, meaning if there are one or more numbers with decimals the whole column contains the number of decimals set by \code{digits}.}
}
\value{
A data.frame containing the identified outlier rows. Returns \code{NULL} (with a message)
  if no outliers are found.
}
\description{
`f_outliers()` scans numerical column(s) for outliers based on the Interquartile Range (IQR) method.
It can detect outliers across the entire dataset or within specified subgroups.

It returns a dataframe containing only the outlier rows, preserving the original data structure
and adding a \code{row_id} column for traceability.
}
\details{
\strong{The Outlier Logic (Tukey's Method):}
An observation is flagged as an outlier if it falls outside the calculated fences:
\itemize{
  \item \strong{Lower Fence:} \eqn{Q1 - (coef \times IQR)}
  \item \strong{Upper Fence:} \eqn{Q3 + (coef \times IQR)}
}
Where \eqn{Q1} is the 25th percentile, \eqn{Q3} is the 75th percentile, and \eqn{IQR = Q3 - Q1}.

\strong{Output Structure:}
The function returns a subset of the original \code{data}. It automatically adds a \code{row_id}
columns, which corresponds to the row number in the original dataframe. This ensures you can
strictly map the outliers back to the source data.
}
\examples{
# --- Setup: Create Dummy Data ---
set.seed(42)
df <- data.frame(
  Team       = rep(c("A", "B"), each = 20),
  Department = rep(c("Sales", "IT"), each = 10, times = 2),
  Salary     = rnorm(40, mean = 50000, sd = 2000),
  Age        = rnorm(40, mean = 35, sd = 3),
  EmployeeID = paste0("E", sprintf("\%03d", 1:40))
)

# Inject outliers
df[2,  "Salary"] <- 57000   # Mild outlier (between 1.5 and 3.0 fence)
df[1,  "Salary"] <- 100000  # Extreme high
df[35, "Salary"] <- 1000    # Extreme low

# --- Example 1: Basic detection (data.frame notation) ---
# Scan the entire dataset for Salary outliers (no grouping)
out <- f_outliers(df, columns = "Salary")
print(out)

# --- Example 2: Basic detection (formula notation) ---
# Equivalent to Example 1 using the formula interface
# LHS = column(s) to scan, RHS = grouping variable(s)
out <- f_outliers(Salary ~ 1, data = df)
print(out)

# --- Example 3: Grouped detection (both notations) ---
# Outliers are now evaluated *within* each Team separately,
# making detection sensitive to group-level distributions

# data.frame notation:
out <- f_outliers(df, columns = "Salary", group_vars = "Team")

# Formula notation (identical result):
out <- f_outliers(Salary ~ Team, data = df)
print(out)

# --- Example 4: Multi-column + multi-group (formula notation) ---
# Scan both Salary and Age for outliers, grouped by Team and Department.
# Returns a named list: one data.frame per column scanned.
out <- f_outliers(Salary + Age ~ Team + Department, data = df)
print(out)            # prints both result tables
out$Salary            # access Salary outliers directly
out$Age               # access Age outliers directly

# --- Example 5: Strict detection with a custom ID column ---
# coef = 3.0 flags only extreme outliers (the "far out" Tukey fence).
# id_var places EmployeeID first in the output for easy identification.

# data.frame notation:
out <- f_outliers(df,
                  columns   = "Salary",
                  group_vars = "Team",
                  id_var    = "EmployeeID",
                  coef      = 3.0)

# Formula notation (identical result):
out <- f_outliers(Salary ~ Team, data = df,
                  id_var = "EmployeeID",
                  coef   = 3.0)
print(out)

# --- Example 6: Sensitivity comparison ---
# Compare how coef = 1.5 (standard) vs coef = 3.0 (extreme-only)
# affects the number of flagged rows.

out_standard <- f_outliers(Salary ~ Team, data = df, coef = 1.5)
out_extreme  <- f_outliers(Salary ~ Team, data = df, coef = 3.0)

nrow(out_standard$output_df)  # 3 -- catches mild + extreme outliers
nrow(out_extreme$output_df)   # 2 -- catches extreme outliers only

# --- Example 7: Vector input ---
# Pass a column directly as a vector -- no data.frame needed.
# The column name is captured automatically from the call.

out <- f_outliers(df$Salary)
print(out)

# Works with coef and other parameters too
out <- f_outliers(df$Salary, coef = 3.0)
print(out)

# Inline vectors fall back to the column name "value"
out <- f_outliers(c(1, 2, 3, 4, 5, 100))
print(out)

}
\seealso{
\code{\link{f_remove_outliers}} to remove the rows identified by this function.
}
