通过最大化 R data.table 中增加虚拟变量(列)分组的流行度来创建 CDF

Posted

技术标签:

【中文标题】通过最大化 R data.table 中增加虚拟变量(列)分组的流行度来创建 CDF【英文标题】:Creating a CDF by Maximizing Prevalence for Increasing Groupings of Dummy Variables (Columns) in R data.table 【发布时间】:2022-01-17 06:15:21 【问题描述】:

我有非排他性类别/分类的流行数据。 (例如,一个故事可以是“惊人的”、“无聊的”、“迷人的”、“黑暗的”或这四者的任意组合。)说明性:

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,其中:

我知道对于无类别的数据(即a = b = c = d = 0),我覆盖了 10% 的人口。 我知道,对于一个类别或没有类别的数据,我可以通过将自己限制为 c 类别来覆盖 21% 的人口。

即:

results[ ( a == 0 & b == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 1 , sum(prevalence) ]
我知道,对于两个、一个或没有类别的数据,我可以通过将自己限制为 bc 类别来覆盖 36% 的人口。

即:

results[ ( a == 0 & d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 2 , sum(prevalence) ]
我知道,对于三个、两个、一个或没有类别的数据,我可以通过将自己限制为 abc 类别来覆盖 59% 的人口。

即:

results[ ( d == 0 ) & rowSums( results[ , -'prevalence' ] ) <= 3 , sum(prevalence) ]
而且,我知道,对于四个、三个、两个、一个或没有类别的数据,我可以通过将自己限制在四个类别中的每一个类别(a、@987654334 @、cd)。

在这个有限的例子中,我只是检查了所有可能的类别,通过对允许的非零类别进行分组来找到最大的流行度(实际上,正如你在我的代码 sn-ps 中看到的那样,我正在做相反的事情并通过分组来找到流行度限制为零的类别)。

我怎样才能以data.table 的方式做到这一点,这样我就不必在我的真实摘要数据集中通过许多虚拟变量(列)组合进行暴力破解?

我怀疑这可能涉及对.EACHIlapply 的巧妙使用,这是我无法想到的。​​

【问题讨论】:

【参考方案1】:

试试这个:

#' @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-syntax,但它是兼容的:

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) 和 prevalence 对象的目的是简化使用 combn 的列选择,而不是硬编码列名称、计数或函数中的位置。

【讨论】:

以上是关于通过最大化 R data.table 中增加虚拟变量(列)分组的流行度来创建 CDF的主要内容,如果未能解决你的问题,请参考以下文章

R之data.table速查手册

通过 data.table (R) 循环 grepl()

R 中 data.table 的 colnames() 行为

r语言table显示10

R通过字符变量的值对data.table进行子集

使用带有R内核的jupyter笔记本,如何通过引用来抑制打印结果更新data.table?