R新主题基于主题的其他列的内容

时间:2014-12-07 17:30:31

标签: r

我想根据其他列的内容创建一个新列,并在每个主题的新列中分隔所需的值。

在下面的示例中,我希望能够从中获得:

Subject = c(1,1,1,1,2,2,2,2)
var = c(0,1,2,3,0,1,2,3)
OBS = c(5,10,15,20,2,4,5,7)
df1 = data.frame(Subject,var,OBS)

到这个

Subject = c(1,1,1,1,2,2,2,2)
var = c(0,1,2,3,0,1,2,3)
OBS = c(5,10,15,20,2,4,5,7)
newOBS0 = c(5,5,5,5,2,2,2,2)
df2 = data.frame(Subject,var,OBS,newOBS0)

换句话说,我想创建一个新列,它只包含主题= 1和主题= 2的var = 0的OBS。然后,我将能够扩展它,例如变量= 1并得到这个:

Subject = c(1,1,1,1,2,2,2,2)
var = c(0,1,2,3,0,1,2,3)
OBS = c(5,10,15,20,2,4,5,7)
newOBS0 = c(5,5,5,5,2,2,2,2)
newOBS1 = c(10,10,10,10,4,4,4,4)
df3 = data.frame(Subject,var,OBS,newOBS0,newOBS1)

第二种情况:var列由字符而不是数字组成。此外,两个科目的变化顺序已经改变。

Subject = c(1,1,1,1,2,2,2,2)
var = c('b','a','d','c','a','b','c','d')
OBS = c(10,5,20,15,2,4,5,7)
df1 = data.frame(Subject,var,OBS)
df1$var <- paste(df1$var)

希望任何人都可以提供帮助。

Sincerily,

YKL

2 个答案:

答案 0 :(得分:2)

您也可以使用data.table。如果您要在new two中创建OBS列(假设数据按var排序)。

library(data.table)

使用paste

创建列名
nm1 <- paste0("newOBS", 0:1)

使用setDTdata.frame转换为data.table。将nm1分配给前两个colnames,即OBS。每个主题OBS[1] OBS[2]by=Subject

setDT(df1)[,(nm1):=list(OBS[1],OBS[2]) , by=Subject][]
#    Subject var OBS nm1 newOBS0 newOBS1
#1:       1   0   5   5       5      10
#2:       1   1  10   5       5      10
#3:       1   2  15   5       5      10
#4:       1   3  20   5       5      10
#5:       2   0   2   2       2       4
#6:       2   1   4   2       2       4
#7:       2   2   5   2       2       4
#8:       2   3   7   2       2       4

对于所有unique值。逻辑与上述类似。唯一的区别是,我们正在OBS为每个Subject创建整个值的列。

 nm1 <- paste0('newOBS', unique(df1$var))
 setDT(df1)[, (nm1) := as.list(OBS), by=Subject][]
 #    Subject var OBS newOBS0 newOBS1 newOBS2 newOBS3
 #1:       1   0   5       5      10      15      20
 #2:       1   1  10       5      10      15      20
 #3:       1   2  15       5      10      15      20
 #4:       1   3  20       5      10      15      20
 #5:       2   0   2       2       4       5       7
 #6:       2   1   4       2       4       5       7
 #7:       2   2   5       2       4       5       7
 #8:       2   3   7       2       4       5       7

或使用dplyr

 library(dplyr)
 df1 %>% 
     group_by(Subject) %>%
     mutate(newOBS1=OBS[1], newOBS2=OBS[2])

更新

假设var列不是数字且未订购

 set.seed(295)
 df1$var <- sample(letters[1:5], 8, replace=TRUE)

 #create the data.table and use `setkey` that
 #will also order the columns `Subject`, `var`
 setkey(setDT(df1), Subject, var)
 #create the column names
 nm1 <- paste0('newOBS', c('ca', 'db'))
 #nm1 <- paste0('newOBS', c('aa', 'bb')) #for the updated post

 df1[, (nm1):= list(OBS[1], OBS[2]), by=Subject][]
 #      Subject var OBS newOBSca newOBSdb
 #1:       1   c  10       10        5
 #2:       1   d   5       10        5
 #3:       1   e  15       10        5
 #4:       1   e  20       10        5
 #5:       2   a   4        4        2
 #6:       2   b   2        4        2
 #7:       2   c   5        4        2
 #8:       2   c   7        4        2

答案 1 :(得分:1)

假设您可以对数据进行排序,使得每个主题的观察结果都是连续的(没有丢失的数据),您可以这样做

df1<-df1[order(df1$Subject, df1$var),]  #ensure sort order
transform(df1,
   newOBS0=ave(OBS, Subject, FUN=function(x) x[1]),
   newOBS1=ave(OBS, Subject, FUN=function(x) x[2]))

#   Subject var OBS newOBS0 newOBS1
# 1       1   0   5       5      10
# 2       1   1  10       5      10
# 3       1   2  15       5      10
# 4       1   3  20       5      10
# 5       2   0   2       2       4
# 6       2   1   4       2       4
# 7       2   2   5       2       4
# 8       2   3   7       2       4

如果您想对所有OBS值执行此操作,您可能会根据重塑来考虑它。您可以将宽数据合并回原始数据。例如

wide<-reshape(df1, direction="wide", timevar="var",idvar="Subject")
merge(df1, wide)

#   Subject var OBS OBS.0 OBS.1 OBS.2 OBS.3
# 1       1   0   5     5    10    15    20
# 2       1   1  10     5    10    15    20
# 3       1   2  15     5    10    15    20
# 4       1   3  20     5    10    15    20
# 5       2   0   2     2     4     5     7
# 6       2   1   4     2     4     5     7
# 7       2   2   5     2     4     5     7
# 8       2   3   7     2     4     5     7