我目前正在研究“长”形式的多态分析数据集(每个人观察一行;每个人最多重复测量5次)。
这个想法是每个人都可以在时变的状态变量 s = 1, 2, 3, 4
的水平上反复转换。我拥有的所有其他变量(此处cohort
)都固定在任何给定的id
内。
经过一些分析,我需要根据访问状态的具体顺序,以“宽”形式重塑数据集。以下是初始长数据的示例:
dat <- read.table(text = "
id cohort s
1 1 2
1 1 2
1 1 1
1 1 4
2 3 1
2 3 1
2 3 3
3 2 1
3 2 2
3 2 3
3 2 3
3 2 4",
header=TRUE)
最终的“宽”数据集应考虑到访问状态的特定个别序列,记录到新创建的变量s1
,s2
,s3
,s4
,s5
,其中s1
是个人访问的第一个州,依此类推。
根据上面的例子,宽数据集看起来像:
id cohort s1 s2 s3 s4 s5
1 1 2 2 1 4 0
2 3 1 1 3 0 0
3 2 1 2 3 3 4
我尝试使用reshape()
,并专注于转置s
,但没有预期的结果。实际上,我对R功能的了解非常有限。你能给出任何建议吗?谢谢。
谢谢大家的帮助,如果可以,我有一个相关的问题。特别是当长时间观察每个人并且跨越状态的转换很少时,以这种替代方式重新构造初始样本dat
非常有用:
id cohort s1 s2 s3 s4 s5 dur1 dur2 dur3 dur4 dur5
1 1 2 1 4 0 0 2 1 1 0 0
2 3 1 3 0 0 0 2 1 0 0 0
3 2 1 2 3 4 0 1 1 2 1 0
在实践中,现在s1
- s5
是不同的访问状态,dur1
- dur5
花费在每个相应的不同访问状态状态。
您能否帮助实现这一数据结构?我认为在使用dur
之前,有必要在中间样本中创建所有s
- 和reshape()
- 变量。否则也许可以直接采用-reshape2-
?
答案 0 :(得分:5)
dat <- read.table(text = "
id cohort s
1 1 2
1 1 2
1 1 1
1 1 4
2 3 1
2 3 1
2 3 3
3 2 1
3 2 2
3 2 3
3 2 3
3 2 4",
header=TRUE)
df <- data.frame(
dat,
period = sequence(rle(dat$id)$lengths)
)
wide <- reshape(df, v.names = "s", idvar = c("id", "cohort"),
timevar = "period", direction = "wide")
wide[is.na(wide)] = 0
wide
给出:
id cohort s.1 s.2 s.3 s.4 s.5
1 1 1 2 2 1 4 0
5 2 3 1 1 3 0 0
8 3 2 1 2 3 3 4
然后使用以下行给出您的姓名:
names(wide) <- c('id','cohort', paste('s', seq_along(1:5), sep=''))
# id cohort s1 s2 s3 s4 s5
# 1 1 1 2 2 1 4 0
# 5 2 3 1 1 3 0 0
# 8 3 2 1 2 3 3 4
如果您在sep=''
语句中使用wide
,则无需重命名变量:
wide <- reshape(df, v.names = "s", idvar = c("id", "cohort"),
timevar = "period", direction = "wide", sep='')
我怀疑有一些方法可以避免创建period
变量并避免直接在NA
语句中替换wide
,但我还没有想到这些。
答案 1 :(得分:3)
确定...
library(plyr)
library(reshape2)
dat2 <- ddply(dat,.(id,cohort), function(x)
data.frame(s=x$s,name=paste0("s",seq_along(x$s))))
dat2 <- ddply(dat2,.(id,cohort), function(x)
dcast(x, id + cohort ~ name, value.var= "s" ,fill= 0)
)
dat2[is.na(dat2)] <- 0
dat2
# id cohort s1 s2 s3 s4 s5
# 1 1 1 2 2 1 4 0
# 2 2 3 1 1 3 0 0
# 3 3 2 1 2 3 3 4
这似乎对吗?我承认第一个ddply
并不优雅。
答案 2 :(得分:3)
试试这个:
library(reshape2)
dat$seq <- ave(dat$id, dat$id, FUN = function(x) paste0("s", seq_along(x)))
dat.s <- dcast(dat, id + cohort ~ seq, value.var = "s", fill = 0)
给出了这个:
> dat.s
id cohort s1 s2 s3 s4 s5
1 1 1 2 2 1 4 0
2 2 3 1 1 3 0 0
3 3 2 1 2 3 3 4
如果您不介意只使用1,2,...,5作为列名,那么您可以将ave
行缩短为:
dat$seq <- ave(dat$id, dat$id, FUN = seq_along)
关于稍后添加的第二个问题,请尝试以下操作:
library(plyr)
dur.fn <- function(x) {
r <- rle(x$s)$length
data.frame(id = x$id[1], dur.value = r, dur.seq = paste0("dur", seq_along(r)))
}
dat.dur.long <- ddply(dat, .(id), dur.fn)
dat.dur <- dcast(dat.dur.long, id ~ dur.seq, c, value.var = "dur.value", fill = 0)
cbind(dat.s, dat.dur[-1])
给出:
id cohort s1 s2 s3 s4 s5 dur1 dur2 dur3 dur4
1 1 1 2 2 1 4 0 2 1 1 0
2 2 3 1 1 3 0 0 2 1 0 0
3 3 2 1 2 3 3 4 1 1 2 1