Последовательное положительное или отрицательное вычисление из фрейма данных и результатов фильтрации с использованием R

#r #dataframe #filter #calculated-columns #stockquotes

#r #фрейм данных #Фильтр #вычисляемые столбцы #котировки акций

Вопрос:

У меня есть следующий набор данных, и я хочу написать код, который поможет определить, какие запасы были положительными или отрицательными последовательно. Данные будут иметь первые 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
  

Ответ №1:

Сложность заключается в том, чтобы иметь функцию, которая делает совокупную сумму, как положительную, так и отрицательную, сбрасывает счетчик при изменении знака и начинает подсчет с первого значения. Значение. Мне удалось сделать один, но он не очень эффективен и, вероятно, будет работать медленно с большим набором данных. Я подозреваю, что есть способ сделать лучше, хотя бы с помощью простого for цикла на C или C .

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

Комментарии:

1. результаты в последнем столбце неверны. Например, акции С датой 17 ноября должны иметь значение -1, а 18 ноября должны иметь значение -2, чтобы показать 2 последовательных отрицательных закрытия. Оно никогда не должно быть равным нулю, потому что положительное отрицательное значение не предполагается вычеркивать.

2. О, я не понял, что вы этого хотели, прямо сейчас это количество последовательных записей с одинаковым знаком, так что вы можете легко извлечь те, у которых 3 или 4 дня подряд. Я редактирую свой ответ, чтобы добавить подписанный столбец (просто путем умножения на pos ).

3. Alexlok, это все еще неверно. после положительного значения 1, если на следующий день акции закрываются с отрицательным значением, результат не должен быть нулевым. При каждом положительном или отрицательном закрытии отсчет должен начинаться с -1 или 1 соответственно. поэтому ответ в последнем столбце никогда не должен быть нулевым. Надеюсь, я смогу прояснить. мой ожидаемый результат для stock C 17 ноября -1, а 18 ноября -2. Пожалуйста, помогите улучшить код.

4. Соответствует ли это ожиданиям сейчас?

5. Да, это соответствует ожиданиям. Как я могу дать оценку 5 звезд и этому веб-сайту за такую блестящую поддержку? Я хотел бы подтвердить только одну вещь, потому что пока я не могу подтвердить результаты. Как этот код будет связан с пробелами в датах, таких как выходные или какие-либо конкретные акции, не торгуемые в какую-либо конкретную дату?