feat: add factor_level_method, factor_as_factor, factor_level_last_pattern to df_explicit_na#1487
Conversation
…ttern to df_explicit_na - factor_level_method: controls level ordering (sort_auto/sort_radix/data) sort_auto preserves original behaviour; sort_radix uses byte-order (ASCII) sort which is not locale-sensitive; data uses first-appearance order - factor_as_factor: when TRUE, re-encodes existing factor columns via factor_level_method (default FALSE preserves original behaviour) - factor_level_last_pattern: regex to move matching levels to end before na_level; NULL by default (no effect); only applies during re-encoding Closes insightsengineering#1322 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
✅ All contributors have signed the CLA |
|
brilliant! @kaipingyang great to see you here! |
Thanks! Happy to address any review comments. |
Melkiades
left a comment
There was a problem hiding this comment.
thanks, this is a nice feature and the defaults do reproduce the old behaviour (checked, output is byte-identical to main across char/logical/factor inputs). a few things before merge:
- the sort_radix test fails under
LC_COLLATE=C, which is what testthat edition 3 forces vialocal_reproducible_output(). under C collate sort_auto is already byte-order so it equals radix andexpect_false(identical(...))fails. it only passes locally because your shell is en_US.UTF-8. drop that line and keep the exact-orderexpect_equal, that one holds in any locale - man/ wasn't re-documented, need to run
devtools::document()and commit (usage/params are out of sync, R CMD check will complain) factor_as_factoris inserted beforena_levelso positional calls likedf_explicit_na(d, NULL, TRUE, FALSE, "MISS")now hit factor_as_factor instead of na_level and error. tern uses na_level by name everywhere so we're fine internally, but this is exported and used a lot in study code. can we move the 3 new args after na_level?
also please strip the auto-generated trailer from the PR description.
- Move factor_as_factor/factor_level_method/factor_level_last_pattern after na_level to preserve positional call compatibility - Update @param order in roxygen and man/df_explicit_na.Rd accordingly - Replace match.arg() with checkmate::assert_choice() so error message matches test expectation and style is consistent with rest of file - Drop expect_false(identical(...)) test line that fails under LC_COLLATE=C (testthat edition 3 forces C locale in CI)
|
I have read the CLA Document and I hereby sign the CLA |
|
All four points addressed:
All 32 tests pass locally. Please re-review when you have a chance. |
|
@copilot fix spell check |
shajoezhu
left a comment
There was a problem hiding this comment.
hi @kaipingyang , thanks for the changes. i made minor update, ci checks out, and downstream scda.test are all ok. thanks! Thanks @Melkiades for the review
changes were made. i made minor update, ci checks out, and downstream scda.test are all ok. thanks! Thanks @Melkiades for the review
Summary
Adds three new arguments to
df_explicit_na()to give users control over factor level ordering. Motivated by #1322.New arguments
factor_level_method("sort_auto"/"sort_radix"/"data") — controls how levels are ordered when character or logical columns are converted to factors (or existing factors are re-encoded viafactor_as_factor):"sort_auto"(default):sort(unique(x))— locale-aware, identical to the original behaviour. No existing code is affected."sort_radix":sort(unique(x), method = "radix")— byte-order (ASCII) sort, not locale-sensitive. Uppercase letters always sort before lowercase, which matches the behaviour of SASPROC SORTon mixed-case data."data":unique(x)— levels follow first-appearance order in the data.factor_as_factor(FALSEby default) — whenTRUE, existing factor columns are also re-encoded usingfactor_level_method. The defaultFALSEpreserves the original behaviour (existing factor levels are kept as-is).factor_level_last_pattern(NULLby default) — a regular expression; any levels matching it are moved to the end of the level list, immediately beforena_level. Useful for consistently placing catch-all categories (e.g."Other","Unknown") last. Has no effect whenNULL.Backward compatibility
All three arguments have defaults that exactly reproduce the original function behaviour, so no existing code needs to change.
Test plan
factor_level_method = "sort_auto"produces identical results to the unmodified functionfactor_level_method = "sort_radix"sorts uppercase before lowercase on mixed-case datafactor_level_method = "data"preserves first-appearance orderfactor_as_factor = TRUEre-encodes existing factor levels;FALSEleaves them unchangedfactor_level_last_patternmoves matching levels to end;NULLis a no-opna_levelremains the last level in all casesFixes #1322