Вземете фиктивни (T/F) променливи от списък, вграден в рамката с данни

Имам 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  ...

person Etienne Low-Décarie    schedule 12.11.2012    source източник


Отговори (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)
}
person Ricardo Saporta    schedule 12.11.2012
comment
Добър. Предполагам, че трябва да направите тази функция(t) функция(g) - person Etienne Racine; 13.11.2012
comment
Не, просто първият ви отговор имаше малка правописна грешка, където function(t) g %in% V всъщност трябваше да бъде function(g) g %in% V. Съжалявам за объркването. Друго объркване е, че аз не съм собственикът на въпроса :) - person Etienne Racine; 13.11.2012

Ето 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,...,Zbut 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]
person mnel    schedule 12.11.2012

Благодарение на въведеното тук, създадох и решение за изискване (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
person Etienne Low-Décarie    schedule 16.11.2012