R:使用apply family而不是for-loops

时间:2018-01-10 01:52:06

标签: r for-loop apply

首先是一些样本数据

yr1 <- sample(0:1, 365, replace = T)
yr2 <- sample(0:1, 365, replace = T)
yr3 <- sample(0:1, 365, replace = T)
yr4 <- sample(0:1, 365, replace = T)

value <- c(yr1, yr2, yr3, yr4)

yr <- rep(2000:2003, each = 365)
doy <- rep(1:365, times = 4)

foo <- as.data.frame(cbind(value, yr, doy))

foo包含3列。第1列的任意值为1或0.第2列包含年份,第3列包含一年中的某一天(365天)

我有两个载体,包括朱利安时代的开始和结束日期

start <- c(258, 258,258,258)
mid <- c(279, 281,285,288)
end <- c(286, 295,300,320)

range.val <- as.data.frame(cbind(start, mid, end))
range.val$yr<- c(2000, 2001, 2002, 2003)

range.val给了我julian天,我必须在foo之间总结每年的值。

例如,对于2000年,我需要从258天到279天,然后从279到286总和foo$value。同样,           2001年,总和foo$value从258到281,然后从281到295。

我还需要计算每年这些指数之间最长连续出现1的长度。

我这样做了:

for(yr in 2000:2003){

    range.sub <- range.val[range.val$yr == yr,]
    foo.sub <- foo[foo$yr == yr,]

    sum.1 <- sum(foo.sub[range.sub$start:range.sub$mid,"value"])
    sum.2 <- sum(foo.sub[range.sub$mid:range.sub$end,"value"])

    length.1 <- rle(foo.sub[range.sub$start:range.sub$mid,"value"]) 
    max.spell.length <-  max(sort(length.1$lengths, , decreasing = TRUE))

    length.1 <- rle(foo.sub[range.sub$mid:range.sub$start,"value"]) 
    max.spell.length1 <-  max(sort(length.1$lengths, , decreasing = TRUE))
}

在我不断努力减少使用for循环的过程中,我想知道是否可以使用其他函数来缩短上面的代码。

1 个答案:

答案 0 :(得分:1)

这是使用dplyr的解决方案。

创建一个联合数据框&amp;指示每个yr-doy组合是在范围1(从开始到中间),范围2(从中到开),还是两者都没有。

heroes

对于每年范围X的总值,过滤范围&amp;按年总结:

library(dplyr)

df <- left_join(foo, range.val, by = "yr")
df <- df %>%
  mutate(in.range1 = doy >= start & doy <= mid,
         in.range2 = doy >= mid & doy <= end)
# Note: I'm not sure if the ranges are supposed to be inclusive on both ends, but you
# should be able to change that easily

对于最长的1次,过滤范围&amp;对每年的值进行df.sum.1 <- df %>% filter(in.range1) %>% #change to in.range2 for mid-end group_by(yr) %>% summarise(value = sum(value)) > df.sum.1 # A tibble: 4 x 2 yr value <dbl> <int> 1 2000 12 2 2001 12 3 2002 10 4 2003 10 。请注意,我们应首先过滤值== 1,否则如果有更长的0,则可能会改为:

rle

(为了重现性,样本数据是使用df.spell.length1 <- df %>% filter(in.range1) %>% #change to in.range2 for mid-end group_by(yr) %>% arrange(doy) %>% do(data.frame(unclass(rle(.$value)))) %>% filter(values == 1) %>% filter(lengths == max(lengths)) %>% unique() > df.spell.length1 # A tibble: 4 x 3 # Groups: yr [4] yr lengths values <dbl> <int> <int> 1 2000 7 1 2 2001 3 1 3 2002 3 1 4 2003 3 1 生成的。)