【发布时间】:2018-02-02 13:12:22
【问题描述】:
我正在分析存储疾病模拟模型输出数据的大型表(300 000 - 500 000 行)。在该模型中,景观中的动物会感染其他动物。例如,在下图的示例中,动物 a1 会感染景观中的每一个动物,并且感染会从一个动物转移到另一个动物,形成感染“链”。
在下面的示例中,我想获取存储有关每个动物信息的表格(在下面的示例中,table = allanimals)并仅删除有关动物的信息 d2 的感染链(我已用绿色突出显示 d2 的感染链),因此我可以计算该感染链的平均栖息地价值。
虽然我的 while 循环有效,但当表存储数十万行并且链有 40-100 个成员时,它就像糖蜜一样慢。
关于如何加快速度的任何想法?希望有一个tidyverse 的解决方案。我知道我的示例数据集“看起来足够快”,但我的数据确实很慢......
示意图:
以下示例数据的所需输出:
AnimalID InfectingAnimal habitat
1 d2 d1 1
2 d1 c3 1
3 c3 c2 3
4 c2 c1 2
5 c1 b3 3
6 b3 b2 6
7 b2 b1 5
8 b1 a2 4
9 a2 a1 2
10 a1 x 1
示例代码:
library(tidyverse)
# make some data
allanimals <- structure(list(AnimalID = c("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8",
"b1", "b2", "b3", "b4", "b5", "c1", "c2", "c3", "c4", "d1", "d2", "e1", "e2",
"e3", "e4", "e5", "e6", "f1", "f2", "f3", "f4", "f5", "f6", "f7"),
InfectingAnimal = c("x", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a2", "b1",
"b2", "b3", "b4", "b3", "c1", "c2", "c3", "c3", "d1", "b1", "e1", "e2", "e3",
"e4", "e5", "e1", "f1", "f2", "f3", "f4", "f5", "f6"), habitat = c(1L, 2L, 1L,
2L, 2L, 1L, 3L, 2L, 4L, 5L, 6L, 1L, 2L, 3L, 2L, 3L, 2L, 1L, 1L, 2L, 5L, 4L,
1L, 1L, 1L, 1L, 4L, 5L, 4L, 5L, 4L, 3L)), .Names = c("AnimalID",
"InfectingAnimal", "habitat"), class = "data.frame", row.names = c(NA, -32L))
# check it out
head(allanimals)
# Start with animal I'm interested in - say, d2
Focal.Animal <- "d2"
# Make a 1-row data.frame with d2's information
Focal.Animal <- allanimals %>%
filter(AnimalID == Focal.Animal)
# This is the animal we start with
Focal.Animal
# Make a new data.frame to store our results of the while loop in
Chain <- Focal.Animal
# make a condition to help while loop
InfectingAnimalInTable <- TRUE
# time it
ptm <- proc.time()
# Run loop until you find an animal that isn't in the table, then stop
while(InfectingAnimalInTable == TRUE){
# Who is the next infecting animal?
NextAnimal <- Chain %>%
slice(n()) %>%
select(InfectingAnimal) %>%
unlist()
NextRow <- allanimals %>%
filter(AnimalID == NextAnimal)
# If there is an infecting animal in the table,
if (nrow(NextRow) > 0) {
# Add this to the Chain table
Chain[(nrow(Chain)+1),] <- NextRow
#Otherwise, if there is no infecting animal in the table,
# define the Infecting animal follows, this will stop the loop.
} else {InfectingAnimalInTable <- FALSE}
}
proc.time() - ptm
# did it work? Check out the Chain data.frame
Chain
【问题讨论】:
-
object 'InfectingAnimal' not found -
谢谢,我修正了代码!它现在应该可以工作了。
-
只是为了确定,每只动物只能受到另一种动物的影响,这样
NextRow每次只有一行(或者如果结束则为零)? -
是的,没错——每只动物在“allanimals”表中只有一行,并且只能被一种动物感染。然而,一只动物可以感染不止一个其他个体。感谢您为此工作!
-
查看
data.tree和data.tree::Transverse函数。我现在没有时间玩它,但我认为这可能会让你到达那里。
标签: r performance while-loop tidyverse