Lectura listado datasets del Banco Mundial (wb.datasets)
# LECTURA DATOS BÁSICOS DATASETS DISPONIBLES DEL WORLD BANK
# Cargar la caché actual del paquete
# (Opcional: puedes actualizarla a la versión más reciente en línea con new_cache <- wb_cache())
new_cache <- wb_cache()
wb.datasets <- wb_cachelist$indicators |> as_tibble() |>
as_tibble() |>
mutate(topics=unlist(lapply(topics, function(df) ifelse(is.null(df$value),NA,df$value)))) |>
mutate(topics=sub(" $", "", topics)) |>
select(Topic=topics,Id=indicator_id,Indicator=indicator,Indicator_desc=indicator_desc)
wb.datasets
## # A tibble: 16,643 × 4
## Topic Id Indicator Indicator_desc
## <chr> <chr> <chr> <chr>
## 1 Poverty 1.0.HCount.1.90usd Poverty Headcount ($1.90 a day) The poverty h…
## 2 Poverty 1.0.HCount.2.5usd Poverty Headcount ($2.50 a day) The poverty h…
## 3 Poverty 1.0.HCount.Mid10to50 Middle Class ($10-50 a day) Head… The poverty h…
## 4 Poverty 1.0.HCount.Ofcl Official Moderate Poverty Rate-N… The poverty h…
## 5 Poverty 1.0.HCount.Poor4uds Poverty Headcount ($4 a day) The poverty h…
## 6 Poverty 1.0.HCount.Vul4to10 Vulnerable ($4-10 a day) Headcou… The poverty h…
## 7 Poverty 1.0.PGap.1.90usd Poverty Gap ($1.90 a day) The poverty g…
## 8 Poverty 1.0.PGap.2.5usd Poverty Gap ($2.50 a day) The poverty g…
## 9 Poverty 1.0.PGap.Poor4uds Poverty Gap ($4 a day) The poverty g…
## 10 Poverty 1.0.PSev.1.90usd Poverty Severity ($1.90 a day) The poverty s…
## # ℹ 16,633 more rows
Opciones del campo Topic de
wb.datasets
unique(wb.datasets$Topic)
## [1] "Poverty" NA
## [3] "Education" "Social Protection & Labor"
## [5] "Economy & Growth" "Agriculture & Rural Development "
## [7] "Climate Change" "Urban Development"
## [9] "External Debt" "Financial Sector"
## [11] "Aid Effectiveness" "Millenium development goals"
## [13] "Environment" "Energy & Mining"
## [15] "Infrastructure" "Public Sector"
## [17] "Science & Technology" "Private Sector"
## [19] "Trade" "Gender"
## [21] "Health"
DESCARGAMOS TODOS LOS DATASETS PARA OBTENER INFORMACIÓN ADICIONAL
# FUNCIÓN PARA DESCARGAR UN DATASET A PARTIR DE SU INDICADOR
wb.data.download <- function(codigo_indicador, paises = "all", inicio = 1900, fin = 2100, max_intentos = 3, tiempo_espera_seg = 1) {
for (intento in 1:max_intentos) {
datos <- tryCatch({
# Intento de descarga
resultado <- wb_data(indicator = codigo_indicador, country = paises, start_date = inicio, end_date = fin)
return(resultado) # Si tiene éxito, sale de la función y devuelve los datos
}, error = function(e) {
# Si hay un error:
return(NULL) # Devuelve NULL temporalmente para permanecer en el bucle
})
# Si 'datos' no es NULL, significa que la descarga fue exitosa y ya se retornó dentro del tryCatch.
# Si 'datos' es NULL (hubo un error) y no es el último intento, espera un momento.
if (is.null(datos) && intento < max_intentos) {
Sys.sleep(tiempo_espera_seg) # Pausa la ejecución
}
}
# Si el bucle termina sin éxito después de todos los intentos:
return(NULL)
}
# --- CONTROL DE CUELGUES ----------------------------------------------------
# El recorrido son miles de llamadas a la API y puede quedarse esperando
# indefinidamente en una de ellas. Dos medidas:
#
# 1) Se acota el tiempo de cualquier descarga, para que una llamada colgada
# termine en error (que la lógica de reintentos ya sabe manejar) en vez de
# bloquear el documento entero.
# 2) Se deja constancia del avance en un fichero .log con marca de tiempo. Al
# compilar con quiet=TRUE no se ve NADA por consola -los print() van al
# documento, que no existe hasta el final-, así que sin este log no hay forma
# de saber si el proceso avanza o está colgado. El fichero se puede abrir
# mientras compila: la última línea dice por qué dataset va y cuánto tardó.
options(timeout = 60) # conexiones de R base
if(requireNamespace("httr", quietly = TRUE)){
httr::set_config(httr::timeout(60)) # llamadas de wbstats
}
LOG <- "WORLD_BANK_TableDatasetGeneration.log"
cat(format(Sys.time()), "- inicio del recorrido\n", file = LOG)
log_avance <- function(k, n, id, seg){
cat(sprintf("%s %5d/%5d %-28s %6.1f s%s\n",
format(Sys.time()), k, n, id, seg,
if(seg > 30) " <-- LENTO" else ""),
file = LOG, append = TRUE)
}
K <- as.numeric()
N.reg <- as.numeric()
DIM <- as.character()
dateStart <- as.character()
dateEnd <- as.character()
Ndates <- as.numeric()
Ncountries <- as.numeric()
last_updated <- as.character()
for(k in 1:nrow(wb.datasets)){
#for(k in 1:100){
Id <- wb.datasets$Id[k]
#print(paste(k,Id))
t.inicio <- Sys.time()
data <- wb.data.download(Id)
log_avance(k, nrow(wb.datasets), Id,
as.numeric(difftime(Sys.time(), t.inicio, units = "secs")))
# if (!"iso3c" %in% names(data)) stop("El campo 'iso3c' no existe en el tibble")
# if (!"country" %in% names(data)) stop("El campo 'country' no existe en el tibble")
# if (!"date" %in% names(data)) stop("El campo 'date' no existe en el tibble")
for(col in colnames(data)){
if(is.numeric(data[[col]])){
data <- data |> filter(! is.na(!!sym(col)))
}
}
if(is.null(data)){
N.reg <- c(N.reg,0)
DIM <- c(DIM,"*")
K <- c(K,k)
dateStart <- c(dateStart, NA)
dateEnd <- c(dateEnd, NA)
Ndates <- c(Ndates,0)
Ncountries <- c(Ncountries,0)
last_updated <- c(last_updated, NA)
next
}
N.reg <- c(N.reg,nrow(data))
K <- c(K,k)
dim <- ""
dateStart <- c(dateStart, NA)
dateEnd <- c(dateEnd, NA)
Ndates <- c(Ndates,0)
Ncountries <- c(Ncountries,0)
last_updated <- c(last_updated, NA)
for(col in colnames(data)){
if(is.numeric(data[[col]]) & col!="date") next
if(col=="date"){
dateStart[length(dateStart)] <- min(data[[col]])
dateEnd[length(dateStart)] <- max(data[[col]])
Ndates[length(dateStart)] <- length(unique(data[[col]]))
next
}
if(col=="country"){
Ncountries[length(dateStart)] <- length(unique(data[[col]]))
next
}
if(col=="last_updated"){
last_updated[length(dateStart)] <- as.character(data[[col]][1])
next
}
N <- length(unique(data[[col]]))
dim <- paste0(dim,substr(col,1,20)," ",N, " - ")
}
#print(paste(nrow(data),dim))
DIM <- c(DIM,substr(dim,1,nchar(dim)-3))
if(k %% 100 == 0){
tibble(
Nº = K,
Ncountries = Ncountries,
N.reg = N.reg,
dateStart=dateStart,
dateEnd=dateEnd,
Ndates=Ndates,
last_updated=last_updated,
DIM = DIM
) |> write.xlsx("wb.datasets.temporal.xlsx")
}
}
tibble(
Nº = K,
Ncountries = Ncountries,
N.reg = N.reg,
dateStart=dateStart,
dateEnd=dateEnd,
Ndates=Ndates,
last_updated=last_updated,
DIM = DIM
) |> write.xlsx("wb.datasets.temporal.xlsx")
# El recorrido ha llegado al final, así que el guardado parcial ya no sirve para
# nada: se borra para no dejar en la carpeta un fichero a medias que se pueda
# confundir con el catálogo bueno. Si el recorrido se interrumpe, este borrado no
# se ejecuta y el .temporal sobrevive, que es justo para lo que está.
if(file.exists("wb.datasets.temporal.xlsx")) file.remove("wb.datasets.temporal.xlsx")
## [1] TRUE
wb.datasets <- wb.datasets |>
cbind(
tibble(
Nº = K,
Ncountries = Ncountries,
N.reg = N.reg,
dateStart=dateStart,
dateEnd=dateEnd,
Ndates=Ndates,
last_updated=last_updated,
DIM = DIM
)
) |>
relocate(Nº) |>
relocate(Ndates,.after=Indicator)|>
relocate(dateEnd,.after=Indicator)|>
relocate(dateStart,.after=Indicator)|>
relocate(N.reg,.after=Indicator)|>
relocate(Ncountries,.after=Indicator)|>
rename(N.obs=N.reg)|>
rename(ANOTHER.DIMENSIONS=DIM)
Escritura metadatos de los datasets antes de filtrar en wb.datasets.raw.xlsx
wb.datasets |>
write.xlsx("wb.datasets.raw.xlsx")
Escritura metadatos de los datasets filtrados en wb.datasets.xlsx
wb.datasets.filtered <- wb.datasets |>
filter(Ncountries>=100,Ndates>=10) |>
filter(as.numeric(substr(dateEnd,1,4))>=2022)
wb.datasets.filtered|>
mutate(Nº=1:nrow(wb.datasets.filtered)) |>
write.xlsx("wb.datasets.xlsx")