R—使用二进制df1对df2中的测量进行分组,然后查看每个组中的任何测量是否满足特定条件以输出新的二进制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)年之后开始。如果是,则在某种while循环中使用SMALL()INDIRECT()ADDRESS()MATCH()ROW()COLUMN(),以便在爆发数据集中向前查看,直到它停止报告1,然后查看索引数据集中等效"组"值中的最小数字,并查看它是否为< 1.28。如果是,则将该组保留为1 s,如果不是,则将该组返回为非爆发条件或0 s。

。,我将使用这些作为输入:

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]s小于-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 }
  }
}      

谢谢你的帮助!

我会这样问你的问题。我有三个数据帧,A, BC。我需要使用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 s的每一列代表一个组。如果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

最新更新