Home > OS >  Count all duplicated values in R
Count all duplicated values in R

Time:12-09

I have the following vector called x:

x <- c(1, 1, 4, 5, 4, 6, 1, 1)
x
#> [1] 1 1 4 5 4 6 1 1

I would like to count all values that are duplicated values. In this case, the numbers 1,1,1,1,4,4 are duplicates which means a total of 6 duplicated values. Here are some tries:

x <- c(1, 1, 4, 5, 4, 6, 1, 1)
# Wrong outputs
sum(duplicated(x))
#> [1] 4
sum(table(x)-1)
#> [1] 4
# Returns number of duplicated values in this case 1 and 4
nrow(data.frame(table(x))[data.frame(table(x))$Freq > 1,])
#> [1] 2

Created on 2022-12-08 with reprex v2.0.2

So I was wondering if anyone knows how to calculate all the duplicates instead of counting the number of values that have duplicates?

CodePudding user response:

Other options:

sum(Filter(\(z) z > 1, table(x)))
sum(setdiff(table(x), 1L))
sum(x %in% x[duplicated(x)])

The last is clearly the fastest, akrun's is a close second:

bench::mark(
  sum(Filter(\(z) z > 1, table(x))),
  sum(setdiff(table(x), 1L)),
  sum(x %in% x[duplicated(x)]),
  sum(table(x)[names(table(x)) %in% x[duplicated(x)]]),
  sum(duplicated(x)|duplicated(x, fromLast = TRUE))
)
# # A tibble: 5 x 13
#   expression                                                min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result    memory              time                gc                   
#   <bch:expr>                                           <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>    <list>              <list>              <list>               
# 1 sum(Filter(function(z) z > 1, table(x)))                 58us   67.5us    14335.    5.35KB     6.62  6499     3    453.4ms <int [1]> <Rprofmem [16 x 3]> <bench_tm [6,502]>  <tibble [6,502 x 3]> 
# 2 sum(setdiff(table(x), 1L))                             51.6us   60.9us    16046.        0B     6.56  7338     3    457.3ms <int [1]> <Rprofmem [0 x 3]>  <bench_tm [7,341]>  <tibble [7,341 x 3]> 
# 3 sum(x %in% x[duplicated(x)])                            2.8us    3.2us   294065.        0B     0    10000     0       34ms <int [1]> <Rprofmem [0 x 3]>  <bench_tm [10,000]> <tibble [10,000 x 3]>
# 4 sum(table(x)[names(table(x)) %in% x[duplicated(x)]])  102.1us  123.4us     7957.        0B     4.26  3737     2    469.6ms <int [1]> <Rprofmem [0 x 3]>  <bench_tm [3,739]>  <tibble [3,739 x 3]> 
# 5 sum(duplicated(x) | duplicated(x, fromLast = TRUE))     4.3us    4.9us   194347.        0B    19.4   9999     1     51.4ms <int [1]> <Rprofmem [0 x 3]>  <bench_tm [10,000]> <tibble [10,000 x 3]>

(Disclaimer: profiling code with data this small is really a fool's errand ... but I was curious.)

CodePudding user response:

We can use duplicated twice ie. from forward as well as reverse so that all the duplicates are covered

sum(duplicated(x)|duplicated(x, fromLast = TRUE))
[1] 6

CodePudding user response:

Alternative way to calculate. Count the duplicated values (1, 1, 1, 4), and count the number of duplicates values (1, 4).

sum(duplicated(x), length(unique(x[duplicated(x)])))
# 6

CodePudding user response:

When writing this question I found an option with table and sum the number of values of the names which have duplicates from that table like this:

x <- c(1, 1, 4, 5, 4, 6, 1, 1)
sum(table(x)[names(table(x)) %in% x[duplicated(x)]])
#> [1] 6

Created on 2022-12-08 with reprex v2.0.2

I assume there should be a better option without using table function.

  • Related