2012-07-12 157 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