Repository navigation
Take a grouped slice() of numbers in one native call - #460
Merged
Merged
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
slice()of grouped data evaluates its expressions in the data mask for each group, casts each value withvctrs::vec_as_subscript()and combines a group's values withvctrs::vec_c(). It then turns each group's subscripts into the group's rows withvctrs::num_as_location(), which removes zeros, missing values and positions past the group's end. Each group's evaluation builds a new data mask. Over the 42,739 women in the first 100,000 rows of the India 2021 DHS births file, grouped bycaseid,slice(gb, 1)took about 0.45 seconds, where a tibble takes about 0.36.This PR adds
C_dtatools_slice_literal_plan(). After the loop evaluates the first group,.slice_literal_planned()takes the rows of every later group in one call when each expression gives every group the value it gave the first. An expression does when it is one of these:(on such an expressionc()on any number of them, untagged:on two numbers of length 1 or their negationsThat covers
slice(gb, 1),slice(gb, -1),slice(gb, 1:3)andslice(gb, c(1, 3)). Each function the call finds from the quosure's environment must be base's primitive, and no column may be named for it, since R reads a column while it looks up a function of that name. None of these calls dispatches on values without a class or can warn. A binary minus's integer overflow and:of a longer vector do warn, so those leave the groups to the loop.Each later group's subscripts are then the first group's. The call keeps the group's rows at the locations
num_as_location()gives for the group's size: the positive positions within it in order, repeats kept, or every position the negative ones do not name, in order. Positive and negative positions together leave the groups to the loop, which raises the error in the first group.Behavior
Results are unchanged. ADR 0122 records the decision. None of the closures the loop calls for a later group may be debugged:
lapply(),environment(),vec_as_subscript(),vec_c(),num_as_location(), and thecheck_dots_empty0(),list2(),is_integer()andis_double()that vctrs' namespace finds. A traced or replaced one sees only the first group's calls, as ADR 0058 allows.Timing
Best of three runs in fresh R sessions, in seconds, with the builds interleaved, over the first 100,000 rows of the India 2021 DHS births file grouped by
caseid. Before is main.slice(gb, 1)slice(gb, -1)slice(gb, 1:2)slice(gb, c(1, 3))Tests
1,-2L,20,c(3, 1, 3),5:2,-1:-3,-c(1, 3),c(1, NA),c()and an injected vector, on 60 interleaved groups and on the empty groups of.drop = FALSE. Each must give the same value, warnings and errors with the plan as without it, and the plan must take every one. It also runs more than one expression, none,.byand rowwise data.n(), a binary minus, names, a classed number, a column namedcbeside a call ofc(), ungrouped data,:of a longer vector, and a minus in the global environment. A column namedcdoes not stopslice(named, 1), which calls noc().