Question Details

No question body available.

Tags

r

Answers (4)

January 27, 2026 Score: 3 Rep: 209,401 Quality: Medium Completeness: 50%

Using dplyr, you can run

dd |> filter(n()==1 | lab=='hburg', .by=id)

id lab value

1 1 hburg 14

2 2 hburg 13

3 3 hb 13

4 4 hb 13

5 5 hb 12

That will return a row for each ID where the value is hburg when there is more than one record, otherwise it will just return the single record.

This would break if a subject has more than one record and neither is hb_urg. Not sure what you would want to do in that case.

January 27, 2026 Score: 3 Rep: 11,859 Quality: Medium Completeness: 50%

We might do the good old duplicated()-trick. Modernly written with |>

dd |> subset(select = (!duplicated(id) & !duplicated(id, fromLast = TRUE)) | lab == "hburg")
  id    lab value 
2  1 hburg    14   
4  2 hburg    13   
5  3     hb    13   
6  4     hb    13   
7  5     hb    12   

or

subset(dd, ave(dd$id, dd$id, FUN=length)==1L | lab=='hb
urg')
January 27, 2026 Score: 2 Rep: 70,425 Quality: Low Completeness: 50%

Another dplyr variant could be to sort with the hburg rows coming first (FALSE coming before TRUE, so test for NOT hburg), and then show the first row for each id.

This strikes me as pretty legible and will always give you one row per id, using the first hburg where one is available.

dd |>
  arrange(lab != "hburg") |>
  slice(1, .by = id)

id lab value 1 1 hburg 14 2 2 hburg 13 3 3 hb 13 4 4 hb 13 5 5 hb 12
January 27, 2026 Score: 1 Rep: 49,933 Quality: Medium Completeness: 60%

While there are some clever solutions already posted, sometimes it is quickest (in person time, not computer time) to use a general solution.

One general solution that works here and should be in every R programmers tool box is the split-apply-recombine idea. Split your data frame (or other data object) into individual pieces (in this case by id), use lapply or other apply function to work on each piece, then recombine the pieces.

Here is some code that demonstrates for the given data:

split(dd, dd$id) |>
  lapply(function(df) { # anonymous function per id
    if(length(w 
  do.call(rbind, args=) -> 
  ddnew

This checks to see if there is one or more "hburg" lab and if so, returns the first one, otherwise it returns the first row. This can easily be modified to return the last row, the last "hburg", the whole data frame if there are no "hburg", all rows with "hburg", etc.

If you use the tidyverse then the row with do.call can be replaced with bind_rows to make it a little simpler. And lapply could be replaced with one of the map functions from the purrr package.