R Невозможно выполнить rbind в функции lapply

Я начинаю с создания пустого фрейма данных:

results <- data.frame(ID=numeric(0), StartDate=numeric(0), term_type=character(0), EndDate=numeric(0), stringsAsFactors = FALSE)

Затем у меня есть список уникальных идентификационных номеров: uniqueIds ‹- c (1234, 4566, 7838)

У меня есть функция getDataForGivenId, которая создает фрейм данных в формате:

ID, StartDate, term_type, EndDate

Мне нужен код для вызова функции getDataForGivenId для каждого идентификатора и добавления результирующего фрейма данных в пустой фрейм данных results.

Я пытался:

library(dplyr)

results <- bind_rows(results, (lapply(uniqueIds, getDataForGivenId)))

и

do.call("rbind", lapply(uniqueIds, getDataForGivenId))

и

for (Id in uniqueIds) {
    Y <- getDataForGivenId(Id)
    results <- rbind(results, Y) 
}

Каждый раз я получаю пустой results фрейм данных.

Обратите внимание, что если я выхожу из цикла и просто выполняю код:

Y <- getDataForGivenId(1234)
results <- rbind(results, Y)

Я получаю ожидаемый результат.

Кто-нибудь знает, что я делаю не так?

ИЗМЕНИТЬ - Мой полный сценарий ниже.

library(dplyr)
library(lubridate)

enVariables <- Sys.getenv()
username    <- enVariables[["DB_USERNAME"]]
password    <- enVariables[["DB_PASSWORD"]]

results <- data.frame(ID=numeric(0), StartDate=numeric(0), term_type=character(0), EndDate=numeric(0), stringsAsFactors = FALSE)

getConnection <- function(){
  require(RMySQL)
  username <- username
  password <- password 
  con <- dbConnect(
    MySQL(), user=username, password=password, 
    dbname='database', host='host', port=port
  )
  return(con)
}

queryuniqueIds <- "SELECT DISTINCT(id) FROM table LIMIT 5"
con                <- getConnection()
uniqueIds      <- dbGetQuery(con, queryuniqueIds)
dbDisconnect(con)

getDataForGivenID <- function(idNumber) {
  queryData <- paste0(
    "SELECT ",
    "Id, bill_date, bill_hour ",
    "FROM table ",
    "WHERE id = ", idNumber
  ) 
  con <- getConnection()
  Data <- dbGetQuery(con, queryData)
  dbDisconnect(con)
  X <- Data %>% 
    select(ID, bill_date, bill_hour) %>%
    mutate(
      bill_date_x = ymd_hms(bill_date)
    ) %>% 
    arrange(ID, bill_date, bill_hour)
  hour(X$bill_date_x) <- X$bill_hour
  X <- X %>% 
    mutate(
      lag_x     = lag(bill_date_x, 1),
      lag_diff  = difftime(bill_date_x,lag_x, units = "hours") %>% as.integer(),
      lead_x    = lead(bill_date_x, 1),
      lead_diff = difftime(lead_x, bill_date_x, units = "hours") %>% as.integer()
    )
  Y <- X %>% 
    filter(
      is.na(lag_diff) | 
        is.na(lead_diff) | 
        !(lag_diff == 1 & lead_diff == 1),

      is.na(lag_diff) | 
        is.na(lead_diff) | 
        !(lag_diff == 0 | lead_diff == 0)
    ) %>% 
    mutate(
      term_type = "N",
      term_type = replace(term_type, lead_diff == 1, "S"),
      term_type = replace(term_type, lag_diff  == 1, "E")
    )
  Y <- Y %>%
    select(ID, bill_date_x, term_type) %>% 
    mutate(
      lead_date = lead(bill_date_x, 1)
    )  %>% 
    filter(term_type == "S")
  colnames(Y) <- c("ID", "StartDate", "term_type", "EndDate")
  return(Y)
}

do.call("rbind", lapply(uniqueIds, getDataForGivenID))
View(results)

person OnlyDean    schedule 25.06.2018    source источник
comment
Первое, что я хотел бы проверить, это действительно ли getDataForGivenId возвращает непустые фреймы данных.   -  person joran    schedule 25.06.2018
comment
Он возвращает заполненные DataFrames, я это проверил.   -  person OnlyDean    schedule 25.06.2018
comment
В этом случае происходит что-то еще, с чем мы, вероятно, не сможем помочь или догадаться без более воспроизводимого примера. Поскольку if lapply на самом деле возвращает список непустых фреймов данных, строка do.call будет работать, что говорит мне о том, что происходит что-то еще, чего мы не делаем не знаю о.   -  person joran    schedule 25.06.2018
comment
Обращаясь за помощью, вы должны указать простой воспроизводимый пример с образцом ввода и желаемым выходом, которые можно использовать для тестирования и проверки возможных решений.   -  person MrFlick    schedule 25.06.2018
comment
так что я предполагаю, что getDataForGivenId - это список фреймов данных?   -  person YOLO    schedule 25.06.2018
comment
@YOLO нет, getDataForGivenId - это функция, которая возвращает фрейм данных и принимает идентификатор в качестве аргумента.   -  person OnlyDean    schedule 25.06.2018
comment
@joran Я загрузил весь свой сценарий.   -  person OnlyDean    schedule 25.06.2018
comment
@MrFlick Я загрузил весь свой скрипт   -  person OnlyDean    schedule 25.06.2018
comment
С этим будет сложно помочь. Нам по-прежнему приходится верить вам, что lapply(uniqueIds, getDataForGivenID) успешно возвращает список непустых фреймов данных. Но если я просто создам список непустых фреймов данных с указанными вами столбцами, do.call("rbind",...) будет отлично работать каждый раз, когда я его тестирую. Частично воспроизводимый бит здесь пытается помочь вам пройти процесс отладки. Запустите lapply(uniqueIds, getDataForGivenID) и поделитесь фактическим выводом через dput.   -  person joran    schedule 25.06.2018


Ответы (1)


Я наконец понял свою проблему.

Список uniqueIds имел длину 1. R передавал весь список как один раз, в результате чего оператор SQL возвращал данные только для первого идентификатора.

Я изменился

uniqueIds <- dbGetQuery(con, queryuniqueIds) 

to

uniqueIds <- as.data.frame(dbGetQuery(con, queryuniqueIds))

и

do.call("rbind", lapply(uniqueIds, getDataForGivenId))

to

results <- do.call("rbind", lapply(uniqueIds$id, getDataForGivenId))

Теперь все работает, как ожидалось. Спасибо тем, кто помогал.

person OnlyDean    schedule 25.06.2018