Add limit parameter to nafill and setnafill - #7819
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #7819 +/- ##
==========================================
- Coverage 99.02% 98.99% -0.03%
==========================================
Files 88 88
Lines 17266 17318 +52
==========================================
+ Hits 17097 17144 +47
- Misses 169 174 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Generated via commit a6018a9 Download link for the artifact containing the test results: ↓ atime-results.zip
|
| test(2379.01, nafill(c(1, NA, NA, NA, 5), type="locf", limit=1), c(1, 1, NA, NA, 5)) | ||
| test(2379.02, nafill(c(1, NA, NA, 5, NA, NA, NA, 9), type="locf", limit=2), c(1, 1, 1, 5, 5, 5, NA, 9)) | ||
| test(2379.03, nafill(c(1, NA, NA, 4, NA), type="locf", limit=Inf), c(1, 1, 1, 4, 4)) | ||
| test(2379.04, nafill(c(NA, NA, 3, NA, NA), type="locf", limit=1), c(NA, NA, 3, 3, NA)) |
There was a problem hiding this comment.
whats the difference between 01 and 04?
There was a problem hiding this comment.
can we also test edge cases like negative, 0, NA, NaN, NULL?
| # limit= restricts the number of consecutive fills | ||
| y = c(1, NA, NA, NA, 5) | ||
| nafill(y, "locf", limit=1) # Only fills the first NA | ||
| nafill(y, "locf", limit=2) # Fills the first two NAs |
There was a problem hiding this comment.
I dont get the added value of the second line, maybe change it to Inf for showcasing filling all.
| type = match.arg(type) | ||
| .Call(CnafillR, x, type, fill, nan_is_na(nan), FALSE, NULL) | ||
| if (!is.numeric(limit) || length(limit) != 1L || limit < 0) | ||
| stopf("limit must be a non-negative scalar numeric or Inf") |
There was a problem hiding this comment.
unprecise since Inf is also non-negative
There was a problem hiding this comment.
What about type="const". What about fractions like limit=1.5?
Please add tests for the following cases:
- nocb
- limit: 0, NA, NaN, negative, fractional, complex, NULL, and length > 1
- integer and character
- setnafill() by-reference
NEWS is missing.
What nafill(c(NA, 1), "locf", fill=0, limit=0)
67e1f87 to
dd875ac
Compare
| ans->dbl_v[0] = ISNAN(x[0]) ? fill : x[0]; | ||
| if (ISNAN(x[0])) fills = 1; |
There was a problem hiding this comment.
We do not need this double branching on ISNAN(x[0]). This will also happen at the other cases below!
| if (verbose) | ||
| tic = omp_get_wtime(); | ||
|
|
||
| double limit_val = REAL(limit)[0]; |
There was a problem hiding this comment.
Might be cleaner to represent as uint64_fast64_t since we also compare with it later
const double limit_d = REAL(limit)[0];
const uint_fast64_t limit_n = !R_FINITE(limit_d) || limit_d >= (double)UINT_FAST64_MAX ? UINT_FAST64_MAX : (uint_fast64_t)limit_d;
ben-schwen
left a comment
There was a problem hiding this comment.
Ty for the changes. We are almost there:
Still missing.
- the double branching thingy
- the c conversion of limit (this I consider as optional but it seems the right/cleaner approach)
- clarify in the docs whats happening for fractions of limit
- clarify whats happening for
type='const' - clarify boundary case for
nafill(c(NA, 1), "locf", fill=0, limit=0)which givesc(0, 1) - code coverage is still failing
| if (verbose) | ||
| tic = omp_get_wtime(); | ||
| if (type==0) { // const | ||
| if (nan_is_na) { |
There was a problem hiding this comment.
why do we remove this explicit branching? please dont just revert but explain!
| } | ||
| } | ||
|
|
||
| unsigned int itype=-1; |
There was a problem hiding this comment.
why do we make this change here? please explain!
| dt = data.table(a=c(1, NA, NA)) | ||
| setnafill(dt, type="locf", limit=1) | ||
| test(2380.09, {dt=data.table(a=c(1,NA,NA)); setnafill(dt, type="locf", limit=1); dt$a}, c(1, 1, NA)) |
There was a problem hiding this comment.
why no test at the 2nd line?
Does also look quite more complicated than simple writing...
| dt = data.table(a=c(1, NA, NA)) | |
| setnafill(dt, type="locf", limit=1) | |
| test(2380.09, {dt=data.table(a=c(1,NA,NA)); setnafill(dt, type="locf", limit=1); dt$a}, c(1, 1, NA)) | |
| test(2380.09, setnafill(data.table(a=c(1, NA, NA)), type="locf", limit=1), data.table(a=c(1, 1, NA))) |
| test(2380.13, nafill(1:5, limit=-1), error="limit must be a non-negative scalar numeric") | ||
| test(2380.14, nafill(1:5, limit=NA), error="limit must be a non-negative scalar numeric") | ||
| test(2380.15, nafill(1:5, limit=NULL), error="limit must be a non-negative scalar numeric") | ||
| test(2380.16, nafill(1:5, limit=c(1, 2)), error="limit must be a non-negative scalar numeric") | ||
| test(2380.17, nafill(1:5, limit=1+2i), error="limit must be a non-negative scalar numeric") | ||
| test(2380.18, setnafill(data.table(a=1:5), limit=-1), error="limit must be a non-negative scalar numeric") |
There was a problem hiding this comment.
Maybe loop over?
| test(2380.13, nafill(1:5, limit=-1), error="limit must be a non-negative scalar numeric") | |
| test(2380.14, nafill(1:5, limit=NA), error="limit must be a non-negative scalar numeric") | |
| test(2380.15, nafill(1:5, limit=NULL), error="limit must be a non-negative scalar numeric") | |
| test(2380.16, nafill(1:5, limit=c(1, 2)), error="limit must be a non-negative scalar numeric") | |
| test(2380.17, nafill(1:5, limit=1+2i), error="limit must be a non-negative scalar numeric") | |
| test(2380.18, setnafill(data.table(a=1:5), limit=-1), error="limit must be a non-negative scalar numeric") | |
| lims = list(-1, NA, NaN, NULL, c(1, 2), 1+2i) | |
| for (i in seq_along(lims)) { | |
| test(2380.12 + i / 100, nafill(1:5, limit=lims[[i]]), error="limit must be a non-negative scalar numeric") | |
| } |
| test(2380.03, nafill(c(1, NA, NA, 4, NA), type="locf", limit=Inf), c(1, 1, 1, 4, 4)) | ||
| test(2380.04, nafill(c(NA, NA, 3, NA, NA), type="locf", limit=1), c(NA, NA, 3, 3, NA)) | ||
| test(2380.05, nafill(c(1, NA, NA, 5), type="nocb", limit=1), c(1, NA, 5, 5)) | ||
| test(2380.06, nafill(c(1L, NA, NA), type="locf", limit=1), c(1L, 1L, NA)) |
There was a problem hiding this comment.
test 1,2,3,6,7, could probably be subsumed in 2 tests.

closes #7677
this PR adds a limit argument to nafill and setnafill to restrict the maximum number of consecutive NA values filled. Default is Inf to preserve existing behavior. Updated R interface, C kernel logic, and documentation.
hi @tdhock @joshhwuu can you please have a look at this when you got time thanks .