在R中,我有一些数据涉及移动物体(velocity
)与物体呈现的特定情况(ID
)的近似速度。
例如:
df<-data.frame(ID = c(1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3), velocity = c(10,11,15,28,33,32,33,38,21,10,3,6,9, 21, 54, 44, 31,15, 29, 7, 38, 29))
那样:
> df
ID velocity
1 1 10
2 1 11
3 1 15
4 1 28
5 2 33
6 2 32
7 2 33
8 2 38
9 2 21
10 2 10
11 2 3
12 2 6
13 2 9
14 2 21
15 2 54
16 2 44
17 2 31
18 2 15
19 2 29
20 2 7
21 3 38
22 3 29
现在我的目标是双重的。我想首先为每个peak
子集标识velocity
的{{1}}值,并报告哪个特定行包含此ID==2
值。其次,我想应用一个从这个特定行开始的函数,向后/向上和向下搜索(从相邻值开始)搜索满足特定条件的所有值,并且&#34; break&#34;一旦不符合标准,
虽然我可能已经找到了第一点的解决方案,但我无法正确编码一个按照所述循环向前和向后循环的函数。我将举例说明我对第一个问题所做的工作以及与第二个问题有关的预期结果,希望更多的专业程序员可以帮助我解决这个问题。
我基本上做的是创建另一个列,将peak
速度的相应行标识为peak
,其余列为TRUE
。为此,我使用了包FALSE
来对数据进行子集化。
以下是一个例子:
plyr
为了清楚起见,我已经实施了这个程序。这个步骤可能嵌套在下一个关于函数实现的步骤中,但我等待你的评论。
现在,我希望该函数仅应用于library(plyr)
df<- ddply(df, .(ID), transform, peak= ifelse(which.max(velocity) == sequence(rle(ID)$lengths), TRUE,FALSE))
> df
ID velocity peak
1 1 10 FALSE
2 1 11 FALSE
3 1 15 FALSE
4 1 28 TRUE
5 2 33 FALSE
6 2 32 FALSE
7 2 33 FALSE
8 2 38 FALSE
9 2 21 FALSE
10 2 10 FALSE
11 2 3 FALSE
12 2 6 FALSE
13 2 9 FALSE
14 2 21 FALSE
15 2 54 TRUE
16 2 44 FALSE
17 2 31 FALSE
18 2 15 FALSE
19 2 29 FALSE
20 2 7 FALSE
21 3 38 TRUE
22 3 29 FALSE
的{{1}}行。在我的原始数据集中重复ID,因此我将不得不应用此函数以及除示例中提供的其他几个子集。
此外,从包含TRUE
语句的行开始,该函数必须向后循环(考虑行ID==2
中的TRUE
,然后TRUE
和转发(考虑行n
中的n-1, n-2, n-3, ...
,然后TRUE
,如果条件满足,则将行的每个其他元素标记为n
。这样的条件是每个如果相邻值在向后和向前方向上都高于n+1, n+2, n+3, ...
TRUE
,则会标记为TRUE
。一旦值低于此值,该函数就会标记所有内容对于子集的其余部分(velocity/5
),每个方向(向后/向前)明显为peak
因此,如果我们将上述FALSE
视为示例,ID
已被归类为该data.frame
范围内peak == 54
的{{1}}值。
peak
然后该函数检查前一行(velocity
)中的ID
值是否高于 > df
ID velocity peak
1 1 10 FALSE
2 1 11 FALSE
3 1 15 FALSE
4 1 28 TRUE
5 2 33 FALSE
6 2 32 FALSE
7 2 33 FALSE
8 2 38 FALSE
9 2 21 FALSE
10 2 10 FALSE
11 2 3 FALSE
12 2 6 FALSE
13 2 9 FALSE
14 2 21 FALSE
15 2 54 TRUE***
16 2 44 FALSE
17 2 31 FALSE
18 2 15 FALSE
19 2 29 FALSE
20 2 7 FALSE
21 3 38 TRUE
22 3 29 FALSE
。在这种情况下,它是21> 10.8。然后该行标记为velocty
,并且该函数继续向后循环。在第二种情况下(第13行),9 <10.8。因此,该函数将此行标记为false,因为它不符合指定条件,而当前子集n-1
的每个其他后向行都标记为54/5=10.8
。
TRUE
然而,在向前方向,行{16}中的ID==2
中的值均为> 10.8。因此,这些行标记为FALSE
,而不是第20行,其值为7.从此时起,同一子集 ID velocity peak
1 1 10 FALSE
2 1 11 FALSE
3 1 15 FALSE
4 1 28 TRUE
5 2 33 FALSE
6 2 32 FALSE
7 2 33 FALSE
8 2 38 FALSE
9 2 21 FALSE
10 2 10 FALSE
11 2 3 FALSE
12 2 6 FALSE
13 2 9 FALSE
14 2 21 TRUE**
15 2 54 TRUE***
16 2 44 FALSE
17 2 31 FALSE
18 2 15 FALSE
19 2 29 FALSE
20 2 7 FALSE
21 3 38 TRUE
22 3 29 FALSE
中的每一行都标记为velocity
。
TRUE
包含的最新data.frame类似于所需输出的示例。我希望我以正确的方式解释我的问题并期待你的意见。
答案 0 :(得分:1)
你绝对可以用for
循环来写这个,尽管对于大型数据集来说它会非常慢(即> 100,000次观察)。如果你需要效率,在Rcpp中实现这个部分可能是一个解决方案。
无论如何,这似乎产生了所需的输出:
df_out = NULL
for(i in unique(df$ID)){
# subset
df_temp = df[df$ID==i,]
df_temp$peak = FALSE
# find peak
max_velocity = max(df_temp$velocity)
peak_pos = which(df_temp$velocity == max_velocity)
# search backward
for(r in peak_pos:1){
if(df_temp$velocity[r] > max_velocity/5) df_temp$peak[r] = TRUE
else break
}
# search forward
for(r in (peak_pos):nrow(df_temp)){
if(df_temp$velocity[r] > max_velocity/5) df_temp$peak[r] = TRUE
else break
}
df_out = rbind(df_out, df_temp)
}
df_out