R reshape, restructure dataframe by chunks

心已入冬 提交于 2019-12-04 11:46:37

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

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

I like Brian's answer better but here's a way to do it with the base package. Pretty ugly though in my opinion.

Your dataframe:

DF
        id    sex v1 v2 v3 v4 v5 v6
    1 ID_1   male A1 A2 A3 B1 B2 B3
    2 ID_2 female A1 A2 A3 B1 B2 B3

Code

DFa<-subset(DF, select=c(1:5))
DFb<-subset(DF, select=c(1:2, 6:8))
colnames(DFb)<-colnames(DFa)
DF<-as.data.frame(rbind(DFa,DFb))
rownames(DF)<-1:nrow(DF)
DF[order(DF$id),] 

How about:

> dat <- data.frame(id=c("id1","id2"),gender=c("m","f"),a.1=1:2,a.2=1:2,a.3=1:2,b.1=3:4,b.2=3:4,b.3=3:4)
> dat1 <- dat[,-(3:5)]
> dat2 <- dat[,-(6:8)]
> names(dat1)[3:5] <- c("v1","v2","v3")
> names(dat2)[3:5] <- c("v1","v2","v3")
> 
> dat1$test <- "b"
> dat2$test <- "a"
> result <- rbind(dat1,dat2)
> dat
   id gender a.1 a.2 a.3 b.1 b.2 b.3
1 id1      m   1   1   1   3   3   3
2 id2      f   2   2   2   4   4   4
> result
   id gender v1 v2 v3 test
1 id1      m  3  3  3    b
2 id2      f  4  4  4    b
3 id1      m  1  1  1    a
4 id2      f  2  2  2    a
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!