Working across sub-lists with apply() functions

﹥>﹥吖頭↗ 提交于 2019-12-14 03:22:48

问题


I am trying to the bootstrap the proportional occurrence of diet items for 7 individuals and calculate a sd()

Lets say there are 9 prey items on the menu.

Diet <- c("Beaver","Bird", "Bobcat","Coyote", "Deer", "Elk",
    "Porcupine", "Raccoon",   "SmMamm")

And that these prey items are eaten by 7 different individuals of the same species

Inds <- c("P01", "P02", "P03", "P04", "P05", "P06", "P07")

My goal is the bootstrap the proportional occurrence of each diet item for each individual.
The loop below generates five diets for each individual (each diet containing N = 20 feedings) that were sampled with replacement. The data are stored as a list of the individuals, each of which contains a list of the sample diets.

BootIndDiet <- list()
IndTotboot <- list()
for(i in Inds){
    for(j in 1:5){
        BootIndDiet[[j]] <- prop.table(table(sample(Diet, 20 ,replace = T)))
                        }
            IndTotboot[[i]] <- BootIndDiet
            }

Below I have included the first two diets of individual P07 as an example of the loop results

$P07
$P07[[1]]

   Beaver      Bird    Bobcat      Deer       Elk 
     0.05      0.15      0.20      0.10      0.15 
Porcupine   Raccoon    SmMamm 
     0.15      0.15      0.05 

$P07[[2]]

   Beaver      Bird    Bobcat    Coyote      Deer 
     0.15      0.10      0.20      0.05      0.05 
      Elk Porcupine   Raccoon    SmMamm 
     0.05      0.20      0.10      0.10 

I then want to calculate the sd() of the proportional of each species for each individual. Equivocally, for each individual (P01 - P07) I want the sd() of the proportional occurrence of each prey species across the 5 diets.

While my loop above runs, I suspect there is a better way (possibly using the boot() function) that avoids lists...

While I have only included 5 samples (bootstraps) for each individual here, I hope to generate 10000.

Suggestions on a different strategy or how to apply sd() across sub-lists is greatly appreciated.


回答1:


I'd try to obtain an array (instead of a nested list) in this way:

   IndTotboot <-array(replicate(5*length(Inds),prop.table(table(sample(as.factor(Diet), 20 ,replace = T))),simplify=T), dim=c(length(Diet),5,length(Inds)), dimnames=list(Diet,NULL,Inds))

With replicate you can execute an expression a given number of times and store the result as an array (if possible). I added an as.factor before Diet to make sure that the table takes trace of every Diet (even the ones with a 0 frequency).

The IndTotboot object obtained is a 3-dimensional array where the first index indicates the Diet, the second the bootstrap replications and the third the Inds. From there you can use apply in the standard way.

Edit:

If you try str(IndTotboot) you get:

    > str(IndTotboot)
     num [1:9, 1:5, 1:7] 0.1 0.15 0.15 0.1 0.1 0.1 0.15 0.05 0.1 0.15 ...
     - attr(*, "dimnames")=List of 3
       ..$ : chr [1:9] "Beaver" "Bird" "Bobcat" "Coyote" ...
       ..$ : NULL
       ..$ : chr [1:7] "P01" "P02" "P03" "P04" ...

The first line is the most important. It says num [1:9, 1:5, 1:7], which means a 9x5x7 array. The rest indicates the dimnames, the names of the dimensions, which is a list. They are the generalization of the rownames and the colnames for a matrix.

Now, to obtain the sd for every Diet and Inds you just use apply:

    apply(IndTotboot,MARGIN=c(1,3),sd)



回答2:


Following may be useful:

dd = data.frame(sapply(IndTotboot, function(x)x))

maindf = data.frame(Var1=as.character(), Freq=as.numeric())

for(rr in 1:nrow(dd)) for (cc in 1:ncol(dd)){
        maindf= merge(maindf, data.frame(dd[rr,cc]), all=TRUE)
}

> head(maindf, 10)
     Var1 Freq
1  Beaver 0.05
2  Beaver 0.10
3  Beaver 0.15
4  Beaver 0.20
5  Beaver 0.30
6    Bird 0.05
7    Bird 0.10
8    Bird 0.15
9    Bird 0.20
10   Bird 0.25


with(maindf, tapply(Freq, Var1, sd))
    Beaver       Bird     Bobcat     Coyote        Elk  Porcupine    Raccoon     SmMamm       Deer 
0.09617692 0.09354143 0.09354143 0.09354143 0.09354143 0.06454972 0.07905694 0.10801234 0.07905694 

For each individual:

counter=1
for (cc in 1:ncol(dd)){
    maindf = data.frame(Var1=as.character(), Freq=as.numeric())
    for(rr in 1:nrow(dd)){
        maindf= merge(maindf, data.frame(dd[rr,cc]), all=TRUE)
    }
    cat("\nFor individual number: ",counter,"\n"); counter=counter+1
    print(with(maindf, tapply(Freq, Var1, sd)))
}


For individual number:  1 
    Beaver       Bird     Bobcat     Coyote        Elk  Porcupine    Raccoon     SmMamm       Deer 
0.05000000 0.07637626 0.05000000 0.06454972 0.03535534 0.05000000 0.05000000 0.07637626 0.05000000 

For individual number:  2 
    Beaver       Bird     Bobcat     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm 
0.05000000 0.10801234 0.03535534 0.05000000 0.09128709         NA 0.03535534 0.07637626 0.13149778 

For individual number:  3 
    Beaver       Bird     Bobcat     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm 
0.03535534 0.07637626 0.12583057 0.03535534 0.03535534 0.06454972 0.05000000 0.10606602 0.06454972 

For individual number:  4 
    Beaver       Bird     Bobcat     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm 
0.05000000 0.05000000 0.05000000 0.03535534 0.10408330 0.07905694 0.05000000 0.03535534 0.10408330 

For individual number:  5 
    Beaver       Bird     Bobcat     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm 
0.05000000 0.03535534 0.05000000 0.03535534 0.03535534 0.03535534 0.05000000 0.05000000 0.07071068 

For individual number:  6 
    Beaver     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm     Bobcat       Bird 
0.10000000 0.07637626 0.03535534 0.05000000 0.07071068 0.03535534 0.05000000 0.10408330 0.10606602 

For individual number:  7 
    Beaver       Bird     Bobcat     Coyote       Deer        Elk  Porcupine    Raccoon     SmMamm 
0.03535534 0.05000000 0.10408330 0.07637626 0.05000000 0.13228757 0.07637626 0.03535534 0.05000000 

For individual+species:

maindf = data.frame(Var1=as.character(), Freq=as.numeric(), ind=as.numeric())
counter=1
for (cc in 1:ncol(dd)){
    for(rr in 1:nrow(dd)){
        maindf= merge(maindf, cbind(data.frame(dd[rr,cc]),ind=counter), all=TRUE)
    }
    counter=counter+1
}
with(maindf, tapply(Freq, list(Var1,ind), sd))

                   1          2          3          4          5          6          7
Beaver    0.05000000 0.05000000 0.03535534 0.05000000 0.05000000 0.10000000 0.03535534
Bird      0.07637626 0.10801234 0.07637626 0.05000000 0.03535534 0.10606602 0.05000000
Bobcat    0.05000000 0.03535534 0.12583057 0.05000000 0.05000000 0.10408330 0.10408330
Coyote    0.06454972 0.05000000 0.03535534 0.03535534 0.03535534 0.07637626 0.07637626
Elk       0.03535534         NA 0.06454972 0.07905694 0.03535534 0.05000000 0.13228757
Porcupine 0.05000000 0.03535534 0.05000000 0.05000000 0.05000000 0.07071068 0.07637626
Raccoon   0.05000000 0.07637626 0.10606602 0.03535534 0.05000000 0.03535534 0.03535534
SmMamm    0.07637626 0.13149778 0.06454972 0.10408330 0.07071068 0.05000000 0.05000000
Deer      0.05000000 0.09128709 0.03535534 0.10408330 0.03535534 0.03535534 0.05000000


来源:https://stackoverflow.com/questions/25595786/working-across-sub-lists-with-apply-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!