如何使用带有 pdftools 和 html 链接的自定义函数在 R 中一次将大量列突变到数据框上?

How to mutate a large number of columns onto a data frame at once in R using a custom function with pdftools and html links?

抱歉,如果这篇文章太长或结构不正确,这是我的第一个问题,也是第一个主要的 R 端项目!让我知道我是否应该为将来更改我的问题。

我目前正在处理一些存储相当奇怪的城市交通数据。不是将每个交叉路口的数据存储在可下载的 csv 文件中,而是 link 到一个网站,该网站包含 html link 以前所有交通调查的 PDF 格式。

我已经为每个交通路口提取了最新的 PDF,但是我无法让我的函数读取 PDF 并且 return 在输入 mapply 和 mutate 时数据无法正常工作。我之前编写了一个函数,能够将 PDF 格式和 PDF link 作为输入,并 returning 一个 1 行 55 列的数据框,其中包含该十字路口的所有交通数据。

现在,我似乎无法让函数在 mapply/with mutate 中工作。该函数在下面,但它需要两个输入,用于 PDF 的调查类型和 PDF link 到有问题的 PDF,以及 returns 上面提到的数据框。

当简单地单独使用 mapply 时,我认为该函数将整个调查类型列/整个 PDF link 列作为一个整体用于函数中的变量,而不是遍历整个列。

在 mutate 内部使用 mapply 时,它似乎在两列上正确循环,但我不确定如何使用 mutate 一次正确添加大量列。理想情况下,我会简单地以正确的顺序制作列名称的向量,并使用 mutate 或一些类似 mutate 的函数将 mapply 的结果分配给列列表,即

类变异(traffic_westwood,col-names = mapply(get_data,SURVEY_TYPE,PDF))

因此我有两个问题:

  1. mapply 如何与我下面的代码相关联?我是否误解了 mapply 如何在两列上循环,或者我的函数没有正确矢量化?我应该为此任务使用不同于 mapply 的循环函数吗?

  2. 是否有一个函数可以用来分配循环遍历感兴趣的两列并将 PDF 数据提取到列名称列表的结果,然后将这些列添加到我的数据框中?

之前,我尝试将 mapply 调用放入 mutate 中,如上所述,但它仍然需要一种方法将 55 列分配给名称列表。

此外,当我意识到循环我需要的两列比尝试对整行执行我的自定义函数更容易时,我切换到 mapply 而不是 lapply。

另请注意,mapply 调用中使用的 SURVEY_TYPE 列和 PDF 列都是正确的维度,每个插槽中的值都可以接受:我已经检查过了。

请注意,我的代码理想情况下适用于包含以下两列 SURVEY_TYPE 和 PDF 的任何维度的任何输入有限数据框。 SURVEY_TYPE 包含 'Auto' 以指示自动调查类型和 'Manual' 以指示手动调查类型。 PDF 包含 strings/PDF html links 的向量,其中 SURVEY_TYPE = 'Auto' 和单个 string/PDF html link 如果 SURVEY_TYPE = 'Manual' 该行。

有关洛杉矶市人工交通调查 PDF link 的示例,请检查下面打印的已关闭连接的错误消息,其中应包含多个此类 link。

#This function obtains a data frame with rows of 55 entries for each intersection with manual data.
#Automatic data only intersections have blank rows for now.
get_data <- function(survey_type, pdf_link){

  #Return data frame of empty row if type was auto. I'm fine on this part.
  if(survey_type == 'Auto'){
    ...
    return(data.frame(#Whatever I want for auto, empty 1 row 55 cols for now))
  }

  #Now we read in this entries manual pdf data.

  #Read in the first pdf.
  pdf1 <- pdf_text(toString(pdf_link))


  #Get the handle for this file..
  file1 <- file("Traffic_Data_Files/pdf1.txt", 'w')

  #Write the PDF contents to the file.
  write(pdf1, file = file1, sep = '\t')

  #Close the file and reopen it.
  close(file1)
  file1 <- file("Traffic_Data_Files/pdf1.txt", 'r')

  #Here is where I had code to get the data frame we will return and extract the 
  #data to it. Note that #the data frame will be 1 row and 55 columns and will  
  #be called 'intersection1'.
  #I have tested this code, which works on a single file to return such data.

  #Return the info for this intersection.
  return(intersection1)

}

#Use lapply on the traffic data.
manual_intersections <- mutate(traffic_westwood, Data = mapply(get_data, SURVEY_TYPE, PDF))

理想情况下,我想直接将55行填充信息附加到当前数据框上。当然,我可以只获取一个包含行的新数据框,并在必要时作为中间步骤将其附加到旧数据框。

当我将 mapply 调用保留在上面最后一行的 mutate 调用之外时,会出现以下错误消息(对我来说,它似乎无法判断列是向量,并首先检查 SURVEY_TYPE == 'Auto' 在列的第一个组件而不是元素方面):

Error in open.connection(con, "rb") : cannot open the connection
In addition: Warning messages:
1: In if (survey_type == "Auto") { :
  the condition has length > 1 and only the first element will be used
2: In open.connection(con, "rb") :
  cannot open URL 'http://navigatela.lacity.org/dot/traffic_data/manual_counts/46972_WESWEY96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/46974_KINWES96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/Gayley.Weyburn.180927-NDSMAN.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12599_GAYVET96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/gaylec06.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12690_BROLEC95.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12691_BROXTON.WEYBURN07.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12995_HILLEC95.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/13531_LECWES96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/13997_VETWIL081021.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/SELWIL080319.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/16896_GLELIN96.pdf, http [... truncated]

当我如代码所示在 mutate 中调用 mapply 并尝试将调用分配给单个变量时,乍一看我认为它不能将整个结果行分配给单个列条目。因此,我的问题是如何使用 mutate 中的任意自定义函数或类似函数的 mutate 将大量列分配给名称列表:

Error in eval(substitute(expr), envir, enclos) : 
  more columns than column names
In addition: Warning message:
closing unused connection 3 (http://navigatela.lacity.org/dot/traffic_data/manual_counts/46972_WESWEY96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/46974_KINWES96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/Gayley.Weyburn.180927-NDSMAN.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12599_GAYVET96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/gaylec06.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12690_BROLEC95.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12691_BROXTON.WEYBURN07.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/12995_HILLEC95.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/13531_LECWES96.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/13997_VETWIL081021.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/SELWIL080319.pdf, http://navigatela.lacity.org/dot/traffic_data/manual_counts/16896_GLELIN [... truncated]
'''

EDIT: Further examination of my code for creating a minimal example revealed other problems. I will update when I am farther along

我弄清楚了为什么我的代码不起作用。事实证明,PDF 虽然以相同的格式编写,但 PDFTools 读取的方式不同,因为看似相同的 table/title 格式之间存在几个明显的间距差异。这就是导致问题第二部分出现错误消息的原因,因为我在从文件中读取 csv 的函数中假定的行数对于这些不同格式的 PDF 是不正确的。

因此,我需要确定我的功能在哪些 PDF 上失败,创建第二种或可能更多类型的手动调查,并调整从 PDFS 读取数据的功能以处理所有不同类型的手动调查。感谢评论中关于找到最小可重现数据集的建议:运行 玩具数据集上的函数而不是完整数据集的过程让我发现了这一点。