Reputation: 123
I have this reduced data frame
ind;year;n
67;2016;1
76;2016;1
95;2016;2
171;2016;3
60;2017;1
73;2017;1
95;2017;3
171;2017;1
175;2017;1
60;2018;4
95;2018;7
96;2018;1
99;2018;1
171;2018;1
171;2019;2
172;2019;1
178;2019;1
and I would like to count the number of individuals that appear per year, excluding those that have appeared in previous years. In that case it would look like this:
year n
2016 4
2017 3
2018 2
2019 2
I used this but it does not exclude those that appear in previous years
df %>%
group_by(ind, year) %>%
dplyr::summarise(totalcount =n())%>%
group_by(year)%>%
tally()
Upvotes: 3
Views: 49
Reputation: 389135
We can get all ind
in a list for each year
. In total
we create accumulating ind
values in each year and to count unique ind
we count of length
with setdiff
.
library(dplyr)
library(purrr)
df %>%
group_by(year) %>%
summarise(ind = list(ind)) %>%
mutate(total = accumulate(ind[-n()], ~unique(c(.x, .y)), .init = list()),
n = map2_int(ind, total, ~length(setdiff(.x, .y)))) %>%
select(year, n)
# A tibble: 4 x 2
# year n
# <int> <int>
#1 2016 4
#2 2017 3
#3 2018 2
#4 2019 2
data
df <- structure(list(ind = c(67L, 76L, 95L, 171L, 60L, 73L, 95L, 171L,
175L, 60L, 95L, 96L, 99L, 171L, 171L, 172L, 178L), year = c(2016L,
2016L, 2016L, 2016L, 2017L, 2017L, 2017L, 2017L, 2017L, 2018L,
2018L, 2018L, 2018L, 2018L, 2019L, 2019L, 2019L), n = c(1L, 1L,
2L, 3L, 1L, 1L, 3L, 1L, 1L, 4L, 7L, 1L, 1L, 1L, 2L, 1L, 1L)),
class = "data.frame", row.names = c(NA, -17L))
Upvotes: 0
Reputation: 887501
Here is an option in base R
lst1 <- split(df$ind, df$year)
lst1[] <- lengths(Reduce(function(x, y) y[!x %in% y],
split(df$ind, df$year), accumulate = TRUE))
setNames(stack(lst1)[2:1], c('year', 'n'))
# year n
#1 2016 4
#2 2017 3
#3 2018 3
#4 2019 2
If this involves all previous 'year'
lst1 <- split(df$ind, df$year)
lst2 <- vector('list', length(lst1))
names(lst2) <- names(lst1)
lst2[[1]] <- length(lst1[[1]])
for(i in 2:length(lst1)) lst2[[i]] <- sum(!lst1[[i]] %in%
unlist(lst1[seq_len(i-1)]))
setNames(stack(lst2)[2:1], c('year', 'n'))
# year n
#1 2016 4
#2 2017 3
#3 2018 2
#4 2019 2
Or an option with dplyr
where we arrange
by 'year', take the distinct
rows (assuming that there won't be any duplicate 'ind' within a 'year'), and then use count
library(dplyr)
df %>%
arrange(year) %>%
distinct(ind, .keep_all = TRUE) %>%
select(-n) %>%
count(year)
# year n
#1 2016 4
#2 2017 3
#3 2018 2
#4 2019 2
df <- structure(list(ind = c(67L, 76L, 95L, 171L, 60L, 73L, 95L, 171L,
175L, 60L, 95L, 96L, 99L, 171L, 171L, 172L, 178L), year = c(2016L,
2016L, 2016L, 2016L, 2017L, 2017L, 2017L, 2017L, 2017L, 2018L,
2018L, 2018L, 2018L, 2018L, 2019L, 2019L, 2019L), n = c(1L, 1L,
2L, 3L, 1L, 1L, 3L, 1L, 1L, 4L, 7L, 1L, 1L, 1L, 2L, 1L, 1L)),
class = "data.frame", row.names = c(NA,
-17L))
Upvotes: 3