Если я вас правильно понимаю, вам нужно компактное и быстрое решение, которое можно применять сразу ко всему диапазону от 1 до n видов.
Сначала я бы reshape
данные в длинном формате, а затем установите NA
, используя by
sp*
, если это элемент c(0, NA)
для каждого site
.В-третьих, мы можем дополнительно reshape
вернуться к исходному большому формату.
tmp <- reshape(dat, varying=list(3:ncol(dat)), v.names="sp", idvar=1:2, direction="long")
tmp <- do.call(rbind, by(tmp, tmp[c("site", "time")], function(x)
if (all(x$sp %in% c(0, NA))) cbind(x[-4], sp=NA) else x))
dat <- reshape(tmp, timevar="time", idvar=c("x", "site"), direction="wide", sep="")
dat
# x site sp1 sp2
# 1.1.1 1 1 1 0
# 2.1.1 2 1 1 0
# 3.1.1 3 1 <NA> 1
# 10.1.1 10 1 0 <NA>
# 4.2.1 4 2 <NA> 1
# 5.2.1 5 2 <NA> <NA>
# 6.2.1 6 2 <NA> <NA>
# 7.3.1 7 3 <NA> 0
# 8.3.1 8 3 <NA> 1
# 9.3.1 9 3 <NA> <NA>
Если мы хотим большей скорости, мы могли бы использовать melt
и dcast
для процесса преобразования из data.table
пакет, который почти удваивает скорость.Код немного меняется:
library(data.table)
tmp <- melt(dat, id.vars=c("x", "site"), variable.name="time", value.name="sp")
tmp <- do.call(rbind, by(tmp, tmp[c("site", "time")], function(x)
if (all(x$sp %in% c(0, NA))) cbind(x[-4], sp=NA) else x))
dcast(tmp, x + site ~ time, value.var="sp")
Чтобы проверить, работают ли оба, увеличьте набор данных до количества видов Zoraptera, равного 28, и снова запустите код:
set.seed(42)
n <- 28 - 2
add <- setNames(as.data.frame(
replicate(n, factor(sample(c(1, 0, NA), nrow(dat), replace=TRUE)))),
paste0("sp", 3:(n + 2)))
dat <- cbind(dat, add)
Данные
# I'd rather use a neutral name for the data, since `table` is a function name, see `?table`
dat <- structure(list(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), site = c(1,
1, 1, 2, 2, 2, 3, 3, 3, 1), sp1 = structure(c(2L, 2L, 3L, 3L,
1L, 1L, 3L, 3L, 3L, 1L), .Label = c("0", "1", "na"), class = "factor"),
sp2 = structure(c(1L, 1L, 2L, 2L, 3L, 3L, 1L, 2L, 3L, 3L), .Label = c("0",
"1", "na"), class = "factor")), class = "data.frame", row.names = c(NA,
-10L))
# first thing to do is make proper NAs!
levels(dat$sp1) <- levels(dat$sp2) <- c(0, 1, NA)