我想根据其他列的内容创建一个新列,并在每个主题的新列中分隔所需的值。
在下面的示例中,我希望能够从中获得:
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
答案 0 :(得分:2)
您也可以使用data.table
。如果您要在new
two
中创建OBS
列(假设数据按var
排序)。
library(data.table)
使用paste
nm1 <- paste0("newOBS", 0:1)
使用setDT
将data.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