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.