3

我有一个 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  ...
4

3 回答 3

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)
}
于 2012-11-12T20:18:33.120 回答
2

这是一个data.table解决reshape2方案

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(....)转换为具有columnsA ,...,Z but is an ugly mess ofNA` 值的宽格式

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


如果您事先知道可用元素

如果您事先知道列名是什么,那么这是使用的简单替代方法dcast

显然,您将替换LETTERS为可能值的向量。

EX[, setNames(as.list(LETTERS%in% unlist(value)), LETTERS),by = groups]
于 2012-11-12T23:19:24.320 回答
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
于 2012-11-16T15:10:28.767 回答