简体   繁体   中英

Calculate the percentage of non-NA values of subgroups

I have a data.frame like this:

df <- structure(list(sample = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                          2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), sub_sample = structure(c(1L, 
                                                                                        1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
                                                                                        3L), .Label = c("A", "B", "C"), class = "factor"), value = c(111L, 
                                                                                                                                                     233L, NA, NA, NA, 56L, 48L, 23L, 48L, 567L, 98L, 75L, 7578L, 
                                                                                                                                                     NA, 56L, 48L, NA, NA)), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                                                                 -18L))

There are a few missing values (NA) and I want to calculate the percentage of non-NA of each group. The way I do it now is like this:

total_nr <- df %>% 
  group_by(sample, sub_sample) %>%
  tally()

nr_wo_NA <- df %>% 
  group_by(sample, sub_sample) %>%
  na.omit() %>% 
  tally()

nr_wo_NA$n <- (nr_wo_NA$n / total_nr$n) * 100

Which gives me what I want:

# A tibble: 6 x 3
# Groups:   sample [2]
  sample sub_sample     n
   <int> <fct>      <dbl>
1      1 A           66.7
2      1 B           33.3
3      1 C          100  
4      2 A          100  
5      2 B           66.7
6      2 C           33.3

But is there a way to this direclty without creating two separate data.frames?

You can do:

df %>%
 group_by(sample, sub_sample) %>%
 summarise(value_non_na = sum(!is.na(value))/n()*100)

  sample sub_sample value_non_na
   <int> <fct>             <dbl>
1      1 A                  66.7
2      1 B                  33.3
3      1 C                 100  
4      2 A                 100  
5      2 B                  66.7
6      2 C                  33.3

We can take mean of logical values after comparing it with is.na

library(dplyr)
df %>% group_by(sample, sub_sample)%>% summarise(value = mean(!is.na(value)) * 100)

#  sample sub_sample value
#   <int> <fct>      <dbl>
#1      1 A           66.7
#2      1 B           33.3
#3      1 C          100  
#4      2 A          100  
#5      2 B           66.7
#6      2 C           33.3

We can use the same logic with base R

aggregate(value~sample+sub_sample, df, function(x) mean(!is.na(x)), na.action = na.pass)

and data.table

library(data.table)
setDT(df)[, mean(!is.na(value)), .(sample, sub_sample)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM