1

I would like to retrieve the first non-zero values from all groups.

DataFrame

Group  values Days
A      0      12 
A      0      15
A      30     18
A      60     20
B      0      2
B      15     10
B      16     20
B      20     30
C      0      5
C      30     10
C      70     15

Output

Group Values  Days
A     30      18
B     15      10
C     30      10
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
BD'auria
  • 135
  • 10
  • Does this answer your question? [Get first and last values per group – dplyr group\_by with last() and first()](https://stackoverflow.com/questions/42654219/get-first-and-last-values-per-group-dplyr-group-by-with-last-and-first) – user438383 Jun 28 '23 at 12:57

5 Answers5

3

You can do

> subset(df, ave(values != 0, Group, FUN = cumsum) == 1)
   Group values Days
3      A     30   18
6      B     15   10
10     C     30   10

or

> aggregate(. ~ Group, subset(df, values != 0), head, 1)
  Group values Days
1     A     30   18
2     B     15   10
3     C     30   10
ThomasIsCoding
  • 96,636
  • 9
  • 24
  • 81
3

data.table approach

library(data.table)
setDT(df)[!values == 0, .SD[1], Group]
#    Group values Days
# 1:     A     30   18
# 2:     B     15   10
# 3:     C     30   10
Wimpel
  • 26,031
  • 1
  • 20
  • 37
3

Two subset`'s.

df |> subset(values > 0) |> subset(!duplicated(Group)) 
#    Group values Days
# 3      A     30   18
# 6      B     15   10
# 10     C     30   10

Data:

df <- structure(list(Group = c("A", "A", "A", "A", "B", "B", "B", "B", 
"C", "C", "C"), values = c(0L, 0L, 30L, 60L, 0L, 15L, 16L, 20L, 
0L, 30L, 70L), Days = c(12L, 15L, 18L, 20L, 2L, 10L, 20L, 30L, 
5L, 10L, 15L)), class = "data.frame", row.names = c(NA, -11L))
jay.sf
  • 60,139
  • 8
  • 53
  • 110
2

You could first filter the rows with values 0 and after that slice the first value .by you Group like this:

library(dplyr)

df %>%
  filter(values != 0) %>%
  slice(1, .by = Group)
#>   Group values Days
#> 1     A     30   18
#> 2     B     15   10
#> 3     C     30   10

Created on 2023-06-28 with reprex v2.0.2

Quinten
  • 35,235
  • 5
  • 20
  • 53
2

Alternatively we can try

library(dplyr) 

df %>% group_by(Group) %>% mutate(val=cumall(lag(!values))) %>% 
filter(is.na(val)) %>% slice_tail(n=1) %>% select(-val)

# ouuput

# A tibble: 3 × 3
# Groups:   Group [3]
  Group values  Days
  <chr>  <dbl> <dbl>
1 A         30    18
2 B         15    10
3 C         30    10

jkatam
  • 2,691
  • 1
  • 4
  • 12