R - 查找正/负值的最大运行

时间:2017-07-29 23:31:58

标签: r

我有一个大约3000行的数据框。我希望找到最长的正数和负数。

我的示例数据框:df

1   0.502310591 
2   -0.247577976    
3   -0.307256769    2
4   0.442253678 
5   -0.795770351    
6   2.08244648  
7   -0.01672777 
8   -0.164145656    2
9   0.610117365 
10  0.014758371 
11  0.381105476 
12  0.721386493 4
13  -0.363222383    
14  0.201409322 
15  0.724867214 
16  -1.586829584    
17  1.066288451 
18  0.182824494 
19  0.237447191 
20  -0.215475797

最长的正面运行:4 最长的负面运行:2

我正在关注本教程:https://ocw.mit.edu/ans7870/18/18.05/s14/html/r-tut-rle.html

我需要资助最长的值&gt; 0并且还<0。那么有什么方法可以编辑上面的内容吗?

我猜这只发现最长的1,0?如果是那种情况,那么我需要一个辅助列ifelse 1,0来分割负数,正数...然后可能找到最长的代码:

> df$wins <- ifelse(df$V2 > 0, 1, 0) 
> df$loss <- ifelse(df$V2 < 0, 1, 0)
> win <- (c(df$wins))
> max(rle(win)$lengths)
[1] 4

这适用于寻找最大胜利......

这是为了损失:

> print(df$loss)
 [1] 0 1 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 1
> df$loss <- ifelse(df$V2 < 0, 1, 0)
> print(df$loss)
 [1] 0 1 1 0 1 0 1 1 0 0 0 0 1 0 0 1 0 0 0 1
> loss <- (c(df$loss))
> max(rle(loss)$lengths)
[1] 4

不确定为什么它说4 ...显然有2个最大损失,有谁知道为什么? 我错过了什么,胜利的逻辑不应该对损失完全相同吗?我看不到代码中的任何错误......

如果df $ loss中的值小于0则打印1否则为0。 制作一个包含df $ loss列内容的向量 使用max(rle(loss)$lengths)找到1的最大长度 再次结果是4 ..然而,它显然是2?

3 个答案:

答案 0 :(得分:1)

我认为rle将根据您的目标完成工作,但我会发布一个替代解决方案,稍微更多的数据操作,但您将能够获得更多信息。

通常,在回答一个问题后,您将被要求回答更多问题。例如,了解正数与负数的运行分布,因为最大值可能不会告诉您太多。或者,进行统计比较,看看阳性是否比平均阴性更长。

此外,在大约3000行的情况下,我认为你没有任何速度问题。

library(dplyr)

# example dataset
dt = data.frame(x = c(1,-1,-2,0,2,4,3,5,-5,-6,-7,0,0))

# get a dataset that assigns an id to all positive or negative series
dt %>%
  mutate(sign = ifelse(x > 0, "pos", ifelse(x < 0, "neg", "zero")), # get the sign of the value
         sign_lag = lag(sign, default = sign[1]),       # get previous value (exception in the first place)
         change = ifelse(sign != sign_lag, 1 , 0),      # check if there's a change
         series_id = cumsum(change)+1) %>%              # create the series id
  print() -> dt2                                        # print to screen and save it

#     x sign sign_lag change series_id
# 1   1  pos      pos      0         1
# 2  -1  neg      pos      1         2
# 3  -2  neg      neg      0         2
# 4   0 zero      neg      1         3
# 5   2  pos     zero      1         4
# 6   4  pos      pos      0         4
# 7   3  pos      pos      0         4
# 8   5  pos      pos      0         4
# 9  -5  neg      pos      1         5
# 10 -6  neg      neg      0         5
# 11 -7  neg      neg      0         5
# 12  0 zero      neg      1         6
# 13  0 zero     zero      0         6

您可以删除帮助列sign_lagchange,因为我已将它们包含在内,仅用于说明该过程的工作原理。

# Get longest runs
dt2 %>% 
  count(sign, series_id) %>%
  group_by(sign) %>%
  filter(n == max(n)) %>%
  select(-series_id) %>%
  ungroup

# # A tibble: 3 x 2
#    sign     n
#   <chr> <int>
# 1   neg     3
# 2   pos     4
# 3  zero     2


# Get all runs
dt2 %>% count(sign, series_id)

# # A tibble: 6 x 3
#    sign series_id     n
#   <chr>     <dbl> <int>
# 1   neg         2     2
# 2   neg         5     3
# 3   pos         1     1
# 4   pos         4     4
# 5  zero         3     1
# 6  zero         6     2

如果你得到所有跑步,你将能够绘制积极与阴性的分布,或进行统计比较,看看阳性平均值是否比阴性更长。

答案 1 :(得分:1)

这是一种简单的方法,我假设你开始只使用一个数据框,我也假设你需要一个数据帧,其中相同数字的计数运行一列为正数,一列为负数

set.seed(42)
df=data.frame(x= runif(300, -1.0, 1.0))
count_pos=c()
count_neg=c()
n1=df$x[1]
if (sign(n1)==1){
  count_pos[1]=1
  count_neg[1]=0
}else{
  count_neg[1]=1
  count_pos[1]=0
}
count=1
index=1
for (i in df$x[2:nrow(df)]){
  #print (i)
  index=index+1
  if (sign(n1)==sign(i)){
    count=count+1
  }
  else{
    count=1
  }
  if (sign(i)==1){
    count_pos[index]=count
    count_neg[index]=0
  }else{
    count_pos[index]=0
    count_neg[index]=count
  }
  n1=i
}

df2=data.frame(x=df$x,count_pos=count_pos,count_neg=count_neg)
#df2 contains the dataframe with columns that count the run for numbers with 
#same sign
print (paste("Maximum run of Positive numbers:",max(count_pos)))
print (paste("Maximun run of negative numbers:",max(count_neg)))

我知道有一种更紧凑的方法可以做到这一点,但这段代码可以解决问题。

答案 2 :(得分:1)

要获得系列中的最大正/负运行(在您的情况下,在data.frame的列中,rle函数就是您所需要的:

set.seed(123)
df <- data.frame(col1=rnorm(20, mean = 0, sd = 1))

最大。 pos run:

max(rle(sign(df$col1))[[1]][rle(sign(df$col1))[[2]] == 1])
[1] 5

最大。 neg.run:

max(rle(sign(df$col1))[[1]][rle(sign(df$col1))[[2]] == -1])
[1] 3

让我们检查一下结果:

> df
          col1
1  -0.56047565
2  -0.23017749
3   1.55870831
4   0.07050839
5   0.12928774
6   1.71506499
7   0.46091621
8  -1.26506123
9  -0.68685285
10 -0.44566197
11  1.22408180
12  0.35981383
13  0.40077145
14  0.11068272
15 -0.55584113
16  1.78691314
17  0.49785048
18 -1.96661716
19  0.70135590
20 -0.47279141