通过闪亮的 WDI 加载世界银行数据的有效方法

Efficiant way to load Wold Bank Data via WDI in shiny

我正在开发一个闪亮的仪表板项目,以可视化世界银行的数据。我总共需要 14 个不同的变量,我想在数据 table 中显示这些变量。它在 R 中有效,但是当我尝试在 shiny 中执行时,出现连接错误。我认为下载需要太多时间。 有没有办法更有效地或在后台加载数据或其他方式?我找不到使它成为 运行 的解决方案,并且我不想将数据存储在服务器上的文件中,因为这样我就没有自动更新...:/

这是一个最基本的重要代码片段

library(shiny)
library(dplyr)
library(WDI)
library(wbstats)
library(lubridate)

ui <- fluidPage(

   titlePanel('WDI Example'),
   mainPanel(tableOutput('table'))

   )


server <- function(input, output) {

  startDate <- as.numeric(format(Sys.Date(), "%Y")) -20
  endDate <- as.numeric(format(Sys.Date(), "%Y"))

  fetch.data <- list() 

  list <- c("SP.POP.TOTL",
            "NY.ADJ.NNTY.PC.CD",
            "SH.XPD.CHEX.PC.CD",
            "SH.XPD.OOPC.CH.ZS",
            "SH.MED.BEDS.ZS",
            "SH.MED.PHYS.ZS",
            "NY.GDP.MKTP.CD",
            "NY.GDP.MKTP.KD",
            "NY.GDP.MKTP.KD.ZG",
            "SH.XPD.CHEX.GD.ZS",
            "SP.DYN.LE00.IN",
            "SP.POP.65UP.TO",
            "SP.POP.DPND",
            "SP.POP.DPND.OL") 

  for (i in 1:length(list)){
    fetch.data[[i]] <- WDI(indicator = as.character(list[i]),
                           start = startDate, 
                           end = endDate,
                           country = "all",
                           extra = TRUE)
  }

  data <- fetch.data


  for (i in 1:length(list)){

    data[[i]] <- subset(data[[i]], region != "Aggregates")
    data[[i]] <- data[[i]] %>% select(country, iso3c, region, year, noquote(list[i]))
    data[[i]]$date <- as.Date(as.character(date), format = "%Y")
    data[[i]] <- data[[i]][complete.cases(data[[i]][ ,5]),]
    data[[i]] <- data[[i]] %>% group_by(country) %>% arrange(desc(date)) %>% slice(1)
  }


  indicators <- fetch.data[[1]] %>% 
    select(country, iso3c, region) %>% 
    subset(region != "Aggregates") %>% 
    arrange(desc(country)) %>% 
    group_by(country) %>% 
    slice(1)


  for (i in 1:length(list)){
    indicators <- merge(indicators, data[[i]][ ,c(2,5)], by.x = "iso3c", by.y = "iso3c", all = TRUE)
  }


  indicators <- indicators %>% 
    arrange(country) %>% 
    mutate_if(is.numeric, round, 2)

  output$table <- renderTable(indicators)

}

shinyApp(ui = ui, server = server)

这是一个不起作用的例子……https://thera-trainer.shinyapps.io/example/

谢谢指教

错误

你的错误在这行代码中:

data[[i]]$date <- as.Date(as.character(date), format = "%Y")

date 是一个函数(闭包),这就是您收到错误的原因。如果您要引用数据框中的列,则需要使用 data[[i]]$date,如

data[[i]]$date <- as.Date(as.character(data[[i]]$date), format = "%Y")

您可能已经习惯了 tidyverse,您不需要在列的数据框前加上前缀,但在使用非 tidyverse 操作时,例如 <-,您还必须包括数据框名称。此外,data[[i]] 中没有名为 date 的列,因此即使您使用了 as.Date(as.character(data[[i]]$date), format = "%Y"),您也会收到错误消息,因为该列不存在。

此外,您似乎正在尝试将日期转换为年份,但 data[[i]] 中已经有一个名为 year 的列,您可以使用 [=23= 引用它].

代码风格

使用与函数名称相匹配的名称来命名对象不是好的做法。您已经完成了两次,一次是通过将 fetch.data 分配给 data(已经有一个函数 utils::data(),更重要的是,您已将指标分配给一个名为 list 的变量。这是 非常 危险的,因为您已经覆盖了全局环境中的 list() 函数,稍后要再次使用列表函数,您将不得不使用 [=29 调用它=]。我会为指标推荐一个更情绪化的名字,比如:

indicators_list <- c("SP.POP.TOTL",
            "NY.ADJ.NNTY.PC.CD",
            "SH.XPD.CHEX.PC.CD",
            "SH.XPD.OOPC.CH.ZS",
            "SH.MED.BEDS.ZS",
            "SH.MED.PHYS.ZS",
            "NY.GDP.MKTP.CD",
            "NY.GDP.MKTP.KD",
            "NY.GDP.MKTP.KD.ZG",
            "SH.XPD.CHEX.GD.ZS",
            "SP.DYN.LE00.IN",
            "SP.POP.65UP.TO",
            "SP.POP.DPND",
            "SP.POP.DPND.OL") 

withProgress

有一个 Shiny progress indicator 可以用来监视需要很长时间的循环。你会像这样包括它;

  withProgress(
    for (i in 1:length(indicators_list)){
      incProgress(1/length(indicators_list), detail = paste("Doing part", i))
      fetch.data[[i]] <- WDI(indicator = indicators_list[i],
                             start = startDate, 
                             end = endDate,
                             country = "all",
                             extra = TRUE)
  })

完整示例

这是我能够开始工作的完整示例。我只包含服务器组件,因为这是我进行更改的唯一组件。

server <- function(input, output) {

  startDate <- as.numeric(format(Sys.Date(), "%Y")) -20
  endDate <- as.numeric(format(Sys.Date(), "%Y"))

  fetch.data <- list() 

  indicators_list <- c("SP.POP.TOTL",
                  "NY.ADJ.NNTY.PC.CD",
                  "SH.XPD.CHEX.PC.CD",
                  "SH.XPD.OOPC.CH.ZS",
                  "SH.MED.BEDS.ZS",
                  "SH.MED.PHYS.ZS",
                  "NY.GDP.MKTP.CD",
                  "NY.GDP.MKTP.KD",
                  "NY.GDP.MKTP.KD.ZG",
                  "SH.XPD.CHEX.GD.ZS",
                  "SP.DYN.LE00.IN",
                  "SP.POP.65UP.TO",
                  "SP.POP.DPND",
                  "SP.POP.DPND.OL") 

  withProgress(
    for (i in 1:length(indicators_list)){
      incProgress(1/length(indicators_list), detail = paste("Doing part", i))
      fetch.data[[i]] <- WDI(indicator = indicators_list[i],
                             start = startDate, 
                             end = endDate,
                             country = "all",
                             extra = TRUE)
  })

  data <- fetch.data


  for (i in 1:length(indicators_list)){

    data[[i]] <- subset(data[[i]], region != "Aggregates")
    data[[i]] <- data[[i]] %>% select(country, iso3c, region, year, noquote(indicators_list[i]))
    data[[i]]$date <- data[[i]]$year
    data[[i]] <- data[[i]][complete.cases(data[[i]][ ,5]),]
    data[[i]] <- data[[i]] %>% group_by(country) %>% arrange(desc(date)) %>% slice(1)
  }


  indicators <- fetch.data[[1]] %>% 
    select(country, iso3c, region) %>% 
    subset(region != "Aggregates") %>% 
    arrange(desc(country)) %>% 
    group_by(country) %>% 
    slice(1)


  for (i in 1:length(indicators_list)){
    indicators <- merge(indicators, data[[i]][ ,c(2,5)], by.x = "iso3c", by.y = "iso3c", all = TRUE)
  }


  indicators <- indicators %>% 
    arrange(country) %>% 
    mutate_if(is.numeric, round, 2)

  output$table <- renderTable(indicators)

}