Цикл по набору данных в R - PullRequest
       1

Цикл по набору данных в R

1 голос
/ 09 февраля 2020

Я новичок в R и быстро сомневаюсь (перебрал много вопросов о переполнении стека, но безрезультатно).

Я создал функцию (как видно из моего кода), где x и y - даты, а $z_{1} to z_{9}$ - фреймы данных. Функция просматривает 9 файлов, подмножества данных в зависимости от заданных дат и возвращает объединенный набор данных.

DATE1_May <- as.Date("2017-11-16")
DATE2_May <- as.Date("2018-02-15")

myfunc1 <- function(x,y,z1,z2,z3,z4,z5,z6,z7,z8,z9){
  a1 <- z1[z1$Date >= x & z1$Date <= y,]
  b1 <- a1[c(1,2)]
  b1 <- data.frame(b1)
  a2 <- z2[z2$Date >= x & z2$Date <= y,]
  b2 <- a2[c(1,2)]
  b2 <- data.frame(b2)
  a3 <- z3[z3$Date >= x & z3$Date <= y,]
  b3 <- a3[c(1,2)]
  b3 <- data.frame(b3)
  a4 <- z4[z4$Date >= x & z4$Date <= y,]
  b4 <- a4[c(1,2)]
  b4 <- data.frame(b4)
  a5 <- z5[z5$Date >= x & z5$Date <= y,]
  b5 <- a5[c(1,2)]
  b5 <- data.frame(b5)
  a6 <- z6[z6$Date >= x & z6$Date <= y,]
  b6 <- a6[c(1,2)]
  b6 <- data.frame(b6)
  a7 <- z7[z7$Date >= x & z7$Date <= y,]
  b7 <- a7[c(1,2)]
  b7 <- data.frame(b7)
  a8 <- z8[z8$Date >= x & z8$Date <= y,]
  b8 <- a8[c(1,2)]
  b8 <- data.frame(b8)
  a9 <- z9[z9$Date >= x & z9$Date <= y,]
  b9 <- a9[c(1,2)]
  b9 <- data.frame(b9)
  fin1 <- Reduce(function(x, y) merge(x, y, all=T, by=c("Date")), list(b1,b2,b3,b4,b5,b6,b7,b8,b9))
  }
Testx1 <- myfunc1(DATE1_May,DATE2_May, May18,July18, September18, December18,March19, May19, July19, September19, December19)    

У меня есть 2 вопроса:

  1. Я написал этот код для фьючерсного контракта 18 марта. Я хочу сделать то же самое с контрактом 17 марта, но в этом случае $z_{1} to z_{9}$ будет с 17 мая по 18 декабря. И даты будут такими:

    DATE1_May <- as.Date("2016-11-16")
    DATE2_May <- as.Date("2017-02-15")
    

    Я пытался создать for l oop и использовать команду assign. Однако я не уверен, как это сделать. Есть ли способ автоматизировать это? (Сейчас я создаю отдельные функции, но это занимает много времени, так как мне нужно сделать это для более чем 100 контрактов.)

  2. Есть ли способ сократить функцию (Это работает отлично, хотя).

Ответы [ 2 ]

0 голосов
/ 09 февраля 2020

Попробуйте обобщить процесс повторяющегося кода для создания списка фреймов данных с lapply, используя ... для динамических c параметров любой длины. Затем запустите цепочку слияния с Reduce, все с использованием базы R:

df_build <- function(x, y, ...) { 
  df_list <- lapply(..., function(df)
      # ROW AND COLUMN INDEXING
      df[df$Date >= x & df$Date <= y, c(1,2)] 
  )

  # CHAIN MERGE FULL JOIN
  merged_df <- Reduce(function(x, y) merge(x, y, all=TRUE, by=c("Date")), 
                      df_list)      
}

# MAY 2018 FUTURES
DATE1_May <- as.Date("2017-11-16") 
DATE2_May <- as.Date("2018-02-15") 

may_2018_df <- df_build(DATE1_May, DATE2_May, 
                        May18, July18, September18, 
                        December18, March19, May19, 
                        July19, September19, December19)  

# MAY 2017 FUTURES
DATE1_May <- as.Date("2016-11-16") 
DATE2_May <- as.Date("2017-02-15")

may_2017_df <- df_build(DATE1_May, DATE2_May, 
                        May17, July17, September17, 
                        December17, March18, May18, 
                        July18, September18, December18)  

Может даже быть динамический способ c для построения списка фреймов данных майского фьючерса с использованием get и paste0 динамически ссылаться на объекты по строке. Ниже строится с 2010 по 2018 год и использует выше df_build(). Отрегулируйте при необходимости.

may_futures_list <- lapply(c(2010:2018), function(yr) {
    DATE1_May <- as.Date(paste0(yr-1, "-11-16"))
    DATE2_May <- as.Date(paste0(yr, "-02-15"))

    may_df <- df_build(DATE1_May, DATE2_May, 
                       get(paste0("May", yr)), 
                       get(paste0("July", yr)),
                       get(paste0("September", yr)), 
                       get(paste0("December", yr)), 
                       get(paste0("March", yr+1)),
                       get(paste0("May", yr+1)),
                       get(paste0("July", yr+1)),
                       get(paste0("September", yr+1)), 
                       get(paste0("December", yr+1))
               )
})

# RENAME LIST ELEMENTS
may_futures_list <- setNames(may_futures_list,
                             as.character(c(2010:2018))
                    )

# RETRIEVE INDIVIDUALS DATA FRAMES
may_futures_list$`2018`
may_futures_list$`2017`
may_futures_list$`2016`
...
0 голосов
/ 09 февраля 2020

Сложно без примера того, как выглядят ваши фреймы данных, но я бы порекомендовал работать с пакетами dpylr и purrr из tidyverse.

Здесь вы должны выполнить итерацию по каждому фрейму данных в список, фильтрующий каждый фрейм данных по датам между start_date и end_date. Наконец, вы можете использовать уменьшение (как и прежде), чтобы объединить каждый кадр данных вместе. Reduce применяет функцию к каждому элементу в списке последовательно, в данном случае full_join, которая будет хранить все строки из объединяемых фреймов данных.

Это может быть записано с набором промежуточных переменных или с использованием оператора %>% для очень чистого кода.

Если вам нужно часто выполнять эти операции, я бы рекомендовал заключить эти шаги в функцию.

library(tidyverse)

start_date <- as.Date("2017-11-16")
end_date <- as.Date("2018-02-15")

my_dfs <- list(z1, z2, z3, z4, z5, z6, z7, z8, z9)
my_dfs_filtered <- map(my_dfs, ~filter(.x, Date >= start_date & Date <= end_date))
my_dfs_joined <- reduce(my_dfs_filtered, full_join, by = "Date")

# as pipe
start_date <- as.Date("2017-11-16")
end_date <- as.Date("2018-02-15")

list(z1, z2, z3, z4, z5, z6, z7, z8, z9) %>% 
  map(~filter(.x, Date >= start_date & Date <= end_date)) %>% 
  reduce(full_join, by = "Date")

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...