我有一个长序列的1和0表示鸟类孵化模式,1表示鸟巢,0表示关闭。
> Fake.data<- c(1,1,1,1,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,0,1,0)
作为终点,我基本上喜欢每个ON周期和连续OFF周期之间的比率的单个值。理想情况下,这应该是Fake.data这样的矢量
[1] 0.4 0.75 0.25 0.5 0.8 0.5 1 (I just typed this out!)
到目前为止,我已使用split()
将矢量拆分为多个部分 > Diff<-diff(Fake.data)
> SPLIT<-split(Fake.data, cumsum(c(1, Diff > 0 )))
> SPLIT
返回......
$`1`
[1] 1 1 1 1 1 0 0
$`2`
[1] 1 1 1 1 0 0 0
$`3`
[1] 1 1 1 1 0
$`4`
[1] 1 1 1 1 0 0
$`5`
[1] 1 1 1 1 1 0 0 0 0
$`6`
[1] 1 1 0
$`7`
[1] 1 0
所以我可以使用
获得单个拆分组的比率 > SPLIT$'1'<- ((length(SPLIT$'1'))-(sum(SPLIT$'1')))/sum(SPLIT$'1')
> SPLIT$'1'
[1] 0.4
然而,在我的数据中,我有几千个这样做,并希望应用某种tapply()或for()循环来自动计算所有这些并将其放入单个向量中。我已经尝试了这些方法中的每一个都没有成功,因为split()输出结构似乎不适合这些函数?
我创建一个新的向量来接收for()循环输出
ratio<-rep(as.character(NA),(length(SPLIT)))
然后使用上面的代码尝试for()循环,该代码适用于单次运行。
for(i in SPLIT$'1':'7')
{ratio[i]<-((length(SPLIT$'[i]'))-(sum(SPLIT$'[i]')))/sum(SPLIT$'[i]')}
我得到的是......
[1]&#34; NaN&#34; &#34; NaN的&#34; &#34; NaN的&#34; &#34; NaN的&#34; &#34; NaN的&#34; &#34; NaN的&#34; NA
尝试了很多其他的变化,但现在真的卡住了!
答案 0 :(得分:3)
我认为你与你的态势非常接近。 sapply
函数非常乐意使用列表。我只想改变最后一步
sapply(SPLIT, function(x) sum(x==0)/sum(x==1))
返回
1 2 3 4 5 6 7
0.40 0.75 0.25 0.50 0.80 0.50 1.00
包含您的示例数据。无需额外的包裹。
答案 1 :(得分:1)
以下是两种可能性:
1)使用rle
计算长度,然后在if
语句中,如果数据以0开头,则不包括第一个长度,以便我们放心我们从1开始。最后使用动物园包中的rollapply
来计算比率:
library(zoo)
lengths <- rle(Fake.data)$lengths
if (Fake.data[1] == 0) lengths <- lengths[-1]
rollapply(lengths, 2, by = 2, function(x) x[2]/x[1])
,并提供:
[1] 0.40 0.75 0.25 0.50 0.80 0.50 1.00
如果我们知道数据始终以1开头,则可以删除if
行。
2)如果我们可以假设系列始终以1开头并以0结尾,那么这一个班轮将起作用:
with( rle(Fake.data), lengths[values == 0] / lengths[values == 1] )
给出与上述相同的答案。