从嵌入在数据框中的列表中获取虚拟(T / F)变量

时间:2012-11-12 20:05:54

标签: r dataframe reduction

我有一个data.frame,其中的单元格包含一系列术语。

我希望为该列表中的每个术语生成一个新变量,表明该术语在该给定单元格中是否存在。

我在data.frame中有多个不同的这样的实例,并且不知道列表组成的修道院。

示例data.frame

require(plyr)

example<-data.frame(groups=letters)

example<-adply(example,
               1,
               function(x) data.frame(value=t(list(sample(LETTERS, 4)))))

    groups      value
1      a F, Y, N, X
2      b N, D, B, Y
3      c W, J, S, U
4      d I, S, N, A
5      e S, Z, Y, A
6      f O, R, J, A

由此,我希望获得

group     F     N     ...
1     A  TRUE  TRUE  ...
2     B FALSE  TRUE  ...
3     C FALSE FALSE  ...

3 个答案:

答案 0 :(得分:3)

根据您的要求,此处为功能形式

示例

myMatrix <- checkValues(example, makeMatrix=TRUE)
myMatrix

#        A     B     C     D     E     F  ...
#   a FALSE FALSE FALSE FALSE FALSE FALSE ...
#   b FALSE FALSE FALSE FALSE FALSE  TRUE ...
#   c FALSE FALSE FALSE  TRUE FALSE FALSE ...
#   d FALSE  TRUE FALSE  TRUE FALSE FALSE ...
#   e  TRUE FALSE FALSE FALSE FALSE FALSE ...
#   .
#   .
#   .


功能

checkValues <- function(myDF, makeMatrix=FALSE, makeUnique=TRUE, sort=TRUE)  {
  # myDF should be a data frame containing columns `group` and `value`
  # if `makeMatrix` is T, will convert the list into a long matrix
  # `makeUnique`  and  `sort` only apply if `makeMatrix` is TRUE
  #   (otherwise, they are ignored)

  res<- 
  lapply(myDF$value, function(L1) 
      t(sapply(myDF$value, function(L2) L1 %in% L2 ))
  )

  # Make the names purtty 
  names(res) <- myDF$group

  for (i in 1:length(res))
      dimnames(res[[i]]) <- list(myDF$group, myDF$value[[i]])

  # convert the list to matrix
  if (makeMatrix)  {  
    res <- do.call(cbind, res)

    # remove duplicates, if required
    if (makeUnique) 
      res <- res[, !duplicated(res, MARGIN=2)]

    # order columns, if required
    if (sort)
      res <- res[, order(colnames(res))]
  }

  return(res)
}

答案 1 :(得分:2)

以下是data.tablereshape2解决方案

library(data.table)
EX <- data.table(example)

data.table(dcast(EX[,list(value = unlist(value)),by=groups], groups~value))[,lapply(.SD, is.na),by = groups]

解释步骤

  • EX[,list(value = unlist(value)),by=groups]以长格式创建data.table(列表值成为单个列

  • dcast(....)使用columns A ,..., Z but is an ugly mess of NA`值转换为宽格式

  • data.table()[,lapply(.SD), by = groups]按组遍历所有列并转换为逻辑值。 by不是必需的(并且会稍微慢一些),但是你必须以不同的方式处理群组列,我不会感到困扰。


如果您事先知道可用元素

如果您事先知道列名是什么,那么这是使用dcast

的简单替代方法

显然,你会用可能值的向量替换LETTERS

EX[, setNames(as.list(LETTERS%in% unlist(value)), LETTERS),by = groups]

答案 2 :(得分:1)

感谢此处的输入,我还创建了一个require(plyr)解决方案。

不如两种解决方案都优雅,但出于某种原因,我仍然觉得通过plyr解决方案更容易阅读。

创建一个可以生成单个虚拟变量的函数

single.value.to.dummy<-function(value.name, list.of.lists){
  ldply(.data=list.of.lists,
        function(list.element){ dummy<-value.name %in% list.element
                              names(dummy)<-value.name
                              return(dummy)
        })}

将此功能应用于列表列表中的所有唯一值

list.of.lists.to.dummy<-function(list.of.lists){

#Extract unique values
  value.names<-unique(unlist(list.of.lists))

  dummy.frame<-llply(.data=value.names,
                      function(value.name){
                        dummy<-single.value.to.dummy(value.name, list.of.lists)
                        return(dummy)})

  return(data.frame(dummy.frame))
}

example<-cbind(example, list.of.lists.to.dummy(example$value))


groups      value     T     S     P     O     U     A     C     B     N     V     D     H     Y     F
1      a T, S, P, O  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
2      b U, A, C, B FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE
3      c S, N, V, D FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE
4      d H, Y, F, X FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE
5      e M, Y, O, X FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
6      f Y, A, K, S FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE