2015-11-06 118 views
0

我有一個數據集,其中包含個人和年份的觀察值。我想將數據分離到每個人。在每個人中,我想每年都適合一些模型。然後,我想要將每個單獨年份模型的AIC分數編譯爲data.frame,然後將其保存在列表中。從for()循環填充的data.frame中重複條目

我使用iris數據創建了一個可重複使用的示例。我使用嵌套for循環將數據分爲個人(i)和年(j)。

問題:有些物種有三年的數據(例如瀨沙和雜色),而維吉尼卡只有一年的數據(2014年)。

當物種data.frames被添加到列表中時,少於三年的物種包含前幾年的重複記錄。正如下面的結果可以看出,list[[3]]應包含數據的單一排在2014年弗吉尼亞物種和從2011年的雜色也沒有重複記錄和2012年

是否有可能有data.frames不同數量的列表行?

我歡迎任何改善嵌套for循環的建議。我懷疑有更好的方法來做到這一點,也許與dplyr

head(iris) 

#Add year to iris to reproduce problem 
iris$Year <- c(rep(c("2011", "2012", "2013"), len = 100), rep("2014", 50)) 

#Make list of species of index and empty list 
Sp <- unique(iris$Species) 
ResultsList <- list() 

#make Results table 
AICTbl <- data.frame(Species = as.character(), AIC_1 = numeric(), AIC_2 = numeric(), stringsAsFactors=FALSE) 

#run nested for loop 
for(i in 1:length(Sp)) { 
    SpeciesDat <- subset(iris, Species == Sp[i]) 

    for(j in 1:length(unique(SpeciesDat$Year))) { 
    Years <- unique(SpeciesDat$Year) 
    datasub <- SpeciesDat[SpeciesDat$Year == Years[j] , ] 

    #Make the animal Year rowID 
    AICTbl[j,1] = paste(Sp[i] , Years[j], sep = "_") 

    mod.1 <- lm(Sepal.Length ~ Sepal.Width, data = datasub) 
    AICTbl[j,2] = AIC(mod.1) 

    mod.2 <- lm(Sepal.Length ~ Petal.Length, data = datasub) 
    AICTbl[j,3] = AIC(mod.2) 

      } 
     ResultsList[[i]] <- AICTbl 
    } 


> ResultsList 
[[1]] 
     Species AIC_1  AIC_2 
1 setosa_2011 3.649775 21.089619 
2 setosa_2012 4.512392 2.280987 
3 setosa_2013 4.638183 19.718576 

[[2]] 
      Species AIC_1 AIC_2 
1 versicolor_2013 25.30007 18.93356 
2 versicolor_2011 26.57170 15.22717 
3 versicolor_2012 21.62511 11.82291 

[[3]] 
      Species AIC_1 AIC_2 
1 virginica_2014 89.88263 32.91367 
2 versicolor_2011 26.57170 15.22717 
3 versicolor_2012 21.62511 11.82291 

加成 感謝您的建議和改進@jeremycg。以下補充是一個延續,儘管您已經回答了OP。任何額外的想法,將不勝感激。

下面列出了我的真實代碼的一個不可重現的示例,其中顯示了適用於每個IndID年的5個模型之一。

datasub %>% group_by(IndID, Year) %>% 
    do(m.1 = try(nls(NSD ~ (asym/(1+exp((t1 - J_day_new)/dur1)))+(-asym/(1+exp((t2 - J_day_new)/dur2))), 
      control=nls.control(maxiter = 1000, warnOnly=TRUE), algorithm="port", 
        start=c(asym=0.75*max(datasub$NSD), t1=135, t2=285, dur1=2, dur2=2), 
       data = datasub),TRUE) 

    ) %>% 
    mutate(m.1 = AIC(m.1)) 

如果我.替換datasub(數據幀)我得到以下錯誤。

Error in UseMethod("logLik") : 
    no applicable method for 'logLik' applied to an object of class "try-error" 
+0

要用兩個變量分割一個數據框,使用split(數據集,數據集[,c('var1','var1')])',它會使你的代碼變短。當然,列表可以具有不同行數的數據幀。列表是一個通用向量。例如:'df1 < - data.frame(1:3,4:6); df2 < - data.frame(1:5,6:10); l1 < - list(df1,df2)'。它適用於R. –

回答

1

你在這裏有一個非常複雜的代碼。我們可以使用dplyr來簡化它。如果您正在按組進行大量建模,​​則可能還需要查看broom軟件包。

這是你的代碼的一個較短的版本:

library(dplyr) 
iris %>% group_by(Species, Year) %>% 
     do(mod1 = lm(Sepal.Length ~ Sepal.Width, data = .), 
      mod2 = lm(Sepal.Length ~ Petal.Length, data = .)) %>% 
     mutate(mod1 = AIC(mod1), mod2 = AIC(mod2)) 

Source: local data frame [7 x 4] 
Groups: <by row> 

    Species Year  mod1  mod2 
     (fctr) (chr)  (dbl)  (dbl) 
1  setosa 2011 3.649775 21.089619 
2  setosa 2012 4.512392 2.280987 
3  setosa 2013 4.638183 19.718576 
4 versicolor 2011 26.571702 15.227167 
5 versicolor 2012 21.625111 11.822912 
6 versicolor 2013 25.300073 18.933559 
7 virginica 2014 89.882627 32.913666 

如果你確實想在一個列表中,您可將以上輸出到z,然後按品種分爲:

split(z, list(z$Species)) 
+0

謝謝。很有幫助。我一直在閱讀「。」但不知道你是否也可以提供額外的信息。使用'data = iris'將會爲每個物種年帶來相同的答案。據我所知,「。」用於調用與group_by分組的數據。當我將您的代碼應用到我使用nls函數的真正問題時,出現錯誤。用「替換我的數據框。「產生在OP。 –

+1

中進一步描述的錯誤,看起來你的一些'nls'調用失敗了,'AIC'正在從'try'的錯誤消息中被調用,你可以嘗試替換AIC(m。 1)用:'ifelse(class(m.1)==「try-error」,NA,AIC(m.1))'是的,你對這些點是正確的 - 在'%>%'之後,前面的東西被用作下一個函數的第一個參數,如果你想把它放在其他地方(例如'data = .'),你需要用一個圓點來表示這個,並且檢查一下[broom + dplyr vignette](https:// cran.r-project.org/web/packages/broom/vignettes/broom_and_dplyr.html) - 它會幫助你在線下 – jeremycg