通过最大化 R 中增加虚拟变量(列)分组的普遍性来创建 CDF data.table
Creating a CDF by Maximizing Prevalence for Increasing Groupings of Dummy Variables (Columns) in R data.table
我有非排他性的患病率数据 categories/classifications。 (例如,一个故事可以是 'amazing'、'boring'、'charming'、'dark' 或这四者的任意组合。)说明性的:
library(data.table)
set.seed(0)
results = as.data.table( expand.grid( rep( list(0:1) , 4 ) ) )
names(results) = c('a', 'b', 'c', 'd')
results$prevalence = runif( n = 16 )
results$prevalence = results$prevalence/sum(results$prevalence)
我希望能够回答以下问题:
- (琐碎)不属于任何类别(
a = b = c = d = 0
)的人口覆盖率是多少?
- 覆盖人口百分比最大的类别是什么?
- 覆盖人口比例最大的两个类别是什么?
- ...等等...
实际上,我想创建一个准 CDF,其中:
- 我知道 none 类别(即
a = b = c = d = 0
)中的数据覆盖了 10% 的人口。
- 我知道对于一个类别或没有类别的数据,我可以通过将自己限制在类别
c
来覆盖 21% 的人口。
That is:
results[ ( a == 0 & b == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 1 , sum(prevalence) ]
- 我知道对于两类、一类或无类别的数据,我可以通过将自己限制在类别
b
和 c
来覆盖 36% 的人口。
That is:
results[ ( a == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 2 , sum(prevalence) ]
- 我知道对于三类、二类、一类或无类别的数据,我可以通过将自己限制在类别
a
、b
和 [= 来覆盖 59% 的人口17=].
That is:
results[ ( d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 3 , sum(prevalence) ]
- 而且,平凡地,我知道对于四、三、二、一或无类别的数据,我可以通过将自己限制在四个类别中的每一个来覆盖 100% 的人口 (
a
, b
, c
, d
).
在这个有限的示例中,我只是检查了所有可能的类别,以通过对允许的非零类别进行分组来找到最大的流行度(实际上,正如您从我的代码片段中看到的那样,我正在做相反的事情并通过分组找到流行度限制为零的类别)。
我怎样才能以 data.table
的方式做到这一点,这样我就不必通过我的真实汇总数据集中虚拟变量(列)的许多组合来强制执行?
我怀疑它可能涉及一些我没有想到的 .EACHI
或 lapply
的巧妙使用。
试试这个:
#' @param dat 'data.frame' (or derivative), with only binary indicator columns
#' @param prev 'numeric', the prevalence indicator to be summed
#' @param n 'integer', number of categories for limiting coverage
#' @return numeric, with attribute "columns" indicating the selected combination of columns
func <- function(dat, prev, n) {
stopifnot(ncol(dat) >= n)
if (n == ncol(dat)) {
out <- sum(prev) # ideally 1
attr(out, "columns") <- colnames(dat)
} else {
com <- t(combn(ncol(dat), ncol(dat) - n))
vec <- apply(com, 1, function(ind) {
sum(prev[rowSums(sapply(subset(dat, select = ind), `>`, 0)) < 1])
})
out <- max(vec)
attr(out, "columns") <- colnames(dat)[-com[which.max(vec),]]
}
out
}
进行中:
func(results[,1:4], results$prevalence, 0)
# [1] 0.1038405
# attr(,"columns")
# character(0)
func(results[,1:4], results$prevalence, 1)
# [1] 0.2090139
# attr(,"columns")
# [1] "c"
func(results[,1:4], results$prevalence, 2)
# [1] 0.3561435
# attr(,"columns")
# [1] "b" "c"
func(results[,1:4], results$prevalence, 3)
# [1] 0.5859805
# attr(,"columns")
# [1] "a" "b" "c"
func(results[,1:4], results$prevalence, 4)
# [1] 1
# attr(,"columns")
# [1] "a" "b" "c" "d"
这不是 data.table
语法,但它是兼容的:
results[, func(.SD, prevalence, 2), .SDcols = a:d]
# [1] 0.3561435
# attr(,"columns")
# [1] "b" "c"
或一次所有数字:
results[, sapply(c(0L, seq_along(.SD)), func, dat = .SD, prev = prevalence), .SDcols = a:d]
# [1] 0.1038405 0.2090139 0.3561435 0.5859805 1.0000000
将数据分成单独的“类别列”(dat
) 和一个 prev
alence 对象的目的是通过 combn
简化列选择并且不难-代码列名称、计数或函数中的位置。
我有非排他性的患病率数据 categories/classifications。 (例如,一个故事可以是 'amazing'、'boring'、'charming'、'dark' 或这四者的任意组合。)说明性的:
library(data.table)
set.seed(0)
results = as.data.table( expand.grid( rep( list(0:1) , 4 ) ) )
names(results) = c('a', 'b', 'c', 'd')
results$prevalence = runif( n = 16 )
results$prevalence = results$prevalence/sum(results$prevalence)
我希望能够回答以下问题:
- (琐碎)不属于任何类别(
a = b = c = d = 0
)的人口覆盖率是多少? - 覆盖人口百分比最大的类别是什么?
- 覆盖人口比例最大的两个类别是什么?
- ...等等...
实际上,我想创建一个准 CDF,其中:
- 我知道 none 类别(即
a = b = c = d = 0
)中的数据覆盖了 10% 的人口。 - 我知道对于一个类别或没有类别的数据,我可以通过将自己限制在类别
c
来覆盖 21% 的人口。
That is:
results[ ( a == 0 & b == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 1 , sum(prevalence) ]
- 我知道对于两类、一类或无类别的数据,我可以通过将自己限制在类别
b
和c
来覆盖 36% 的人口。
That is:
results[ ( a == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 2 , sum(prevalence) ]
- 我知道对于三类、二类、一类或无类别的数据,我可以通过将自己限制在类别
a
、b
和 [= 来覆盖 59% 的人口17=].
That is:
results[ ( d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 3 , sum(prevalence) ]
- 而且,平凡地,我知道对于四、三、二、一或无类别的数据,我可以通过将自己限制在四个类别中的每一个来覆盖 100% 的人口 (
a
,b
,c
,d
).
在这个有限的示例中,我只是检查了所有可能的类别,以通过对允许的非零类别进行分组来找到最大的流行度(实际上,正如您从我的代码片段中看到的那样,我正在做相反的事情并通过分组找到流行度限制为零的类别)。
我怎样才能以 data.table
的方式做到这一点,这样我就不必通过我的真实汇总数据集中虚拟变量(列)的许多组合来强制执行?
我怀疑它可能涉及一些我没有想到的 .EACHI
或 lapply
的巧妙使用。
试试这个:
#' @param dat 'data.frame' (or derivative), with only binary indicator columns
#' @param prev 'numeric', the prevalence indicator to be summed
#' @param n 'integer', number of categories for limiting coverage
#' @return numeric, with attribute "columns" indicating the selected combination of columns
func <- function(dat, prev, n) {
stopifnot(ncol(dat) >= n)
if (n == ncol(dat)) {
out <- sum(prev) # ideally 1
attr(out, "columns") <- colnames(dat)
} else {
com <- t(combn(ncol(dat), ncol(dat) - n))
vec <- apply(com, 1, function(ind) {
sum(prev[rowSums(sapply(subset(dat, select = ind), `>`, 0)) < 1])
})
out <- max(vec)
attr(out, "columns") <- colnames(dat)[-com[which.max(vec),]]
}
out
}
进行中:
func(results[,1:4], results$prevalence, 0)
# [1] 0.1038405
# attr(,"columns")
# character(0)
func(results[,1:4], results$prevalence, 1)
# [1] 0.2090139
# attr(,"columns")
# [1] "c"
func(results[,1:4], results$prevalence, 2)
# [1] 0.3561435
# attr(,"columns")
# [1] "b" "c"
func(results[,1:4], results$prevalence, 3)
# [1] 0.5859805
# attr(,"columns")
# [1] "a" "b" "c"
func(results[,1:4], results$prevalence, 4)
# [1] 1
# attr(,"columns")
# [1] "a" "b" "c" "d"
这不是 data.table
语法,但它是兼容的:
results[, func(.SD, prevalence, 2), .SDcols = a:d]
# [1] 0.3561435
# attr(,"columns")
# [1] "b" "c"
或一次所有数字:
results[, sapply(c(0L, seq_along(.SD)), func, dat = .SD, prev = prevalence), .SDcols = a:d]
# [1] 0.1038405 0.2090139 0.3561435 0.5859805 1.0000000
将数据分成单独的“类别列”(dat
) 和一个 prev
alence 对象的目的是通过 combn
简化列选择并且不难-代码列名称、计数或函数中的位置。