繁体   English   中英

分配给转换后的 Date 对象列表的值与函数中返回值的值不同

[英]Assigned value to list of a converted Date object differs from that of a returned value in function

我有一个函数可以返回运动员的许多属性,其中一个是他们的出生日期,通过网络抓取官方国际田联体育页面。 为了这个问题,我已经稍微修改了它:

upscope_list <- list()

library(xml2)
library(tidyverse)
library(stringi)
library(rvest)

scrape_function_mod <- function(athlete_name) {
  
  starting_name <- stri_trans_general(athlete_name, "latin-ascii")
  
  initial_url <-
    paste0("https://www.iaaf.org/athletes/search?query=", starting_name)
  initial_search_page <- read_html(initial_url)
  
  rawnodes_text <-
    initial_search_page %>% html_nodes("table td") %>% html_text(trim = T) %>% stri_trans_general("latin-ascii")
  
  name_split <- as_vector(strsplit(starting_name, " ", fixed = T))
  number <- which(sapply(rawnodes_text, function(x)
    grepl(name_split[1], x, ignore.case = T) &
      grepl(name_split[length(name_split)], x, ignore.case = T)))
  
  upscope_list[[athlete_name]][["birth_date"]] <<-
    rawnodes_text[(number + 4)] %>% as.Date("%d %B %Y")
  
  return(rawnodes_text[(number + 4)] %>% as.Date("%d %B %Y"))
  
}

除了最后两行,大部分函数代码并不重要。 如果我运行:

> scrape_function_mod("Ashton Eaton")
[1] "1988-01-21"

这将返回运动员出生日期的正确 Date 对象,但是通过返回一个我无法理解的数字四位数字,我插入到开始时创建的列表中的值不同。

> upscope_list[["Ashton Eaton"]][["birth_date"]]
[1] 6594

您可以看到,与我返回的内容相比,我分配给列表的内容应该几乎相同,但事实并非如此。 有什么提示可以让它在函数内正确转换?

如评论中所述,您的日期已转换为数字

> as.numeric(as.Date("1988-01-21"))
[1] 6594

这是一个已知问题,请参见此处:

已知问题可以通过 hadleys 示例得到最好的证明: https : //github.com/tidyverse/purrr/issues/358#issuecomment-363091446

> x <- list(as.Date("1988-01-21"))
> x[[1]]
[1] "1988-01-21"
> x[[c(1, 1)]]
[1] 6594

正如您在线程中看到的, purr r` 中的pmap问题已解决。 你可以切换到那个包,或者你可以用不同的方式分配变量?

为了理解确切的问题,让我们举一个简单的例子。

考虑一个列表abc ,让我们分配一个名称为var1的日期对象

情况1:

abc <- list()
abc[["var1"]] <- Sys.Date()
abc
#$var1
#[1] "2019-11-28"

这按预期工作正常。 甚至class是“日期”

class(abc$var1)
#[1] "Date"

现在让我们更深入一层。

案例2:

abc <- list()
abc[["var1"]][["var2"]] <- Sys.Date()
abc
#$var1
# var2 
#18228 

在这里,日期被转换为数字。 我们都知道日期在内部存储为数字,但为什么它适用于第一个而不适用于第二个? 让我们再举一个例子

案例3:

abc <- list()
abc[["var1"]] <- list()
abc[["var1"]][["var2"]] <- Sys.Date()
abc
#$var1
#$var1$var2
#[1] "2019-11-28"

啊……我想我们现在正在了解模式及其工作原理。 因此,从上述情况来看,您似乎需要定义列表中的父元素来维护元素的 Date 类,否则它将日期强制转换为数字。 但是现在让我让它变得更加混乱/有趣/复杂。

案例4:

abc <- list()
abc[["var1"]][["var2"]] <- c(Sys.Date(), Sys.Date())
abc
#$var1
#$var1$var2
#[1] "2019-11-28" "2019-11-28"

现在这也有效。 这里我们没有早先定义var1但它仍然保持了abc$var1$var2 如何 ? 为什么 ?

以上所有问题的答案都记录在?Extract

当 $<- 应用于 NULL x 时,它首先将 x 强制转换为 list()。 如果替换值的长度大于 1,则 [[<- 也会发生这种情况:如果值的长度为 1 或 0,则首先将 x 强制转换为该值类型的零长度向量。

所以总结一下,当你分配的长度值大于 1 时,它会强制x列出然后分配值。 如果您在案例 2 中检查class(abc$var1) ,它的类型为'numeric'而在案例 3 和案例 4 中,它的类型为list 在第 3 种情况下它是list类型,因为abc$var1不是NULL而在第 4 种情况下abc$var1NULL但它的长度大于 1。

虽然答案很长,但我希望这个解释很有帮助并且易于理解。 特别感谢@Roland将我指向了相关的帮助页面。


除了 OP

有什么提示可以让它在函数内正确转换?

通常使用<<-不是一个好的做法,互联网上有很多关于它的讨论。 但是要解决当前的问题,您可以在函数中添加一行

library(xml2)
library(tidyverse)
library(stringi)
library(rvest)

upscope_list <- list()
scrap_function_mod <- function(athlete_name) {

  starting_name <- stri_trans_general(athlete_name, "latin-ascii")

  initial_url <- paste0("https://www.iaaf.org/athletes/search?query=", starting_name)
  initial_search_page <- read_html(initial_url)

 rawnodes_text <-
initial_search_page %>% html_nodes("table td") %>% html_text(trim = T) %>% stri_trans_general("latin-ascii")

  name_split <- as_vector(strsplit(starting_name, " ", fixed = T))
  number <- which(sapply(rawnodes_text, function(x)
      grepl(name_split[1], x, ignore.case = T) &
      grepl(name_split[length(name_split)], x, ignore.case = T)))
  upscope_list[[athlete_name]] <<- list() #Added a line here
  upscope_list[[athlete_name]][["birth_date"]] <<-
      rawnodes_text[(number + 4)] %>% as.Date("%d %B %Y")

  return(rawnodes_text[(number + 4)] %>% as.Date("%d %B %Y"))

} 

现在,当您调用该函数时,您会得到

scrap_function_mod("Ashton Eaton")
#[1] "1988-01-21"

upscope_list[["Ashton Eaton"]][["birth_date"]]
#[1] "1988-01-21"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM