0

Suppose I have a data frame called DF:

options(stringsAsFactors = F)

letters <- list("A", "B", "C", "D")
numbers <- list(list(1,2), 1, 1, 2)
score <- list(.44, .54, .21, .102)

DF <- data.frame(cbind(letters, numbers, score))

Note that all columns in the data frame are of class "list".

Also, take a look at the structure: DF$numbers[1] is also a list

I'm trying to UNLIST each column.

 DF$letters <- unlist(DF$letters)
 DF$score <- unlist(DF$score)
 DF$numbers <- unlist(DF$numbers)

However, because, DF$numbers[1] is also a list, I'm thrown back this error:

 Error in `$<-.data.frame`(`*tmp*`, numbers, value = c(1, 2, 1, 1, 2)) : 
   replacement has 5 rows, data has 4

Is there a way that I can unlist the whole column, and keep the values cells like DF$numbers[1] as a character vector like c(1,2) or 1,2?

Ideally I would like DF to look something like this, where the individual values in the number column are still of type int:

 letters   numbers   score
  A         1,2       .44
  B         1         .54
  C         1         .21
  D         2         .102

The goal is to then write the data frame to a csv file.

Sheila
  • 2,438
  • 7
  • 28
  • 37

2 Answers2

1

You can apply unlist to each individual element of the column numbers instead of the whole column:

DF$numbers <- lapply(DF$numbers, unlist)

DF
#  letters numbers value
#1       A    1, 2 0.440
#2       B       1 0.540
#3       C       1 0.210
#4       D       2 0.102

DF$numbers[1]
#[[1]]
#[1] 1 2

Or paste the elements as a single string if you want an atomic vector column:

DF$numbers <- sapply(DF$numbers, toString)
DF
#  letters numbers value
#1       A    1, 2  0.44
#2       B       1  0.54
#3       C       1  0.21
#4       D       2 0.102

DF$numbers[1]
#[1] "1, 2"

class(DF$numbers)
# [1] "character"
Psidom
  • 209,562
  • 33
  • 339
  • 356
  • Hi! That's a great tip, however DF$numbers is still in list format. When I try and unlist() that DF$numbers <- unlist(lapply(DF$numbers,unlist)), I'm thrown back the same error i described in my original post – Sheila May 16 '17 at 20:22
  • The *numbers* column will be list if the elements contain vector like `c(1,2)`. If don't want it to be a list, you can paste the elements as a string as `DF$numbers <- sapply(DF$numbers, toString)`. – Psidom May 16 '17 at 20:25
  • I see, Yes, I would like the elements of the list to be of type int. Using your initial approach with lapply, when I try to write DF using write.csv I'm thrown back an error " Error in write.table(DF, "test.csv", col.names = NA, sep = ",", dec = ".", : unimplemented type 'list' in 'EncodeElement'" – Sheila May 16 '17 at 20:29
  • If your purpose is to write the data frame to csv file, then it makes sense to convert the column to character columns before hand. Did you try the second approach? – Psidom May 16 '17 at 20:33
  • Yes, however I would like the numbers to still be of type int – Sheila May 16 '17 at 20:40
  • I am not sure what you mean. In a csv file, all the numbers are strings. Maybe `DF$numbers <- sapply(DF$numbers, function(x) paste0(as.integer(unlist(x)), collapse = ","))`? – Psidom May 16 '17 at 20:44
  • You can save *dataframe* as objects, if you want to keep the data type information. See [here](http://stackoverflow.com/questions/19967478/how-to-save-data-file-into-rdata) – Psidom May 16 '17 at 20:46
0

You can do:

DF$letters <- unlist(DF$letters)
DF$value <- unlist(DF$value)
DF$numbers <- unlist(as.character(DF$numbers))

This returns:

DF
  letters numbers value
1       A c(1, 2) 0.440
2       B       1 0.540
3       C       1 0.210
4       D       2 0.102
Lamia
  • 3,845
  • 1
  • 12
  • 19