【问题标题】:wildcards to download particular csv用于下载特定 csv 的通配符
【发布时间】:2021-09-07 22:31:01
【问题描述】:

对 R 还是很陌生,所以请见谅。

我正在尝试从 Sloane 数字网站调查下载 csv 数据。在 R 中,我执行以下操作 -

astro1 <- read.csv("https://dr14.sdss.org/optical/spectrum/view/data/format=csv/spec=full?mjd=55359&fiberid=596&plateid=4055")

这会为每个板的每个光纤 ID 下载 1 个 csv 光谱 [此处,plateid=4055]。但是,如果有数百个光纤 ID,这将是很长的几天。

  1. 有没有办法批量下载所有光纤 ID 的所有 csv 数据?我试过fibreid=*(和“”,“”,@,但得到以下错误-

    “输入中没有可用的行”,或意外的字符串常量。

  2. 例如,如果每个板有 100 个 .csv 文件。所有将有一个共同的 x 轴(波长),但不同的第 3 列(最适合,y 轴)。有没有办法让下载的 csv 表形成 1 个非常大的数据集,具有相同的公共轴(波长),以及后续列以仅显示最佳拟合列?

很多感谢

【问题讨论】:

  • 你能得到一份你需要的所有文件的列表吗?这样你就可以循环下载文件。从 2 开始,是的,循环读取所有内容,然后使用连接创建一个表。具体如何做到这一点取决于表格的格式。

标签: r csv web web-scraping download


【解决方案1】:

最好的情况是您拥有指向所需 csv 文件的所有链接的列表。由于情况似乎并非如此,因此您知道您想要遍历所有fiberids。您知道链接的结构,因此我们可以使用它来定义

buildFibreIdLink <- function(fibreId) {
  paste0("https://dr14.sdss.org/optical/spectrum/view/data/format=csv/spec=full?mjd=55359&fiberid=",fibreId,"&plateid=4055")
}

现在我将遍历所有 id,无论在这种情况下意味着什么。只需从 1 开始计数。因此我会使用该功能

getCsvDataList <- function(startId = 1, endId = 10, maxConsecutiveNulls = 5) {
  
  dataList <- list()
  consecutiveNullCount <- 0
  
  for(id in startId:endId) {
    csvLink <- buildFibreIdLink(fibreId = id)
    newData <- tryCatch(expr = {
      read.csv(csvLink)
    }, error = function(e) {return(NULL)})
    if(is.null(newData)) {
      consecutiveNullCount <- consecutiveNullCount +1
    } else {
      dataList <- c(dataList,list(newData))
      consecutiveNullCount <- 0
    }
    if(consecutiveNullCount == maxConsecutiveNulls) {
      print(paste0("reached maxConsecutiveNulls at id ",id))
      break;
    }
  }
  
  return(dataList)
}

指定您要读取的 id-range,以便您可以真正部分读取 csv。现在的问题是:你什么时候到达终点?我的回答基本上是:当有maxConsecutiveNulls 连续的“read-csv-fails”时,你已经走到了尽头。我假设如果您无法阅读链接,则该链接不存在,因此tryCatch-block 触发器,我基本上将这些触发器计数到给定的最大值。

如果你知道 csvs 的结构总是相同的,你可以通过以下方式将 data.frames 列表合并在一起

dataListFrom1to10 <- getCsvDataList(startId = 1, endId = 10)
merged1to10 <- do.call("rbind",dataListFrom1to10)

更新:如果您有所需的光纤 ID 向量,您可以按如下方式修改函数。由于我们不知道确切的 Id,我们从 1 循环到任何地方。现在,知道了 ID,您可以将 startIdendId 参数替换为 fibreIdVector,以获得签名 getCsvDataList &lt;- function(fibreIdVector, maxConsecutiveNulls) ...。在for 循环中,将for(id in startId:endId) 替换为for(id in fibreIdVector)。如果您知道您的所有 Id 都是有效的,您可以删除错误处理以获得更清晰的功能。由于您不需要知道先前迭代的结果,例如算上consecutiveNullCount,你可以把所有的东西都放到lapply

allCsvData <- lapply(fibreIdVector, function(id) {
  read.csv(buildFibreIdLink(fibreId = id))
})

替换整个函数。

【讨论】:

  • tryCatch 的使用使这个非常通用和有用。在这种情况下,光纤的数量是已知的,具体取决于望远镜架构,SDSS fibreFiberID:表示光纤数量的整数(SDSS-I/II 为 1 到 640;BOSS 为 1 到 1000)。将按照指示采用这种方法。
  • 感谢大家分享您的见解,非常感谢。
  • Jonas,经过一番挖掘和后见之明,我找到了一种方法来指定所需的 fiberID。根据我的新手身份,我可以生成一个带有所需光纤 ID 的 excel csv 表 - 这可能是多达 150 个这样的数字。能否轻松修改 buildFibreIDlink 及后续代码以读取这样的表?
  • 如果你还没有自己弄清楚,我现在已经更新了答案。
  • 嗨乔纳斯,这远远超出了我以前见过的范围,我需要几天时间才能完成它,谢谢
猜你喜欢
  • 2017-01-28
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 2019-03-03
  • 1970-01-01
  • 2020-01-31
  • 2022-01-11
  • 1970-01-01
相关资源
最近更新 更多