Ниже мы обсудим решения с использованием двух пакетов, упомянутых в вопросе.
1) sqldf Чтобы использовать пакет sqldf, указанный в вопросе, используя ввод, воспроизводимый в примечании в конце:
library(sqldf)
sqldf("select ID,
nullif(count(Test1), 0) Test1,
nullif(count(Test2), 0) Test2,
nullif(count(Test3), 0) Test3,
nullif(count(Test4), 0) Test4
from DF
group by ID")
давая:
ID Test1 Test2 Test3 Test4
1 1 2 1 NA 3
2 2 2 2 1 1
nullif(count(test1), 0)
можно сократить до count(test1)
, если можно сообщить 0 для идентификатора, который является полностью Н/П, и аналогичным образом для других столбцов теста*.
1a) Если на самом деле столбцов много, а не только 4, или вам не нравится повторяющаяся часть select
, мы можем создать строку, а затем вставить ее следующим образом:
testNames <- names(DF)[-1]
select <- toString(sprintf("nullif(count(%s), 0) %s", testNames, testNames))
library(sqldf)
fn$sqldf("select ID, $select
from DF
group by ID")
Добавьте аргумент verbose = TRUE
к вызову sqldf
, чтобы увидеть, что та же самая строка фактически отправляется на серверную часть.
Если можно указать 0 вместо NA, мы могли бы упростить select <- ...
до:
select <- toString(sprintf("count(%s) %s", testNames, testNames))
2) reshape2 Чтобы использовать melt
, как в попытке кода в вопросе:
library(magrittr)
library(reshape2)
count <- function(x) if (all(is.na(x))) NA_integer_ else sum(!is.na(x))
DF %>%
melt(id.vars = "ID") %>%
dcast(ID ~ variable, count)
Если можно сообщить 0 для любого идентификатора, который полностью NA, тогда подсчет можно упростить до:
count <- function(x) sum(!is.na(x))
Примечание
Lines <- "ID Test1 Test2 Test3 Test4
1 0 0 NA 1.2
1 0 NA NA 3.0
1 NA NA NA 0
2 0 0 0 0
2 0 0 NA NA"
DF <- read.table(text = Lines, header = TRUE)
person
G. Grothendieck
schedule
27.10.2018