从现有数据框或数据表创建多个虚拟对象

时间:2015-02-18 05:38:45

标签: r loops data.table lapply

我正在寻找对here发布的以下解决方案的快速扩展。在其中,Frank显示了一个示例数据表

test <- data.table("index"=rep(letters[1:10],100),"var1"=rnorm(1000,0,1))

您可以使用以下代码快速制作假人

inds <- unique(test$index) ; test[,(inds):=lapply(inds,function(x)index==x)]

现在我想为具有多行索引的data.table扩展此解决方案,例如

new <- data.table("id" = rep(c("Jan","James","Dirk","Harry","Cindy","Leslie","John","Frank"),125), "index1"=rep(letters[1:5],200),"index2" = rep(letters[6:15],100),"index3" = rep(letters[16:19],250))

我需要为许多傻瓜做这件事,理想情况下,解决方案可以让我得到4件事:

  1. 每个指数的总数
  2. 每个索引发生的平均次数
  3. 每个ID的每个索引的计数
  4. 每个ID的每个索引的平均值
  5. 在我的实际案例中,索引的命名方式不同,因此解决方案需要能够遍历我认为的列名。

    谢谢

    西蒙

1 个答案:

答案 0 :(得分:2)

如果您只需要该列表中的四个项目,则应该只列表:

indcols <- paste0('index',1:3)
lapply(new[,indcols,with=FALSE],table) # counts
lapply(new[,indcols,with=FALSE],function(x)prop.table(table(x))) # means

# or...

lapply(
  new[,indcols,with=FALSE],
  function(x){
    z<-table(x)
    rbind(count=z,mean=prop.table(z))
  })

这给出了

$index1
          a     b     c     d     e
count 200.0 200.0 200.0 200.0 200.0
mean    0.2   0.2   0.2   0.2   0.2

$index2
          f     g     h     i     j     k     l     m     n     o
count 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0 100.0
mean    0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1

$index3
           p      q      r      s
count 250.00 250.00 250.00 250.00
mean    0.25   0.25   0.25   0.25


以前的方法适用于data.frame或data.table,但相当复杂。使用data.table,可以使用melt语法:

melt(new, id="id")[,.(
  N=.N, 
  mean=.N/nrow(new)
), by=.(variable,value)]

给出了

    variable value   N mean
 1:   index1     a 200 0.20
 2:   index1     b 200 0.20
 3:   index1     c 200 0.20
 4:   index1     d 200 0.20
 5:   index1     e 200 0.20
 6:   index2     f 100 0.10
 7:   index2     g 100 0.10
 8:   index2     h 100 0.10
 9:   index2     i 100 0.10
10:   index2     j 100 0.10
11:   index2     k 100 0.10
12:   index2     l 100 0.10
13:   index2     m 100 0.10
14:   index2     n 100 0.10
15:   index2     o 100 0.10
16:   index3     p 250 0.25
17:   index3     q 250 0.25
18:   index3     r 250 0.25
19:   index3     s 250 0.25

@Arun在评论中提到了这种方法(并且他也实施了,我认为......?)。要了解其工作原理,请先查看melt(new, id="id")转换原始data.table。

正如评论中所述,融合data.table需要为某些版本的reshape2软件包安装和加载data.table



如果你还需要假人,可以像链接问题一样循环制作:

newcols <- list()
for (i in indcols){
    vals = unique(new[[i]])
    newcols[[i]] = paste(vals,i,sep='_')
    new[,(newcols[[i]]):=lapply(vals,function(x)get(i)==x)]
}

为方便起见,这会在newcols中存储与每个变量关联的列组。如果你想用这些虚拟对象进行制表(而不是上面的解决方案中的基础变量),你可以做

lapply(
  indcols,
  function(i) new[,lapply(.SD,function(x){
    z <- sum(x)
    list(z,z/.N)
  }),.SDcols=newcols[[i]] ])

给出了类似的结果。我只是用这种方式编写它来说明如何使用data.table语法。你可以再次避免使用方括号和.SD

lapply(
  indcols,
  function(i) sapply(
    new[, newcols[[i]], with=FALSE],
    function(x){
      z<-sum(x)
      rbind(z,z/length(x))
    }))

但无论如何:如果你能掌握基础变量,只需使用table