从R

时间:2016-11-02 09:56:48

标签: arrays r function loops conditional

数据集

在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;一旦不符合标准,

问题:

虽然我可能已经找到了第一点的解决方案,但我无法正确编码一个按照所述循环向前和向后循环的函数。我将举例说明我对第一个问题所做的工作以及与第二个问题有关的预期结果,希望更多的专业程序员可以帮助我解决这个问题。

1)找到峰值

我基本上做的是创建另一个列,将peak速度的相应行标识为peak,其余列为TRUE。为此,我使用了包FALSE来对数据进行子集化。

以下是一个例子:

plyr

为了清楚起见,我已经实施了这个程序。这个步骤可能嵌套在下一个关于函数实现的步骤中,但我等待你的评论。

2)从TRUE行

向后和向前循环

现在,我希望该函数仅应用于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类似于所需输出的示例。我希望我以正确的方式解释我的问题并期待你的意见。

1 个答案:

答案 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