提问人:Michael 提问时间:10/16/2023 最后编辑:Michael 更新时间:10/16/2023 访问量:99
在嵌套列表中提取列表并在 R 中创建数据帧
Extract lists within a nested list and create dataframe in R
问:
这是我之前在这里发布的问题的后续。
我使用 nhlapi 包来抓取一些 boxscores,这会产生一个大的嵌套列表。
install.packages("nhlapi")
library(nhlapi)
boxscores <- nhl_games_boxscore(gameIds = 2023020001)
目标是从多场比赛(而不仅仅是一场比赛)中获取 boxscores,并将所有统计数据以及玩家信息合并到一个数据帧中。
我调整了我的代码,如下所示:
gameIds = c(2023020001, 2023020002) #multiple gameIds
boxscores <- nhl_games_boxscore(gameIds = gameIds)
根据之前的答案,我使用了:
away_players <- map(boxscores, \(x) boxscores[[1]][["teams"]][["away"]][["players"]])
之前建议使用:
away_players <- map(boxscores, \(x) x[[1]][["teams"]][["away"]][["players"]])
但这会导致一个我不确定如何解决的错误。subscript out of bounds
我可以看到我有 2 份 22 人的名单,它们是两场比赛的客队:
str(away_players, list.len=2)
List of 2
$ :List of 22
..$ ID8482062:List of 4
.. ..$ person :List of 22
使用前面建议的代码:
df_away <- away_players %>%
map(unlist) %>%
map(enframe) %>%
map(\(x) pivot_wider(x,
names_from = name,
values_from = value)) %>%
bind_rows()
给出 1060 个变量的 2 个 obs。df
我确信我可能需要在列表中降低一个级别,这可能会起作用,但我被困在如何到达那里。
我还想将 添加为一列,但我不确定如何做到这一点,因为 没有出现在任何地方的初始列表中。gameId
gameId
我也尝试过循环,但我必须覆盖数据,因为我两次得到一个具有相同 22 名玩家的 df:
comb_away = data.frame()
for (game_id in gameIds) {
boxscore = nhl_games_boxscore(gameIds = gameIds)
away_players = boxscores[[1]][["teams"]][["away"]][["players"]]
res = away_players %>%
map(unlist) %>%
map(enframe) %>%
map(\(x) pivot_wider(x,
names_from = name,
values_from = value)) %>%
bind_rows()
comb_away = rbind(res, comb_away)
}
答:
1赞
margusl
10/16/2023
#1
map(boxscores, \(x) x[[1]][["teams"]][["away"]][["players"]])
抛出错误,因为在 map 中的第一次迭代函数期间,它的计算结果为:subscript out of bounds
[[1]]
boxscore[[1]][[1]][["teams"]][["away"]][["players"]]
并且恰好指的是第一个游戏的一个项目。boxscores[[1]][[1]]
copyright
当遍历输入列表的项目时,它会将每个项目传递给其函数,在函数的上下文中,列表深度已经减少了一个级别,这意味着 和 已经是顶级列表项。和你一起穿越到其中的第一个。map()
copyright
teams
officials
x[[1]]
我会选择这样的东西:
library(nhlapi)
library(purrr)
library(tibble)
library(tidyr)
gameIds = c(2023020001, 2023020002)
boxscores <- nhl_games_boxscore(gameIds = gameIds)
boxscores |>
# assume (kmh.. ) that list from nhl_games_boxscore is in the same order as
# gameIds input list
set_names(gameIds) |>
# use map with pluck() shorthand to extract nested list element, check ?pluck
map(list("teams", "away", "players")) |>
# use map with a named function, `name` and `value` are passed to enframe as args
map(enframe, name = "id", value = "player") |>
# bind resulting dataframes, list names to gameId column
list_rbind(names_to = "gameId") |>
unnest_wider(player) |>
# we don't need to unnest the whole nested structure,
# hoisting a single item from person lists:
hoist(person, "fullName")
#> # A tibble: 44 × 7
#> gameId id fullName person jerseyNumber position stats
#> <chr> <chr> <chr> <list> <chr> <list> <list>
#> 1 2023020001 ID84… Cole Sm… <named list> 36 <named list> <named list>
#> 2 2023020001 ID84… Yakov T… <named list> 13 <named list> <named list>
#> 3 2023020001 ID84… Gustav … <named list> 14 <named list> <named list>
#> 4 2023020001 ID84… Colton … <named list> 10 <named list> <named list>
#> 5 2023020001 ID84… Tommy N… <named list> 82 <named list> <named list>
#> 6 2023020001 ID84… Filip F… <named list> 9 <named list> <named list>
#> 7 2023020001 ID84… Roman J… <named list> 59 <named list> <named list>
#> 8 2023020001 ID84… Luke Sc… <named list> 2 <named list> <named list>
#> 9 2023020001 ID84… Samuel … <named list> 11 <named list> <NULL>
#> 10 2023020001 ID84… Alexand… <named list> 45 <named list> <named list>
#> # ℹ 34 more rows
创建于 2023-10-16 with reprex v2.0.2
评论
0赞
Michael
10/16/2023
这太棒了!我们将如何取消所有列表的嵌套?我需要查看所有人员/职位/统计数据详细信息。你还会为主队球员重复这一点吗,也许 rbind 因为我也需要这些?
0赞
margusl
10/16/2023
1- 你很可能需要经历一系列的unnest() / unnest_wider() / unnest_longer()操作来塑造这个框架,以满足你的需要,这样它才有意义(当你在错误的方向上未经测试时,你会肯定知道)。进程有时被称为矩形,有这个漂亮的小插图 - tidyr.tidyverse.org/articles/rectangle.html 。2 - 您可以在第一次调用中替换为 。away
home
map()
评论