Day 8 of 30·Data Manipulation
Sorting & De-duplication: arrange() & distinct()
PROC SORT — including NODUPKEY and BY-group firsts — the dplyr way.
Learning objectives
- 1Sort with arrange() and desc().
- 2Remove duplicates with distinct().
- 3Reproduce FIRST./LAST. logic with group_by() + slice().
- 4Understand stable sorting behavior.
Key SAS® → R comparison
| Task | SAS® | R |
|---|---|---|
| Sort ascending | proc sort; by age; | arrange(df, age) |
| Sort descending | by descending age; | arrange(df, desc(age)) |
| Remove dups | nodupkey by usubjid; | distinct(df, usubjid, .keep_all=TRUE) |
| First per group | first.usubjid | group_by()+slice(1) |
| Last per group | last.usubjid | group_by()+slice_tail(n=1) |
Code examples
SAS®
proc sort data=vs; by usubjid visitnum; run;
data last; set vs;
by usubjid;
if last.usubjid;
run;R
last <- vs |>
arrange(usubjid, visitnum) |>
group_by(usubjid) |>
slice_tail(n = 1) |>
ungroup()Note: Always ungroup() when done so later operations don't silently run by group.
Explanation
arrange() sorts and is stable, so ties retain their original order. distinct() handles NODUPKEY, optionally keeping all columns with .keep_all = TRUE.
The FIRST./LAST. idiom becomes group_by() plus slice() — explicit, composable, and free of the positional sort dependencies that make DATA-step BY processing error-prone.
Practice exercise
From a VS dataset, keep the last record per subject by visit, and separately produce a de-duplicated subject-level list of USUBJID and ARM.