【问题标题】:Consecutive Positive or Negative calculation from data frame and filter results using R使用 R 从数据帧和过滤结果进行连续正或负计算
【发布时间】:2020-11-18 18:46:13
【问题描述】:

我有以下数据集,并希望编写一个代码来帮助找出哪些股票连续上涨或下跌。数据将具有前 3 列。最后 2 列是在 Excel 中手动计算的,以描述预期结果。

这只是样本,我将拥有 200 多只股票的数据和几年的数据,所有股票都不是每天交易。

最后,我想提取哪些股票在一天中有 3 或 4 或 5 个连续的正或负变化。

`    Stocks Date    Close Price Change for day  Positive/Negative Count
A   11/11/2020         11       
B   11/11/2020         50       
C   11/11/2020        164       
A   11/12/2020         19         8                 1
B   11/12/2020         62        12                 1
C   11/12/2020        125        -39               -1
A   11/13/2020          7        -12               -1
B   11/13/2020         63         1                 2
C   11/13/2020        165        40                 1
A   11/16/2020         17        10                 1
B   11/16/2020         70         7                 3
C   11/16/2020        170         5                 2
A   11/17/2020         24         7                 2
B   11/17/2020         52        -18               -1
C   11/17/2020        165         -5               -1
A   11/18/2020         31          7                3
B   11/18/2020         61          9                1
C   11/18/2020        157         -8               -2

【问题讨论】:

    标签: r dataframe filter calculated-columns stockquotes


    【解决方案1】:

    难点在于有一个函数可以使累积和(正负),当符号改变时重置计数,并从第一个值开始计数。我设法制作了一个,但它的效率不是很高,并且在更大的数据集上可能会变慢。我怀疑有一种方法可以做得更好,只要在 C 或 C++ 中使用简单的for 循环即可。

    library(tidyverse)
    
    
    df <- read.table(text="Stocks Date    Close_Price Change_for_day  Positive/Negative_Count
    A   11/11/2020         11       NA                 0
    B   11/11/2020         50       NA                 0
    C   11/11/2020        164       NA                 0
    A   11/12/2020         19         8                 1
    B   11/12/2020         62        12                 1
    C   11/12/2020        125        -39               -1
    A   11/13/2020          7        -12               -1
    B   11/13/2020         63         1                 2
    C   11/13/2020        165        40                 1
    A   11/16/2020         17        10                 1
    B   11/16/2020         70         7                 3
    C   11/16/2020        170         5                 2
    A   11/17/2020         24         7                 2
    B   11/17/2020         52        -18               -1
    C   11/17/2020        165         -5               -1
    A   11/18/2020         31          7                3
    B   11/18/2020         61          9                1
    C   11/18/2020        157         -8               -2",
               header = TRUE) %>%
      select(1:3) %>%
      as_tibble()
    
    
    # this formulation could be faster on data with longer stretches
    nb_days_cons2 <- function(x){
      n <- length(x)
      if(n < 2) x
      out <- integer(n)
      y <- rle(x)
      cur_pos <- 1
      for(i in seq_len(length(y$lengths))){
        out[(cur_pos):(cur_pos+y$lengths[i]-1)] <- cumsum(rep(y$values[i], y$lengths[i]))
        cur_pos <- cur_pos + y$lengths[i]
      }
      out
    }
    
    # this formulation was faster on some tests, and would be easier to rewrite in C
    nb_days_cons <- function(x){
      n <- length(x)
      if(n < 2) x
      out <- integer(n)
      out[1] <- x[1]
      for(i in 2:n){
        if(x[i] == x[i-1]){
          out[i] <- out[i-1] + x[i]
        } else{
          out[i] <- x[i]
        }
      }
      out
    }
    

    一旦我们有了这个功能,dplyr 部分就非常经典了。

    df %>%
      group_by(Stocks) %>%
      arrange(Date) %>%   # make sure of order
      mutate(change = c(0, diff(Close_Price)),
             stretch_duration = nb_days_cons(sign(change))) %>%
      arrange(Stocks)
    #> # A tibble: 18 x 5
    #> # Groups:   Stocks [3]
    #>    Stocks Date       Close_Price change stretch_duration
    #>    <chr>  <chr>            <int>  <dbl>            <dbl>
    #>  1 A      11/11/2020          11      0                0
    #>  2 A      11/12/2020          19      8                1
    #>  3 A      11/13/2020           7    -12               -1
    #>  4 A      11/16/2020          17     10                1
    #>  5 A      11/17/2020          24      7                2
    #>  6 A      11/18/2020          31      7                3
    #>  7 B      11/11/2020          50      0                0
    #>  8 B      11/12/2020          62     12                1
    #>  9 B      11/13/2020          63      1                2
    #> 10 B      11/16/2020          70      7                3
    #> 11 B      11/17/2020          52    -18               -1
    #> 12 B      11/18/2020          61      9                1
    #> 13 C      11/11/2020         164      0                0
    #> 14 C      11/12/2020         125    -39               -1
    #> 15 C      11/13/2020         165     40                1
    #> 16 C      11/16/2020         170      5                2
    #> 17 C      11/17/2020         165     -5               -1
    #> 18 C      11/18/2020         157     -8               -2
    Created on 2020-11-19 by the reprex package (v0.3.0)
    

    当然,最后的arrange()只是为了方便可视化,你可以用select()去掉不再需要的列。

    【讨论】:

    • 最后一列的结果不正确。例如,股票 C-date 11 月 17 日的值应为 -1,11 月 18 日的值应为 -2,以显示连续 2 个负收盘价。它永远不应该为零,因为正负不应该抵消。
    • 哦,我不明白你想要这个,现在它是具有相同符号的连续条目的数量,这样您就可以轻松提取连续 3 或 4 天的条目。我正在编辑我的答案以添加一个签名列(只需乘以 pos)。
    • Alexlok,它仍然不正确。在正值 1 之后,如果股票第二天收盘为负,结果不应该为零。在每次正或负收盘时,它应该分别从 -1 或 +1 开始计数。所以最后一列的答案永远不应该为零。希望我能够澄清。我在 11 月 17 日对股票 C 的预期结果是-1,而 11 月 18 日是-2。请帮助改进代码。
    • 现在符合预期吗?
    • 是的,它符合预期。我怎样才能给予 5 星评级和对这个网站的如此出色的支持?我只想确认一件事,因为到目前为止我无法从结果中确认。由于周末或任何特定股票未在任何特定日期交易的日期之间的差距,此代码将如何变化?
    猜你喜欢
    • 1970-01-01
    • 2021-12-29
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多