4

This question is related to: Count values in the columns separated by ":"

I have following list of tables:

ll = structure(list(`001` = structure(c(1L, 2L, 1L, 1L), .Dim = 4L, .Dimnames = structure(list(
    c("Active", "Com.Tent", "Perform", "Sport_Well")), .Names = ""), class = "table"), 
    `002` = structure(c(1L, 2L, 5L, 2L), .Dim = 4L, .Dimnames = structure(list(
        c("Active", "Com.Tent", "Perform", "Sport_Well")), .Names = ""), class = "table"), 
    `003` = structure(c(2L, 1L, 4L), .Dim = 3L, .Dimnames = structure(list(
        c("Active", "Com.Tent", "Perform")), .Names = ""), class = "table")), .Names = c("001", 
"002", "003"))

ll

$`001`

    Active   Com.Tent    Perform Sport_Well 
         1          2          1          1 

$`002`

    Active   Com.Tent    Perform Sport_Well 
         1          2          5          2 

$`003`

  Active Com.Tent  Perform 
       2        1        4 

How can I convert this to following data frame:

user_id  Active Com.tent Perform  Sport_Well
001     1       2       1       1
002     1       2       5       2
003     2       1       4       0
1
  • Thanks everyone for your answers. You will agree this is an interesting problem. Commented Oct 13, 2014 at 14:09

6 Answers 6

4

rbindlist from the data.table package has a fill parameter which can handle varying columns in an rbinded list:

library(data.table)
tmp <- rbindlist(lapply(ll, function(x) as.data.frame.list(x)), fill=TRUE)
tmp$user_id <- names(ll)

##    Active Com.Tent Perform Sport_Well user_id
## 1:      1        2       1          1     001
## 2:      1        2       5          2     002
## 3:      2        1       4         NA     003
Sign up to request clarification or add additional context in comments.

Comments

4

I found a simple method:

> library(reshape2)
> dcast(melt(ll), L1~Var1)
   L1 Active Com.Tent Perform Sport_Well
1 001      1        2       1          1
2 002      1        2       5          2
3 003      2        1       4         NA

Comments

3

Here's a very manual approach (but one that is generally efficient):

## Get the unique column names needed
colNames <- unique(unlist(lapply(ll, names)))

## Create an empty matrix to hold the data
M <- matrix(0, nrow = length(ll), ncol = length(colNames), 
            dimnames = list(names(ll), colNames))

## Match the matrix column names with the required values
matches <- lapply(ll, function(x) match(names(x), colNames))

## Use matrix indexing to replace the required values
M[cbind(rep(sequence(nrow(M)), sapply(matches, length)),
        unlist(matches))] <- unlist(ll)
M
#     Active Com.Tent Perform Sport_Well
# 001      1        2       1          1
# 002      1        2       5          2
# 003      2        1       4          0

The result is a matrix, so if you wanted a data.frame, you would need as.data.frame.

Comments

2

You could also use unnest from tidyr

 devtools::install_github("hadley/tidyr")
 library(tidyr)
 unnest(lapply(ll, as.data.frame.list), user_id)
 #  user_id Active Com.Tent Perform Sport_Well
 #1     001      1        2       1          1
 #2     002      1        2       5          2
 #3     003      2        1       4         NA

Comments

2

All the other answers work just fine, I just wanted to add the base R solution

max.length  <- max(sapply(ll, length))
ll <- lapply(ll, function(x) {length(x) <- max.length; x})
d <- data.frame(do.call(rbind, ll))
d$user_id <- rownames(d)

If you want to replace NAs by zeros like in your sample output, d[is.na(d)] <- 0 as you suggested yourself :)

2 Comments

For the last part of replacing NA with 0, why do you not do: d[is.na(d)]=0 ?
Hmm you're right.. I know this works for a matrix but I thought I had run into problems when doing that with a data frame before but I probably just remembered wrongly. thanks:)
1

dplyr::rbind_all also works.

library(dplyr)    
cbind(user_id = names(ll), rbind_all(lapply(ll, as.data.frame.list)))
#   user_id Active Com.Tent Perform Sport_Well
# 1     001      1        2       1          1
# 2     002      1        2       5          2
# 3     003      2        1       4         NA

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.