我有一个 R 时间序列数据表,其中包含年份、位置、物种和人口计数的列。
我一直在试图找到一种方法来删除存在多个(三个)连续人口计数为零的时间序列(或只是年份)。我很惊讶还没有一个函数可以做到这一点,但我还没有找到任何东西。
例如,以下是在 R 中生成的示例数据:
dt <- data.table(
Species = c(rep("A", 6), rep("B", 6), rep("C", 6)),
Location = c("X", "X", "X", "X", "Y", "Y", "X", "X", "X", "X", "X", "X", "Y", "Y", "Y", "Y", "Y", "Y"),
Year = c(2010, 2011, 2012, 2013, 2010, 2011, 2010, 2011, 2012, 2013, 2014, 2015, 2010, 2011, 2012, 2013, 2014, 2015),
Count = c(3, 4, 10, 1, 5, 0, 3, 0, 0, 0, 2, 1, 0, 10, 11, 14, 12, 9)
)
根据这些数据,我预计位置 X 的物种 B 将被删除,但其他物种将被保留。
我一直在尝试编写自己的函数,但没有成功,我最终编写了一个函数来创建 TRUE/FALSE 列,在每个位置-物种组合的 for 循环中使用它,然后过滤掉时间序列包含其中的 TRUE 值。但它不起作用,我认为我让它变得比需要的更复杂。
consecutive_zeros <- function(dt, Count) {
Count <- dt$Count
for (i in 1:nrow(dt)-2) {
consecutive_zeros <- dt$Count[i] + dt$Count[i+1] + dt$Count[i+2] == 0
dt$consecutive_zeros[i] <- consecutive_zeros
}
return(dt)
}
我确信有人之前一定需要做类似的事情...任何建议将不胜感激!
在
dplyr
中,您可以创建一个临时变量(three0
)然后过滤:
dt %>%
mutate(three0 = n() <= 2,
.by = c(Species, Count)) %>%
filter(!any(!three0),
.by = c(Species, Location)) %>%
select(-three0)
输出:
Species Location Year Count
1: A X 2010 3
2: A X 2011 4
3: A X 2012 10
4: A X 2013 1
5: A Y 2010 5
6: A Y 2011 0
7: C Y 2010 0
8: C Y 2011 10
9: C Y 2012 11
10: C Y 2013 14
11: C Y 2014 12
12: C Y 2015 9
dt[,
if (any(frollapply(Count, FUN = is_all0, n = 3, fill = -1) > 0)) NULL else .SD,
by = .(Species, Location)]
# Species Location Year Count
# <char> <char> <num> <num>
# 1: A X 2010 3
# 2: A X 2011 4
# 3: A X 2012 10
# 4: A X 2013 1
# 5: A Y 2010 5
# 6: A Y 2011 0
# 7: C Y 2010 0
# 8: C Y 2011 10
# 9: C Y 2012 11
# 10: C Y 2013 14
# 11: C Y 2014 12
# 12: C Y 2015 9
有很多方法可以实现检查三个数字是否全为 0 的函数。以下是一些示例:
is_all0 <- \(x) max(x) == 0
is_all0 <- \(x) all(x == 0)
is_all0 <- \(x) Reduce(bitwOr, x) == 0