Способы оптимизации вложенного цикла с добавлением списка? - PullRequest
0 голосов
/ 02 января 2019

Я извлекаю данные по конкретным географическим районам и конкретным показателям из агентства общественного здравоохранения в Великобритании, используя пакет, который они разработали для извлечения данных из их API, под названием fingertipsR, а затем вставляю их в пустой список, гдесписок состоит из списков (географических регионов), которые содержат списки, представляющие каждый индикатор.

geog <- c("E38000220", "E38000046", "E38000144", "E38000191", "E38000210", 
"E38000038", "E38000164", "E38000195", "E38000078", "E38000139", 
"E38000166", "E38000211", "E38000147", "E38000183", "E38000028", 
"E38000053", "E38000126", "E38000153", "E38000173", "E38000175"
)
indicators <- c(241, 92588, 90672, 90692, 90697, 90698, 90701, 90702, 91238, 
90690, 90694, 93245, 93246, 93244, 93247, 93248, 93049, 93047, 
90700)

## install.packages("fingertipsR"); library(fingertipsR)
library(dplyr)

list <- list()

start <- Sys.time()
for (geog_group in geog) {
    for (indicator_number in indicators) {
    list[[geog_group]][[as.character(indicator_number)]] <- fingertips_data(IndicatorID = indicator_number, AreaTypeID = c(152, 153, 154)) %>% 
      filter(AreaCode == geog_group, TimeperiodSortable == max(TimeperiodSortable)) %>% 
      select(Timeperiod, Value) %>% distinct()
  }
}
end <- Sys.time()
end-start

На моем рабочем ноутбуке это занимает около 15 минут - мне интересно, есть ли какие-нибудь простые способы оптимизировать этот код- возможно с lapply или purrr?

Редактировать: в идеале я хочу, чтобы индикаторы для каждой географической области были в одном фрейме данных, так как все они имеют одинаковые столбцы Time period и Value -Я собирался разобраться с этим после unlist() или чего-то подобного - но если у кого-то есть способы решить это внутри цикла for, я открыт для предложений.

1 Ответ

0 голосов
/ 02 января 2019

Вот более сжатый цикл (примерно 25 секунд)

result_list <- list(length(indicators))
for (k in seq_along(indicators)) {
  ind   <- indicators[k]
  # load the data once per indicator
  tmpDF <- fingertips_data(IndicatorID = ind, AreaTypeID = 152:154)
  # retrieve the rows corresp. to max per geog
  out <- t(vapply(seq_along(geog), function (s) {
    row_geog <- which(.subset2(tmpDF, which(names(tmpDF) == 'AreaCode')) == geog[s])
    row_max <- which.max(.subset2(tmpDF, which(names(tmpDF) == 'TimeperiodSortable'))[row_geog])
    res <- tmpDF[row_geog,c("Timeperiod","Value")][row_max,]
    res <- c(Timeperiod = res$Timeperiod, Value = res$Value)
    if (length(res) == 0) res <- c(Timeperiod = NA_character_, Value = NA_character_)
    return (res)
  }, character(2)))
  # save result for indicator[k]
  result_list[[k]] <- data.frame(indicator = ind, geog, 
                                 Timeperiod = out[,1], 
                                 Value = as.numeric(out[,2]),
                                 stringsAsFactors = FALSE)  
}

Я не очень знаком с fingertipsR, но, похоже, работа выполнена (поправьте меня, если я ошибаюсь), вот первый элемент результата:

head(result_list[[1]])
# indicator      geog Timeperiod    Value
# 1       241 E38000220    2017/18 8.214912
# 2       241 E38000046    2017/18 7.907130
# 3       241 E38000144    2017/18 9.139239
# 4       241 E38000191    2017/18 8.891195
# 5       241 E38000210    2017/18 8.311592
# 6       241 E38000038    2017/18 6.653444

Изменения

Вот что я изменил из вашей версии:

  • Я написал только один цикл for (строго говоря, в моей версии все еще есть два цикла, поскольку я использую vapply), итерирующий по индикаторам. Основная причина была даже не в том, чтобы иметь меньше циклов (что само по себе уже достаточно мотивирует), а в том, чтобы вызывать функцию fingertips_data как можно реже: эти вызовы функций очень медленные и не зависят только от geog подмножество делает.
  • Таким образом, для каждого indicator функция fingertips_data вызывается один раз, а затем с помощью vapply выполняется поднабор и определение максимума
  • В результате выходные данные имеют немного другой формат, но по существу они содержат ту же информацию
...