【问题标题】:R - Find maximum run of positive / negative valuesR - 查找正/负值的最大运行
【发布时间】:2017-07-29 23:31:58
【问题描述】:

我有一个大约 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

我需要资助最长的值 >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?

【问题讨论】:

  • 到目前为止你尝试了什么?
  • y 0] 只需要返回最长长度 > 0
  • 如果我理解正确,rle(sign(x)) 应该会为你做的

标签: r


【解决方案1】:

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

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

最大。位置运行:

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

最大。负运行:

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

【讨论】:

  • 这是否处理系列中的 0 值?如果系列中有连续的 0 值,我想我会看到一些奇怪的东西。
  • 好吧,我知道发生了什么......如果我有积极的......和消极的由 0 分隔它是不同的。所以基本上如果我有 c(1,0,0,0,1,0,0,-1,0,0,-2,0,0,0) 为正数,我希望从 1 开始计数。 ..跳过0 ...并计算下一个1 ...所以正运行是2 ....对于负运行,我们发现-1跳过0并计算-2 ..所以最大负运行是 2.... 也许会提出一个新问题!我在最初的问题中没有意识到这一点
  • 我可以从数据框中提取数据,删除所有 0 然后运行相同的计算。应该工作..
  • @AndrewBannerman,您有几种处理零的选项。一种是在计算运行之前过滤掉零,其次:将零视为胜利或失败,或者计算一个辅助列,即损失 -> 0、胜利 -> 1 和零 -> 2,并将零视为单独的运行。无论您使用哪种方法,如何计算最大输/赢的原理都保持不变。希望这会有所帮助。
  • sign(x) 返回一个带有 x 对应元素符号的向量。(如果数字是正数、零或负数,实数的符号是​​ 1、0 或 -1,分别)。
【解决方案2】:

这是一种简单的方法,我假设您从一个只有值的数据框开始.

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)))

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

【讨论】:

  • 酷代码!我只习惯看 R 代码,没有做过任何其他编程。以上是围绕另一种语言的基础形成的吗?
【解决方案3】:

我认为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

如果您获得所有运行,您将能够绘制正运行与负运行的分布,或执行统计比较以查看平均运行时间是否比正运行更长。

【讨论】:

  • 你能检查你的数据是否可以处理 0 吗?现在,如果我的数据 == 0,它会下降为否定。我认为如果我们纠正了那应该很好去
  • 解决方案已更新,将零视为单独的类别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-18
  • 1970-01-01
  • 2010-10-19
  • 2015-10-28
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
相关资源
最近更新 更多