I have some data in long form that looks like this:
dat1 = data.frame(
id = rep(LETTERS[1:2], each=4),
value = 1:8
)
In table form:
id value
A 1
A 2
A 3
A 4
B 5
B 6
B 7
B 8
And I want it to be in short form and look like this:
dat1 = data.frame(A = 1:4, B = 5:8)
In table form:
A B
1 5
2 6
3 7
4 8
Now I could solve this by looping with cbind()
and stuff, but I want to use some kind of reshape/melt function as these are the best way to do this kind of thing I think.
However, from spending >30 minutes trying to get melt()
and reshape()
to work, reading answers on SO, it seems that these functions requires the id.var
to be set. Now, it is plainly redundant for this kind of thing, so how do I do what I want to do without having to resort to some kind of looping?
I'm pretty sure this has been answered before. Anyway, unstack
is convenient in this particular case with equal group size:
unstack(dat1, form = value ~ id)
# A B
# 1 1 5
# 2 2 6
# 3 3 7
# 4 4 8
Solution below works when there are different numbers of As and Bs. For equal counts, unstack
works great and with less code (Henrik's answer).
# create more general data (unbalanced 'id')
each <- c(4,2,3)
dat1 = data.frame(
id = unlist(mapply(rep, x = LETTERS[1:length(each)], each = each)),
value = 1:sum(each),
row.names = 1:sum(each) # to reproduce original row.names
)
tab <- table(dat1$id)
dat1$timevar <- unlist(sapply(tab, seq))
library(reshape2)
dcast(dat1, timevar ~ id )[-1]
initial data:
id value
1 A 1
2 A 2
3 A 3
4 A 4
5 B 5
6 B 6
7 C 7
8 C 8
9 C 9
result:
A B C
1 1 5 7
2 2 6 8
3 3 NA 9
4 4 NA NA
Here's a base R approach to consider. It uses the lengths
function, which I believe was introduced in R 3.2.
x <- split(dat1$value, dat1$id)
as.data.frame(lapply(x, function(y) `length<-`(y, max(lengths(x)))))
# A B C
# 1 1 5 7
# 2 2 6 8
# 3 3 NA 9
# 4 4 NA NA