首页 > 解决方案 > 这是在 R 中迭代和捕获 API 输出的最简洁方法吗?

问题描述

我想遍历一系列年份并在一个大数据框中捕获每个输出。该查询一次只允许请求一年的数据,所以我认为我可以运行如下所示的循环并捕获到一个空的数据帧中。这似乎可行,但我想知道是否有更简洁的方法来实现这一点。

万一有人感兴趣。API 信息和注册:https ://aqs.epa.gov/aqsweb/documents/data_api.html#bdate

library("jsonlite")
library(lubridate)
base_url_site <- "https://aqs.epa.gov/data/api/sampleData/bySite"

years <- as.character(2011:2019)
dat = {}
for (year in years) {
  my_raw_result <- httr::GET(base_url_site,
                             query = list(email="example@email.com",key=Sys.getenv("AQS_KEY"),
                                          param = "44201",
                                          bdate=paste(year,"0101",sep = ""),
                                          edate=paste(year,"1231",sep = ""),state="48",
                                          county="141", site="0055"))
  my_content <- httr::content(my_raw_result, as = 'text')
  my_content_from_json <- fromJSON(my_content)
  df <- my_content_from_json$Data
  dat = rbind(dat,df)
}

标签: r

解决方案


rbind()通过仅使用一次而不是在循环中迭代可以获得稍微更有效的解决方案。我们可以结合使用 Base R 和lapply(). 使代码正常工作的关键更改是将fromJSON()函数的列表输出转换为数据框,这在与原始问题一起发布的代码中无法正常工作。

# set private key
Sys.setenv(AQS_KEY = "yourKeyGoesHere")

base_url_site <- "https://aqs.epa.gov/data/api/sampleData/bySite"
library(RJSONIO)
library(tidyr)
years <- as.character(2011:2019)

system.time(dfList <- lapply(years,function(year){
     my_raw_result <- httr::GET(base_url_site,
                                query = list(email="example@gmail.com",key=Sys.getenv("AQS_KEY"),
                                             param = "44201",
                                             bdate=paste(year,"0101",sep = ""),
                                             edate=paste(year,"1231",sep = ""),state="48",
                                             county="141", site="0055"))
     my_content <- httr::content(my_raw_result, as = 'text')
     my_content_from_json <- fromJSON(my_content)
     df <- data.frame(t(sapply(my_content_from_json$Data,c))) 
     df$uncertainty <- " "
     tidyr::unnest(df,cols = colnames(df)) # unnest & return to parent
}))
system.time(combinedData <- do.call(rbind,dfList))

从 EPA 数据库中提取 2011 - 2019 年的代码在大约 46.8 秒的用户时间内运行,包括初始提取、每个结果数据结构的取消嵌套以及最后数据帧的一次性组合。

   user  system elapsed 
 46.670   0.756  71.432 
> system.time(combinedData <- data.frame(do.call(rbind,dfList)))
   user  system elapsed 
  0.096   0.027   0.123 

用户时间和经过时间之间的巨大差异可能是由于从 API 接收数据的等待时间。

该解决方案的一个关键特性是用于将列表列表转换为数据框行的技术,其完成方式如下(h/t Alex Brown 对Convert a List to a Data Frame的回答,以及结果的取消嵌套数据结构tidyr::unnest()。我们还必须将uncertainty列设置为空白,因为unnest()从 EPA API 提取的 NULL 值失败。

 df <- data.frame(t(sapply(my_content_from_json$Data,c)))
 df$uncertainty <- " "
 tidyr::unnest(df,cols = colnames(df)) # unnest & return to parent

组合数据框的输出如下所示。

> head(combinedData)
  state_code county_code site_number parameter_code poc latitude longitude datum
1         48         141        0055          44201   1 31.74677 -106.4028 WGS84
2         48         141        0055          44201   1 31.74677 -106.4028 WGS84
3         48         141        0055          44201   1 31.74677 -106.4028 WGS84
4         48         141        0055          44201   1 31.74677 -106.4028 WGS84
5         48         141        0055          44201   1 31.74677 -106.4028 WGS84
6         48         141        0055          44201   1 31.74677 -106.4028 WGS84
  parameter date_local time_local   date_gmt time_gmt sample_measurement
1     Ozone 2011-12-31      23:00 2012-01-01    06:00              0.023
2     Ozone 2011-12-31      22:00 2012-01-01    05:00                 NA
3     Ozone 2011-12-31      21:00 2012-01-01    04:00                 NA
4     Ozone 2011-12-31      20:00 2012-01-01    03:00              0.018
5     Ozone 2011-12-31      19:00 2012-01-01    02:00              0.006
6     Ozone 2011-12-31      18:00 2012-01-01    01:00              0.002
   units_of_measure units_of_measure_code sample_duration sample_duration_code
1 Parts per million                   007          1 HOUR                    1
2 Parts per million                   007          1 HOUR                    1
3 Parts per million                   007          1 HOUR                    1
4 Parts per million                   007          1 HOUR                    1
5 Parts per million                   007          1 HOUR                    1
6 Parts per million                   007          1 HOUR                    1
                sample_frequency detection_limit uncertainty
1 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
2 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
3 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
4 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
5 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
6 DAILY: 24 - 1 HR SAMPLES -PAMS           0.005            
                  qualifier method_type                                 method
1                      <NA>         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
2 BF - Precision/Zero/Span.         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
3 BF - Precision/Zero/Span.         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
4                      <NA>         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
5                      <NA>         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
6                      <NA>         FEM INSTRUMENTAL - ULTRA VIOLET ABSORPTION
  method_code state  county date_of_last_change cbsa_code
1         087 Texas El Paso          2012-01-23     21340
2         087 Texas El Paso          2012-01-23     21340
3         087 Texas El Paso          2012-01-23     21340
4         087 Texas El Paso          2012-01-23     21340
5         087 Texas El Paso          2012-01-23     21340
6         087 Texas El Paso          2012-01-23     21340

原始代码经过更新以生成没有嵌套列表的数据框,运行时间约为 43.6 秒,比lapply()版本快了约 3 秒,这有点令人惊讶。

base_url_site <- "https://aqs.epa.gov/data/api/sampleData/bySite"

years <- as.character(2011:2019)
dat = {}
 
system.time(for (year in years) {
     my_raw_result <- httr::GET(base_url_site,
                                query = list(email="example@gmail.com",key=Sys.getenv("AQS_KEY"),
                                             param = "44201",
                                             bdate=paste(year,"0101",sep = ""),
                                             edate=paste(year,"1231",sep = ""),state="48",
                                             county="141", site="0055"))
     my_content <- httr::content(my_raw_result, as = 'text')
     my_content_from_json <- fromJSON(my_content)
     dataList <- my_content_from_json$Data
     df <- data.frame(t(sapply(dataList,c)))[!(colnames(df) == "uncertainty")]
     unnestedDf <- tidyr::unnest(df,cols = colnames(df))
     dat <- rbind(dat,unnestedDf)
 })

...以及运行时统计信息,它们显示相对于用户时间的相同经过时间模式:

   user  system elapsed 
 43.586   0.686  66.604  

推荐阅读