Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R reshape, restructure dataframe by chunks

I am trying to reshape a dataframe:

Currently it looks like this:

ID   | Gender |A1 | A2 | A3 | B1 | B2 | B3
ID_1 | m      | 3 | 3  | 3  | 2  | 3  | 2 
ID_2 | f      | 1 | 1  | 1  | 4  | 4  | 4

I want to have something like:

 ID   | Gender | A1 | A2 | A3
 ID_1 | m      | 3  | 3  |  3   <- this would be columns A1 - A3 for ID 1
 ID_1 | m      | 2  | 2  |  2   <- this would be columns B1 - B3 for ID 1
 ID_2 | f      | 1  | 1  |  1   <- this would be columns A1 - A3 for ID 2
 ID_2 | f      | 4  | 4  |  4   <- this would be columns B1 - B3 for ID 2

(A1 and B1 / A2 and B2 are the same variables (with regard to the content), so for example: A1 and B1 would be both variables for the result of Test 1 and A2 and B2 both contain the result of Test 2. So in order to evaluate it I need all the result of Test1 in one column and all of Test 2 in another column. I tried to solve this with "melt", but it only melts down the dataframe one by one, not as chunks. (since I need to keep the first 2 columns the way they are and only rearrange the last 4 columns, but as chunks of three) Any other ideas? Thanks!

like image 868
Elisa Avatar asked Dec 10 '25 18:12

Elisa


2 Answers

One liner using reshape from base R.

reshape(dat, varying = 3:8, idvar = 1:2, direction = 'long', drop=FALSE, 
   timevar = 'Test')

           ID Gender Test Test1 Test2 Test3
ID_1.m.A ID_1      m    A    A1    A2    A3
ID_2.f.A ID_2      f    A    A1    A2    A3
ID_1.m.B ID_1      m    B    B1    B2    B3
ID_2.f.B ID_2      f    B    B1    B2    B3
like image 78
Ramnath Avatar answered Dec 12 '25 17:12

Ramnath


As @Andrie said, the first step is melting the data with your given columns (ID and gender). Your problem, as you say, is identifying what columns then "go together". Here is one approach, originally encoding that information in column names, and then pulling it out from there.

First some dummy data

dat <- data.frame(ID=c("ID_1", "ID_2"), Gender=c("m","f"), 
  Test1.A = "A1", Test2.A = "A2", Test3.A = "A3",
  Test1.B = "B1", Test2.B = "B2", Test3.B = "B3", stringsAsFactors=FALSE)

Note that I've named the columns with a name that systematically indicates which test and which group it is part of.

> dat
    ID Gender Test1.A Test2.A Test3.A Test1.B Test2.B Test3.B
1 ID_1      m      A1      A2      A3      B1      B2      B3
2 ID_2      f      A1      A2      A3      B1      B2      B3

Using the reshape2 package

library("reshape2")

Melt the data, and then take the variable column which has two pieces of information in it (test and group), and split those two bits of info into two separate columns.

dat.m <- melt(dat, id.vars=c("ID", "Gender"))
dat.m <- cbind(dat.m, colsplit(dat.m$variable, "\\.", names=c("Test", "Group")))

Now it is easy to cast since the test and the group are separate.

dcast(dat.m, ID+Gender+Group~Test)

Which gives

> dcast(dat.m, ID+Gender+Group~Test)
    ID Gender Group Test1 Test2 Test3
1 ID_1      m     A    A1    A2    A3
2 ID_1      m     B    B1    B2    B3
3 ID_2      f     A    A1    A2    A3
4 ID_2      f     B    B1    B2    B3
like image 31
Brian Diggs Avatar answered Dec 12 '25 16:12

Brian Diggs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!