[英]Matrix converted from distance object, subset behaviour differs from normal matrices
[英]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$var1
是NULL
但它的长度大于 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.