2012-07-12 103 views
0

我正在开发一个审查因变量,用于生存分析。我的目标是找出某人在调查中回答问题的最后时间(“时间”)(例如,“q.time”被编码为“1”,“q.time + 1”和q后续时间编码为“0”)。疑难解答ddply()脚本

通过这个逻辑,最后回答的问题应该被编码为“1”(q.time)。未回答的第一个问题(q.time + 1)应该编码为“0”。第一个问题未回答后的所有问题都应编码为“NA”。然后我想从我的数据集中删除DV = NA的所有行。

一位非常慷慨的同事帮助我开发了下面的代码,但他现在休假了,需要更多的爱心。代码如下:

library(plyr) # for ddply 
library(stats) # for reshape(...) 
# From above 
dat <- data.frame( 
    id=c(1, 2, 3, 4), 
    q.1=c(1, 1, 0, 0), 
    q.2=c(1, 0, 1, 0), 
    dv.1=c(1, 1, 1, 1), 
    dv.2=c(1, 1, 0, 1)) 
# From above 
    long <- reshape(dat, 
       direction='long', 
       varying=c('q.1', 'q.2', 'dv.1', 'dv.2')) 
    ddply(long, .(id), function(df) { 
# figure out the dropoff time 
answered <- subset(df, q == 1) 
last.q = max(answered$time) 
subs <- subset(df, time <= last.q + 1) 
# set all the dv as desired 
new.dv <- rep(last.q,1) 
if (last.q < max(df$time)) new.dv <- c(0,last.q) 
subs$dv <- new.dv 
subs 
}) 

不幸的是,这会产生错误消息:

"Error in `$<-.data.frame`(`*tmp*`, "dv", value = c(0, -Inf)) : 
replacement has 2 rows, data has 0" 

任何想法?问题似乎位于“rep”命令中,但我是R的新手。非常感谢!

UPDATE:请参阅以下解释,然后参照后续问题

您好,我完全跟着你,真的很感谢你了,帮我出时间。我回到我的数据中,并编写了一个虚拟Q,其中所有受访者都具有“1”的值 - 但是,发现错误真的可能在哪里。在我的真实数据集中,我有30个问题(即30个长格式)。我改变了数据集经过这么肯定q == 1对所有ID的变量,该错误信息更改为说

"Error in `$<-.data.frame`(`*tmp*`, "newvar", value = c(0, 29)) : replacement has 2 rows, data has 31" 

如果问题是与分配给潜艇的行数,则是错误的根源从未来...

subs <- subset(df, time <= last.q + 1) 

$时间< = last.q + 1 $是行数设定为等于值last.q + 1?

更新2:什么,理想情况下,我想我的新变量看起来像!

id time q dv 
1 1 1 1 
1 2 1 1 
1 3 1 1 
1 4 1 1 
1 5 0 0 
1 6 0 NA 
2 1 1 1 
2 2 1 1 
2 3 0 0 
2 4 0 NA 
2 5 0 NA 
2 6 0 NA 

请注意,“Q”可之间变化为“0”或“1”随着时间的推移(参见ID = 1的观察在时间= 2),但由于生存分析的性质, “dv”不能。我需要做的是创建一个变量,查找“q”在“1”和“0”之间变化的最后时间,然后进行相应审查。第4步之后,我的数据应该是这样的:

id time q dv 
1 1 1 1 
1 2 1 1 
1 3 1 1 
1 4 1 1 
2 1 1 1 
2 2 1 1 
2 3 0 0 
+0

一个小问题,'reshape2'软件包不包含'reshape',这是'stats' pacakge。 – mnel 2012-07-12 02:06:34

+0

谢谢!修正:) – roody 2012-07-12 13:01:02

回答

0

首先,在信贷到期时给予贷款,下面的代码不是我的。它是与另一位非常慷慨的同事(和工程师)合作产生的,他帮助我解决了我的问题(几个小时!)。

我认为其他分析师的任务是从调查数据中构建一个被审查的变量,可能会发现这个代码很有用,所以我正在通过解决方案。

library(plyr) 
#A function that only selects cases before the last time "q" was coded as "1" 
slicedf <- function(df.orig, df=NULL) { 
if (is.null(df)) { 
    return(slicedf(df.orig, df.orig)) 
} 
if (nrow(df) == 0) { 
    return(df) 
} 
target <- tail(df, n=1) 
    #print(df) 
    #print('--------') 
    if (target$q == 0) { 
     return(slicedf(df.orig, df[1:nrow(df) - 1, ])) 
    } 
if (nrow(df.orig) == nrow(df)) { 
    return(df.orig) 
} 
return(df.orig[1:(nrow(df) + 1), ]) 
} 
#Applies function to the dataset, and codes over any "0's" before the last "1" as "1" 
long <- ddply(long, .(id), function(df) { 
df <- slicedf(df) 
if(nrow(df) == 0) { 
return(df) 
} 
q <- df$q 
if (tail(q, n=1) == 1) { 
df$q <- rep(1, length(q)) 
} else { 
df$q <- c(rep(1, length(q) - 1), 0) 
} 
return(df) 
}) 

感谢网上所有评论过您的耐心和帮助的人。

+0

很高兴你有它的伴侣!不要忘记标记你的问题如答复。 – 2012-07-13 00:01:38

5

.(id)在plyr相当于

> dum<-split(long,long$id) 
> dum[[4]] 
    id time q dv 
4.1 4 1 0 1 
4.2 4 2 0 1 

你的问题是在你的第4分。你参考

answered <- subset(df, q == 1) 

在你的功能。这是一个空集,因为没有dum[[4]]$q回吐值1

如果你只是想忽略这个分裂然后像

ans<-ddply(long, .(id), function(df) { 
# figure out the dropoff time 
answered <- subset(df, q == 1) 
if(length(answered$q)==0){return()} 
last.q = max(answered$time) 
subs <- subset(df, time <= last.q + 1) 
# set all the dv as desired 
new.dv <- rep(last.q,1) 
if (last.q < max(df$time)) new.dv <- c(0,last.q) 
subs$dv <- new.dv 
subs 
}) 

> ans 
    id time q dv 
1 1 1 1 2 
2 1 2 1 2 
3 2 1 1 0 
4 2 2 0 1 
5 3 1 0 2 
6 3 2 1 2 

东西会是这个结果

5

简而言之:这个错误是因为当id == 4没有q == 1


一个很好的方法来检查怎么在这里上是分别改写功能,手动测试ddply正在处理每个数据块。

所以首先重写代码是这样的:

myfun <- function(df) { 
    # figure out the dropoff time 
    answered <- subset(df, q == 1) 
    last.q = max(answered$time) 
    subs <- subset(df, time <= last.q + 1) 
    # set all the dv as desired 
    new.dv <- rep(last.q,1) 
    if (last.q < max(df$time)) new.dv <- c(0,last.q) 
    subs$dv <- new.dv 
    subs 
} 
ddply(long, .(id), myfun) 

这仍然给出当然是一个错误,但至少现在我们可以手动检查什么ddply在做什么。

ddply(long, .(id), myfun)真正含义是:

  1. 采取所谓的长
  2. (为每个不同的ID之一)创造了多个子集dataframes的
  3. 应用功能myfun每个子集数据帧
  4. 重新组装数据帧结果合并为单个数据帧

因此,让我们尝试做手动ly ddply自动执行的操作。

> myfun(subset(long, id == 1)) 
     id time q dv 
    1.1 1 1 1 2 
    1.2 1 2 1 2 
    > myfun(subset(long, id == 2)) 
     id time q dv 
    2.1 2 1 1 0 
    2.2 2 2 0 1 
    > myfun(subset(long, id == 3)) 
     id time q dv 
    3.1 3 1 0 2 
    3.2 3 2 1 2 
    > myfun(subset(long, id == 4)) 
    Error in `$<-.data.frame`(`*tmp*`, "dv", value = c(0, -Inf)) : 
     replacement has 2 rows, data has 0 
    In addition: Warning message: 
    In max(answered$time) : no non-missing arguments to max; returning -Inf 
    > 

所以好像错误是从哪儿ddply应用功能ID == 4

步骤来现在,让我们的代码的功能之外,所以我们可以检查每个块。

> ################# 
> # set the problem chunk to "df" so we 
> # can examine what the function does 
> # step by step 
> ################ 
> df <- subset(long, id == 4) 
> 
> ################### 
> # run the bits of function separately 
> ################### 
> answered <- subset(df, q == 1) 
> answered 
[1] id time q dv 
<0 rows> (or 0-length row.names) 
> last.q = max(answered$time) 
Warning message: 
In max(answered$time) : no non-missing arguments to max; returning -Inf 
> last.q 
[1] -Inf 
> subs <- subset(df, time <= last.q + 1) 
> subs 
[1] id time q dv 
<0 rows> (or 0-length row.names) 
> # set all the dv as desired 
> new.dv <- rep(last.q,1) 
> new.dv 
[1] -Inf 
> if (last.q < max(df$time)) new.dv <- c(0,last.q) 
> subs$dv <- new.dv 
Error in `$<-.data.frame`(`*tmp*`, "dv", value = c(0, -Inf)) : 
    replacement has 2 rows, data has 0 
> subs 
[1] id time q dv 
<0 rows> (or 0-length row.names) 
> 

所以你得到的错误来自subs$dv <- new.dv因为new.dv有二个长度(即两个值 - (0,-Inf)),但子$ DV是长度为0这将不会是如果dv是一个简单的向量,但由于它在sub数据框中,其列全都有两行,那么sub $ dv也必须有两行。

原因sub有零行是因为没有q == 1id == 4

对于id == 4最终数据帧应该没有任何内容吗?你的问题的答案真的取决于你想要在id没有q==1的情况下发生什么。请告诉我们,我们可以帮助您解决代码问题。

UPDATE:

的错误,你得到的是因为subs$dv有31个值,并在new.dv有两个值。

在R中,当您尝试将较长的矢量分配给较短的矢量时,它总会抱怨。

> test <- data.frame(a=rnorm(100),b=rnorm(100)) 
> test$a <- rnorm(1000) 
Error in `$<-.data.frame`(`*tmp*`, "a", value = c(-0.0507065994549323, : 
    replacement has 1000 rows, data has 100 
> 

但是当你分配一个短向量较长向量,如果较短不是偶数倍的时间越长载体只会抱怨。 (例如3不走均匀,放入100)

> test$a <- rnorm(3) 
Error in `$<-.data.frame`(`*tmp*`, "a", value = c(-0.897908251650798, : 
    replacement has 3 rows, data has 100 

但是,如果你尝试这样做,它不会抱怨,因为2进入100均匀。

> test$a <- rnorm(2) 
> 

试试这个:

> length(test$a) 
[1] 100 
> length(rnorm(2)) 
[1] 2 
> test$a <- rnorm(2) 
> length(test$a) 
[1] 100 
> 

什么是它做的是静静地重复较短的载体,填补了更长的载体。

再次,你怎样解决这个错误(即让两个向量长度相同)将取决于你想要达到的目标。您是否缩短了new.dv,或者缩短了subs$dv

+0

你好 - 我完全跟着你,真的很感激你帮助我的时间。我回到我的数据中,并编写了一个虚拟Q,其中所有受访者都具有“1”的值 - 但是,发现错误真的可能在哪里。在我的真实数据集中,我有30个问题(即30个长格式)。在我修改了数据集后,为了确保所有的id变量都保持为q == 1,错误信息变为 – roody 2012-07-12 05:43:02

+0

......抱歉!印刷困难。我在自己的部分写了上面我的问题的其余部分。 – roody 2012-07-12 05:52:49

+0

我很抱歉如此呆板......从概念上讲,我真正需要的是一个变量,其中所有问题的答案都是直到最后编码为“1”,最后一个+1编码为“0”。回答你原来的问题,我不需要担心编码的情况下,从q从不== 1的ID,并且它们从数据集中被丢弃是很好的。那么我认为答案是我想new.dv更短?如果它需要是29的长度,以便进行29次比较,询问“这个q值是否为< | > | =时间+ 1?”在所有时间点为所有ID,“那么也许我应该让sub.dv更长? – roody 2012-07-12 13:53:21