R How to write a variable number of rows with same attributes in one row by creating new columns

StackOverflow https://stackoverflow.com/questions/23563753

  •  18-07-2023
  •  | 
  •  

Question

I have a huge data frame consisting of about 7.000 rows, each with a specific ID-number, which can occur several times (up to 16). In a simple version it looks like this:

ID <- factor(c("a","a","a","a","b","c","c","d","d","d"))
var1 <-c(10,20,10,40,30,20,20,10,10,40)
var2 <-c(5,5,4,8,9,2,4,7,1,3)

df <- data.frame(ID,var1,var2)
df
    ID var1 var2
1   a   10    5
2   a   20    5
3   a   10    4
4   a   40    8
5   b   30    9
6   c   20    2
7   c   20    4
8   d   10    7
9   d   10    1
10  d   40    3

Now I would like to form my data.frame in the way that the attributes with the same ID are written in one row, so that I have (in this case) up to 4 columns for var1 and 4 columns for var2, as the most frequent ID occurs four times (ID a). All other spaces, for which no data exists, should be filled with .

The resulting data.frame should look like this:

    ID  var1_1 var1_2 var1_3 var1_4 var2_1 var2_2 var2_3 var2_4
1   a      10     20     10     40     5      5      4      8
2   b      30     NA     NA     NA     9      NA     NA     NA
3   c      20     20     NA     NA     2      4      NA     NA
4   d      10     10     40     NA     7      1      3      NA

My idea was to solve this via tapply

df2 <- tapply (df$var1,df$ID,paste)

which gives me the following output:

$a
[1] "10" "20" "10" "40"
$b
[1] "30"
$c
[1] "20" "20"
$d
[1] "10" "10" "40"

If I convert this to a dataframe it looks like this:

> df3 <-as.data.frame(df2)  
> df3     

             df3  
a 10, 20, 10, 40  
b             30  
c         20, 20  
d     10, 10, 40   

The problem is that I now have only one variable instead of the desired four. (or actually eight, concerning those resulting from var2, which I would have handled like var1 and combined via merge in a final step).

I then tried strsplit() but this does not help me to solve the Problem, as I don´t get the different columns and I don't no how to add the NA values.

Maybe there is a simple function to restructure the data.frame? I would be very lucky if someone could help me.

Was it helpful?

Solution

Add a secondary ID and use reshape:

Here's what our second ID should look like (actually, this is generally known as your "time" variable)

with(df, ave(rep(1, nrow(df)), ID, FUN = seq_along))
#  [1] 1 2 3 4 1 1 2 1 2 3

With that, base R's underappreciated reshape takes care of this with ease:

df$ID2 <- with(df, ave(rep(1, nrow(df)), ID, FUN = seq_along))
reshape(df, direction = "wide", idvar="ID", timevar="ID2")
#   ID var1.1 var2.1 var1.2 var2.2 var1.3 var2.3 var1.4 var2.4
# 1  a     10      5     20      5     10      4     40      8
# 5  b     30      9     NA     NA     NA     NA     NA     NA
# 6  c     20      2     20      4     NA     NA     NA     NA
# 8  d     10      7     10      1     40      3     NA     NA

Alternatively, with "reshape2":

library(reshape2)
df$ID2 <- with(df, ave(rep(1, nrow(df)), ID, FUN = seq_along))
dfL <- melt(df, id.vars=c("ID", "ID2"))
dcast(dfL, ID ~ variable + ID2, value.var="value")
#   ID var1_1 var1_2 var1_3 var1_4 var2_1 var2_2 var2_3 var2_4
# 1  a     10     20     10     40      5      5      4      8
# 2  b     30     NA     NA     NA      9     NA     NA     NA
# 3  c     20     20     NA     NA      2      4     NA     NA
# 4  d     10     10     40     NA      7      1      3     NA

OTHER TIPS

ncolVar1 <- max(rowSums(table(ID, var1)))
ncolVar2 <- max(rowSums(table(ID, var2)))

fun <- function(x, maxcol) {ifelse(length(x)==maxcol, list(x), list(c(x, rep(NA, maxcol-length(x)))))}

cbind(do.call(rbind, tapply(var1, ID, fun, ncolVar1)), do.call(rbind, tapply(var2, ID, fun, ncolVar2)))

#    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# a   10   20   10   40    5    5    4    8
# b   30   NA   NA   NA    9   NA   NA   NA
# c   20   20   NA   NA    2    4   NA   NA
# d   10   10   40   NA    7    1    3   NA
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top