Grouping key/value columns into single rows

130 views Asked by At

I'm trying to take key-value combinations and put all the values on the same row as the keys. I'm pretty sure I knew how to do this at one point (I think with data.table) and I've been looking at the usual suspects reshape2, tidyr, data.table, etc, but I can't seem to figure out a simple solution.

key1 = c(1,1,1,1,2,2,2,2)
key2 = c("A","A","B","B","C","C","D","D")
value = c("a","b","c","d","e","f","g","h")
kvframe = data.frame(key1,key2,value)

#  key1 key2 value
#1    1    A     a
#2    1    A     b
#3    1    B     c
#4    1    B     d
#5    2    C     e
#6    2    C     f
#7    2    D     g
#8    2    D     h

Here's what I would like the table to look like:

# key1 key2 value1 value2
#    1    A      a      b
#    1    B      c      d
#    2    C      e      f
#    2    D      g      h

Most of the key1,key2 pairs have the same number of corresponding values, but not all of them do. I'm hoping for a solution with the number of value columns equal to the max number of values for any given key set, where any pairs with fewer values are filled in with NA.

1

There are 1 answers

2
akrun On BEST ANSWER

You need a sequence column for the group 'key1/key2'.

library(data.table) # v1.9.5+
setDT(kvframe)[, Seq := paste0('value', 1:.N), by = .(key1, key2)] # generate Seq
dcast(kvframe, key1 + key2  ~Seq, value.var = 'value') # cast from long to wide

#   key1 key2 value1 value2
#1:    1    A      a      b
#2:    1    B      c      d
#3:    2    C      e      f
#4:    2    D      g      h

Or using reshape from base R

 d1 <- transform(kvframe, Seq=ave(seq_along(value),
              key1, key2, FUN=seq_along))
 reshape(d1, idvar=c('key1', 'key2'), timevar='Seq', direction='wide')
 #  key1 key2 value.1 value.2
 #1    1    A       a       b
 #3    1    B       c       d
 #5    2    C       e       f
 #7    2    D       g       h

Or

library(tidyr)
spread(d1, Seq, value)