r - 这是在 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)
}
解决方案
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
推荐阅读
- c++ - 尝试将 Linux 网络功能合并到 Winsock 程序中
- c++ - 如何安全地使用 deque::pop_front() 中的元素?
- apache-beam - 如何从 Apache Beam Row 写入 Avro 文件
- javascript - 如何对具有 document.querySelector 的函数进行单元测试?
- matplotlib - 使用 Matplotlib 理解和绘制 L2 正则化
- huawei-mobile-services - 应用程序在 AppGallery 和 GooglePlaystore 中使用相同的包名后,由于 Google Play 保护而被删除
- c# - Serilog ThreadId 始终输出为 1
- amazon-web-services - 使用会话凭据测试 Boto3 客户端
- reactjs - 将具有对象的状态传递给 React 中的另一个兄弟组件并映射它
- gcc - Cortex-M 编译器生成不正确的 FOR 循环