unique()
unique(x, incomparables = FALSE, MARGIN = 1, fromLast = FALSE, ...) unique() returns a vector, data frame, or array with duplicate elements removed. This function is fundamental for data cleaning and analysis.
Syntax
unique(x, incomparables = FALSE, MARGIN = 1, fromLast = FALSE, ...)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
x | vector/data.frame/array | , | Input object to process |
incomparables | vector | FALSE | Values to treat as incomparable |
MARGIN | integer | 1 | For arrays: 1 for rows, 2 for columns |
fromLast | logical | FALSE | If TRUE, count from last occurrence |
... | arguments | , | Additional arguments passed to methods |
Examples
Basic usage with vectors
x <- c(1, 2, 2, 3, 3, 3, 4)
unique(x)
# [1] 1 2 3 4
unique() works identically on character vectors as it does on numeric ones — it scans the input, remembers which strings it has already seen, and discards repeats. This is especially useful for cleaning categorical data before analysis: you can extract the distinct levels present in a messy column, get the set of unique participant IDs from a repeated-measures dataset, or identify the distinct error messages logged during a batch job.
Working with character vectors
names <- c("Alice", "Bob", "Charlie", "Alice", "Diana", "Bob")
unique(names)
# [1] "Alice" "Bob" "Charlie" "Diana"
The function is not limited to atomic vectors. When you pass a data frame to unique(), it compares entire rows — a row is considered a duplicate only if all its column values match those of an earlier row. This row-wise deduplication is equivalent to dplyr::distinct() and is the simplest way to remove exact duplicate records from a dataset without writing explicit comparison logic.
With data frames
df <- data.frame(
id = c(1, 2, 2, 3, 4, 1),
name = c("A", "B", "B", "C", "D", "A")
)
unique(df)
# id name
# 1 1 A
# 2 2 B
# 3 3 C
# 4 4 D
The fromLast argument controls which occurrence is retained when duplicates exist. By default (fromLast = FALSE), the first occurrence is kept and later duplicates are dropped. Setting fromLast = TRUE reverses this — the last occurrence of each value survives. This matters when row ordering carries meaning, for example when you want to keep the most recent entry for each ID in a time-ordered log.
Using fromLast argument
x <- c(1, 2, 2, 3)
unique(x, fromLast = TRUE)
# [1] 1 2 3
Common patterns
In data-cleaning pipelines, removing duplicate rows is frequently the first step after loading. Calling unique(df) strips exact duplicates from the entire data frame in one line. If you prefer the tidyverse, dplyr::distinct(df) achieves the same result. Both compare all columns, so to deduplicate by a subset pass a column selection — for instance unique(df[, c("id", "date")]) — to limit the comparison scope.
Remove duplicates from data frame
df_unique <- unique(df)
library(dplyr)
df_unique <- distinct(df)
Beyond full-row deduplication, unique() is often used to enumerate the distinct combinations of two or more variables. By selecting specific columns and passing them to unique(), you get back a data frame where each row represents one observed pairing. This is useful for creating lookup tables, identifying all possible pairings of categorical variables in a dataset, or building a design matrix with only the factor levels that actually occur.
Find unique combinations
unique(interactions[, c("user_id", "item_id")])
unique() in practice
unique() removes duplicate values and returns a vector of the distinct elements in the order they first appear. unique(c(3,1,2,1,3)) returns c(3,1,2), the first occurrence of each value, preserving original order. This order-preserving behavior distinguishes it from sort(unique(x)), which returns sorted distinct values.
For data frames, unique(df) removes duplicate rows based on all columns. This is equivalent to dplyr::distinct(df). unique(df[, c("col1", "col2")]) deduplicates based on a subset of columns.
length(unique(x)) counts the number of distinct values — a common operation for checking cardinality before deciding whether to encode as a factor. dplyr::n_distinct(x) is the tidyverse equivalent, with slightly better handling of NA (it counts NA as a distinct value by default, while unique() includes NA in the output).
duplicated() and unique() are complementary: unique(x) is equivalent to x[!duplicated(x)] for atomic vectors. Use unique() when you want the distinct values; use duplicated() when you need to know which positions are duplicates.
unique() preserves the first occurrence of each value, discarding subsequent duplicates. The order of results mirrors the order of first appearances in the input — elements are not sorted. For sorted unique values, use sort(unique(x)). On a data frame, unique() removes duplicate rows (comparing all columns). duplicated() gives the complementary logical vector marking which elements are duplicates of an earlier occurrence.
Performance and alternatives
unique() preserves the order of first occurrence. The first time a value appears, it is included in the result; subsequent occurrences are dropped. This preserves the relative order of elements from the original vector. For sorted unique values, wrap with sort() after calling unique().
For checking whether a vector has any duplicates without extracting the unique values, anyDuplicated() is faster than length(unique(x)) < length(x). It stops at the first duplicate it finds rather than finding all unique values. For large vectors where you only need to know if duplicates exist, anyDuplicated() avoids the overhead of computing the full set of unique values. The duplicated() function returns a logical vector indicating which elements are duplicates of earlier elements, which is useful for filtering rather than just counting.
Counting distinct combinations in grouped data
# Count distinct values per group using unique() and table()
sales <- data.frame(
region = c("East", "East", "East", "West", "West", "West", "West"),
product = c("A", "B", "A", "A", "B", "B", "C")
)
# Distinct product-region combinations
unique(sales)
# region product
# 1 East A
# 2 East B
# 4 West A
# 5 West B
# 7 West C
# Count distinct products per region
table(unique(sales)$region)
# East West
# 2 3
When you need to know how many unique categories appear within each group, unique() combined with table() gives you the answer without writing a loop. The first call strips duplicate rows from the data frame, and the second call counts how many distinct rows belong to each region. For larger datasets where you need per-group distinct counts directly, dplyr::n_distinct() handles the grouped counting in one step with sales |> group_by(region) |> summarise(n = n_distinct(product)).
See also
- duplicated()
- match()Internally,
unique()uses a hash table for O(n) average complexity. For very large vectors where only the first occurrence is needed,!duplicated(x)returns the logical index faster than callingunique()when the goal is subsetting. For sorted input,unique()uses a sequential scan that is cache-friendly. Thevctrs::vec_unique()function is a faster alternative for vctrs-compatible types, particularly for list vectors and record types.