R -- 使用二进制 df1 对 df2 中的测量值进行分组,然后查看每个组中的任何测量值是否满足特定条件以输出新的二进制 df3

R -- use binary df1 to group measurements in df2, then see if any measurements within each group meet a specific condition to output a new binary df3

我正在尝试将一些旧的 Excel 函数转换为 R,识别昆虫爆发的最后一步对我来说是最具挑战性的。输入将包括两个时间序列数据集:报告多棵树爆发或未爆发情况的二进制数据集,以及代表相同树木和相同时间尺度的低或高生长的树环宽度指数的等效数据集。

我将首先发布 Excel 代码及其尝试执行的操作,然后是下面的 R 示例 dfs:

=IF((( IF( outbreak.year > prev.outbreak.year; SMALL( index.year : INDIRECT( ADDRESS(( ROW( outbreak.year) + (( MATCH( 0; outbreak.year : 100th.outbreak.ahead; 0)) - 1) - 1); COLUMN( index.year))); 1))) < 1.28); 1; IF( outbreak.year; prev.outbreak.year; 0))

outbreak.yearprev.outbreak.yearoutbreak.ahead 指的是指示是否正在爆发的二进制数据集; index.year 指的是具有年轮增长指数的同等大小的数据集。

此功能应首先确定爆发 1 是否在非爆发 0 之后开始。如果是,则 SMALL()INDIRECT()ADDRESS()MATCH()ROW()COLUMN() 都用于一种 while 循环以在爆发数据集中向前看,直到它停止报告 1,然后查看索引数据集中等效 'group' 值中的最小数字,看看它是否是 < 1.28。如果是,则保持该组为1s,如果不是,则return该组为非爆发条件,或0s。

例如,我将这些作为输入:

df <- data.frame(t1 = c(0,0,0,1,1,1,1,1,0,0), t2 = c(0,0,0,0,0,1,1,1,1,1), t3 = c(0,0,1,1,1,1,1,1,1,0), t4 = c(0,0,1,1,1,1,1,0,0,1), t5 = c(0,1,1,1,1,1,0,0,1,1), row.names = 2000:2009)

df2 <- data.frame(t1 = c(0.12,0.54,-1.2,-0.3,-0.6,-1.29,-1.30,-0.5,0.3,0.5), t2 = c(0.9,0.8,0.32,0.9,-0.3,-0.4,-0.9,-1.1,-1.12,-1.14), t3 = c(-0.3,0.1,-1.11,-1.14,-1.45,-1.29,-1.68,-1.01,-0.6,0.1), t4 = c(-0.3,-0.34,-0.6,-0.9,-0.8,-1.1,-1.36,-0.4,0.5,0.3), t5 = c(1.45,-0.05,-0.12,-1.26,-0.21,-1.18,-1.01,-0.03,-0.6,-1.39), row.names = 2000:2009)

我希望 df1 看起来像 df3,这取决于 df2 中是否有任何等效的 [i,j] 小于 -1.28。请注意,由于没有足够低的增长,t2 和 t5 列丢失报告的爆发,这在 df2:

中看到
           df1                         df2                                  df3
      t1 t2 t3 t4 t5             t1    t2    t3    t4    t5           t1 t2 t3 t4 t5
2000   0  0  0  0  0     2000  0.12  0.90 -0.30 -0.30  1.45     2000   0  0  0  0  0
2001   0  0  0  0  1     2001  0.54  0.80  0.10 -0.34 -0.05     2001   0  0  0  0  0
2002   0  0  1  1  1     2002 -1.20  0.32 -1.11 -0.60 -0.12     2002   0  0  1  1  0
2003   1  0  1  1  1     2003 -0.30  0.90 -1.14 -0.90 -1.26     2003   1  0  1  1  0
2004   1  0  1  1  1     2004 -0.60 -0.30 -1.45 -0.80 -0.21     2004   1  0  1  1  0
2005   1  1  1  1  1     2005 -1.29 -0.40 -1.29 -1.10 -1.18     2005   1  0  1  1  0
2006   1  1  1  1  0     2006 -1.30 -0.90 -1.68 -1.36 -1.01     2006   1  0  1  1  0
2007   1  1  1  0  0     2007 -0.50 -1.10 -1.01 -0.40 -0.03     2007   1  0  1  0  0
2008   0  1  1  0  1     2008  0.03 -1.12 -0.60  0.50 -0.60     2008   0  0  1  0  1
2009   0  1  0  0  1     2009  0.50 -1.14  0.10  0.30 -1.39     2009   0  0  0  0  1

很难举例说明我的进步,因为我几乎不知道从哪里开始,或者我是否在朝着正确的方向努力。我目前正开始尝试为 df1 中的移位制作一个 while 循环,并让它 shift + 1 滞后直到它达到 0,但后来我迷路了,只是盯着整个(丑陋的)东西:

for( i in 1:dim( df1)[1]) {
  for( j in 1:dim( df1)[2]) {
    if( df1[i,j] > shift( df1, n = 1)) {
      n <- 1
      while( shift( df1, n = n) == 1) {
        shift( df1, n =+ 1)
        df3[i,j] <- 1
      } 
    } else { df3[i,j] <- 0 }
  }
}      

感谢您的帮助!

我会这样问你的问题。我有三个数据框,ABC。我需要使用 B 中的值将 A 转换为 C。以下是数据框:

A <- data.frame(c1=c(0, 1, 1, 0, 1, 1), c2=c(0, 1, 1, 1, 1, 0))
B <- data.frame(c1=c(2, 2, 4, 4, 2, 3), c2=c(0, 2, 3, 4, 1, 4))
C <- data.frame(c1=c(0, 1, 1, 0, 0, 0), c2=c(0, 1, 1, 1, 1, 0))

A 的每一列中的每个连续 1 系列代表一个组。如果B中的相应值中没有大于3的值,我需要将A中的序列转换为零。例如,A$c1中的第一组对应于第二组和该列中的第三个值。 B 中的其中一个值大于 3,因此我保留该组。 A$c1 中的第二组对应于第 5 个和第 6 个值,但它们都不大于 3,因此我不保留该组​​中的值。


一个答案:

# Generate IDs for each sequence of 1s or 0s in each column of A

A.splits <- lapply(A, function(x) cumsum(c(0, abs(diff(x)))))

# Loop through each column, and split the values of B by the
# groups in A.  If any group in any column contains values
# greater than 3, then return ones for that group else zero

A.keep <- Map(
  ave, B, A.splits, MoreArgs=list(FUN=function(x) !!any(x > 3))
)
# remove ones by multiplying each column of `A` against `A.keep`
# and confirm results are the same as expected

all.equal(A * A.keep, C)
## TRUE