Назначьте день (от 1 до n) по дате сопоставления в другом фрейме данных - PullRequest
2 голосов
/ 03 апреля 2020

Общая цель: Создать переменную в фрейме данных ежедневных цен на акции, которая будет указывать, сколько дней прошло с тех пор, как фирма представила прибыль. Это должно быть сделано путем поиска даты в другом фрейме данных.

У меня есть два фрейма данных: один, содержащий ежедневные цены акций ( df1 ), и другой, содержащий квартальные наблюдения с отчетными доходами от фирма ( df2 ). В df1 я стремлюсь создать новую переменную, которая будет указывать дни от объявленной прибыли, т.е. сообщается, что дневной заработок - это день 0, а следующий день - 1 и c. пока он не достигнет следующей отчетной даты, где он должен начинаться с 0.

Как сопоставить дату цены акций в df1 с ближайшей датой сообщаемой прибыли в df2 и присвоить ее переменной в df1 ? У меня есть несколько фирм в моем наборе данных.

Пример: В идеале мой конечный результат в df1 должен выглядеть следующим образом, где последняя переменная указывает, что объявление о прибыли фирмы было 2019/01/30:

date          stock price   days from earnings announcement
2019/01/30    4,4           0
2019/01/31    4,2           1
2019/02/01    4,5           2
2019/02/02    4,6           3
...

Теперь предположим, что фирма представляет новое объявление о прибыли в 2019/04/30. Если это так, он должен выглядеть следующим образом:

date          stock price   days from earnings announcement
2019/01/30    x             0
2019/01/31    x             1
2019/02/01    x             2
2019/02/02    x             3
...
2019/04/29    x             89
2019/04/30    x             0
2019/05/01    x             1
...

Таким образом, указывается, что 2019/04/29 - это 89 дней после последнего объявления о прибыли, а в 2019/04/30 было представлено новое объявление о прибыли. Соответствующие файлы (включая первые шаги кода) можно найти по этой ссылке на dropbox

stackoverflow.r:

setwd("~/R")
setwd("~/R/stackoverflow")
library(readr)
df2 <- read_delim("eps_forecasted_clean.csv", 
                  ";", escape_double = FALSE, col_types = cols(date = col_date(format = "%d-%m-%Y")), 
                  trim_ws = TRUE)
View(df2) #use "date" to lookup
df1 <- read_delim("~/R/stackoverflow/stock_prices.csv", 
                  ";", escape_double = FALSE, trim_ws = TRUE)
View(df1)

Ответы [ 3 ]

1 голос
/ 03 апреля 2020

Вот подход data.table.

Редактировать : основано на фактических данных из предоставленной ссылки OP.

  • df1 с GVKEY и reportdate
  • df2 с gvkey и date

, где gvkey / GVKEY представляет каждую фирму.

Общее join_date создается в обоих таблицы данных. Индекс создается с использованием скользящего объединения, который идентифицирует самую последнюю дату отчета.

Затем указывается число дней от отчетной прибыли - join_date после скользящего объединения.

library(readr)
library(data.table)

df2 <- read_delim("eps_forecasted_clean.csv", 
                  ";", escape_double = FALSE, col_types = cols(date = col_date(format = "%d-%m-%Y")), 
                  trim_ws = TRUE)

# Changed filepath here
df1 <- read_delim("stock_prices.csv", 
                  ";", escape_double = FALSE, trim_ws = TRUE)

# Reportdate needs to be in date format
df1$reportdate <- as.Date(df1$reportdate, format = "%d-%m-%Y")

setDT(df1)[ , join_date := reportdate]
setDT(df2)[ , join_date := date]

# Joining by gvkey as ID for firm, correct?
idx <- df2[df1, on = c(gvkey = "GVKEY", "join_date"), roll = TRUE, which = TRUE]

df1[ , numDays := reportdate - df2[idx, join_date]]
df1

Выход

              X1 GVKEY LIID LINKTYPE   LINKDT iid datadate reportdate   tic         conm prccd trfd year price_adjusted  join_date numDays
      1:       1  1004    1       LU 19720424   1 19831230 1983-12-30   AIR     AAR CORP  1725    1 1983           1725 1983-12-30 30 days
      2:       2  1004    1       LU 19720424   1 19840103 1984-01-03   AIR     AAR CORP    17    1 1984             17 1984-01-03 34 days
      3:       3  1004    1       LU 19720424   1 19840104 1984-01-04   AIR     AAR CORP  1725    1 1984           1725 1984-01-04 35 days
      4:       4  1004    1       LU 19720424   1 19840105 1984-01-05   AIR     AAR CORP  1725    1 1984           1725 1984-01-05 36 days
      5:       5  1004    1       LU 19720424   1 19840106 1984-01-06   AIR     AAR CORP    18    1 1984             18 1984-01-06 37 days
     ---                                                                                                                                  
1048571: 1048571  4394    1       LU 19820129   1 19880629 1988-06-29 EEE.2 ENSOURCE INC  7188    1 1988           7188 1988-06-29 90 days
1048572: 1048572  4394    1       LU 19820129   1 19880630 1988-06-30 EEE.2 ENSOURCE INC  7375    1 1988           7375 1988-06-30 91 days
1048573: 1048573  4394    1       LU 19820129   1 19880701 1988-07-01 EEE.2 ENSOURCE INC  7375    1 1988           7375 1988-07-01 92 days
1048574: 1048574  4394    1       LU 19820129   1 19880705 1988-07-05 EEE.2 ENSOURCE INC  7375    1 1988           7375 1988-07-05 96 days
1048575: 1048575  4394    1       LU 19820129   1 19880706 1988-07-06 EEE.2 ENSOURCE INC   725    1 1988            725 1988-07-06 97 days
0 голосов
/ 03 апреля 2020

Чтобы получить самое последнее совпадение дат, вам нужно нечеткое объединение с пакетом fuzzyjoin.

Так что с fuzzyjoin, tidyverse и lubridate вы можете сделать:


library(tidyverse)
library(lubridate)
library(fuzzyjoin)

df1 %>%
    fuzzyjoin::fuzzy_left_join(
        df2, 
        by = c("tic" = "tic", "reportdate" = "date"),
        match_fun = list(`==`, `>=`)) %>%
    mutate(daysFromWhatever = difftime(reportdate, date, units = "days"))

Обратите внимание, что после загрузки ваших файлов из Dropbox мне пришлось изменить поля даты, и чтобы они были в разных форматах, что также может создавать проблемы.

Если я неправильно пойму, какую дату вы хотите отложить, какую, вы можете измените >= на <=.

0 голосов
/ 03 апреля 2020

Я думаю, что это должно сделать то, что вы ищете.

df1 <- data.frame(id = c(1,1,1,1,2,2,2,2),
                  date = rep(as.Date(c("2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04")),2))
df1                  
df2 <- data.frame(id = c(1,1,2,2),
                  reportDate = rep(as.Date(c("2019-10-01","2020-01-01", "2019-10-03", "2020-01-03"))))
df2                  

for(i in seq_len(nrow(df1))){
  refDate <- max(df2$reportDate[df2$reportDate<= df1$date[i] & df2$id == df1$id[i]])
  df1$numDays[i] <- df1$date[i] - refDate
}

(Возможно, есть более эффективный способ сделать это без l oop, но я не совсем уверен, что это есть.)

...