在R中将多个不均匀嵌套列表转换为数据帧
我正在努力掌握R,作为一个实验,我想我会尝试利用一些板球数据。在其最原始的格式中,它是一个yaml文件,我使用yaml R包将其转换为一个R对象 但是,我现在有一些长度不均匀的嵌套列表,我想尝试将它们转换为R中的数据帧。我尝试了一些方法,例如编写一些循环来解析数据和tidyr包中的一些函数。然而,我似乎无法让它很好地工作 我想知道人们是否知道解决这个问题的最佳方法?复制数据结构在这里是很困难的,因为多个嵌套列表及其长度的不均匀性(这将导致非常长的代码块。但是,您可以在这里找到原始yaml数据:(我使用的是ODI internationals) 提前谢谢 更新 我试过这个: 1) 使用tidyr-separate在R中将多个不均匀嵌套列表转换为数据帧,r,R,我正在努力掌握R,作为一个实验,我想我会尝试利用一些板球数据。在其最原始的格式中,它是一个yaml文件,我使用yaml R包将其转换为一个R对象 但是,我现在有一些长度不均匀的嵌套列表,我想尝试将它们转换为R中的数据帧。我尝试了一些方法,例如编写一些循环来解析数据和tidyr包中的一些函数。然而,我似乎无法让它很好地工作 我想知道人们是否知道解决这个问题的最佳方法?复制数据结构在这里是很困难的,因为多个嵌套列表及其长度的不均匀性(这将导致非常长的代码块。但是,您可以在这里找到原始yaml数据:(
d <- unnest(balls)
Name <- c("Batsman","Bowler","NonStriker","RunsBatsman","RunsExtras","RunsTotal","WicketFielder","WicketKind","PlayerOut")
a <- separate(d, x, Name, sep = ",",extra = "drop")
d警告:答案不完整;尝试安排局数数据
plyr::rbind.fill
可以提供一种解决方案,用不同的列数绑定行
我不使用tidyr
,但下面是一些将局数数据转换为data.frame的粗略代码。然后,您可以在目录中的所有yaml
文件中循环此操作
# Download and unzip data
download.file("http://cricsheet.org/downloads/odis.zip", temp<- tempfile())
tmp <- unzip(temp)
# Create lists - use first game
library(yaml)
raw_dat <- yaml.load_file(tmp[[2]])
#names(raw_dat)
# Function to process list into dataframe
p_fun <- function(X) {
team = X[[1]][["team"]]
# function to process each list subelement that represents each throw
fn <- function(...) {
tmp = unlist(...)
tmp = data.frame(ball=gsub("[^0-9]", "", names(tmp))[1], t(tmp))
colnames(tmp) = gsub("[0-9]", "", colnames(tmp))
tmp
}
# loop over all throws
lst = lapply(X[[1]][["deliveries"]], fn )
cbind(team, plyr:::rbind.fill(lst))
}
# Loop over each innings
dat <- plyr::rbind.fill(lapply(raw_dat$innings, p_fun))
您可以截断它,使其更有用
str(raw_dat, 3)
length(raw_dat)
因此,有三个主要的列表元素-meta
、info
、和innings
。你也可以看到这一点
names(raw_dat)
要访问元数据,可以使用
raw_dat$meta
#or using `[[1]]` to access the first element of the list (see ?'[[')
raw_dat[[1]]
#and get sub-elements by either
raw_dat$meta$data_version
raw_dat[[1]][[1]] # you can also use the names of the list elements eg [[`data_version`]]
主要数据在局数
元素中
str(raw_dat$innings, 3)
查看列表元素中的名称
lapply(raw_dat$innings, names)
lapply(raw_dat$innings[[1]], names)
有两个列表元素,每个元素都有子元素。您可以通过以下方式访问这些
raw_dat$innings[[1]][[1]][["team"]] # raw_dat$innings[[1]][["1st innings"]][["team"]]
raw_dat$innings[[2]][[1]][["team"]] # raw_dat$innings[[2]][["2nd innings"]][["team"]]
上述函数解析了原始数据$innings
中的交付数据。要了解它的功能,请从内部进行操作
使用一条记录查看其工作原理
(注意lappy
,带p\u fun
,在raw\u dat$局[[1]]
和raw\u dat$局[[2]]]
上循环;因此这是外循环,lappy
,带fn
,在一局内循环传递;内环)
所以我们第一局的第一次投球
tmp = data.frame(ball=gsub("[^0-9]", "", names(tmp))[1], t(tmp))
colnames(tmp) = gsub("[0-9]", "", colnames(tmp))
tmp
# ball X..batsman X..bowler X..non_striker X..runs.batsman X..runs.extras X..runs.total
# 1 01 IR Bell DW Steyn MJ Prior 0 0 0
要查看lappy
的工作方式,请使用前三次交付(您需要在工作区中运行函数fn
)
因此,对于一局内的每一次投球,我们都会得到一个列表元素。然后我们使用rbind.fill
创建一个data.frame
如果我要尝试解析每个yaml文件,我会使用一个循环
以前三条记录为例,并添加匹配日期
tmp <- unzip(temp)[2:4]
all_raw_dat <- vector("list", length=length(tmp))
for(i in seq_along(tmp)) {
d = yaml.load_file(tmp[i])
all_raw_dat[[i]] <- cbind(date=d$info$date, plyr::rbind.fill(lapply(d$innings, p_fun)))
}
rbind.fill
不返回并在需要的地方用额外的列添加/更新行(a
仍然没有列z
),将其视为创建一个空数据框,列数等于在数据框列表中找到的唯一列数-unique(c(名称(a),名称(b))
。然后,在可能的情况下,在每一行中填充值,并保留缺失值(NA)。否则。警告:答案不完整;尝试安排局数数据
plyr::rbind.fill
可以提供一种解决方案,用不同的列数绑定行
我不使用tidyr
,但下面是一些将局数数据转换为data.frame的粗略代码。然后,您可以在目录中的所有yaml
文件中循环此操作
# Download and unzip data
download.file("http://cricsheet.org/downloads/odis.zip", temp<- tempfile())
tmp <- unzip(temp)
# Create lists - use first game
library(yaml)
raw_dat <- yaml.load_file(tmp[[2]])
#names(raw_dat)
# Function to process list into dataframe
p_fun <- function(X) {
team = X[[1]][["team"]]
# function to process each list subelement that represents each throw
fn <- function(...) {
tmp = unlist(...)
tmp = data.frame(ball=gsub("[^0-9]", "", names(tmp))[1], t(tmp))
colnames(tmp) = gsub("[0-9]", "", colnames(tmp))
tmp
}
# loop over all throws
lst = lapply(X[[1]][["deliveries"]], fn )
cbind(team, plyr:::rbind.fill(lst))
}
# Loop over each innings
dat <- plyr::rbind.fill(lapply(raw_dat$innings, p_fun))
您可以截断它,使其更有用
str(raw_dat, 3)
length(raw_dat)
因此,有三个主要的列表元素-meta
、info
、和innings
。你也可以看到这一点
names(raw_dat)
要访问元数据,可以使用
raw_dat$meta
#or using `[[1]]` to access the first element of the list (see ?'[[')
raw_dat[[1]]
#and get sub-elements by either
raw_dat$meta$data_version
raw_dat[[1]][[1]] # you can also use the names of the list elements eg [[`data_version`]]
主要数据在局数
元素中
str(raw_dat$innings, 3)
查看列表元素中的名称
lapply(raw_dat$innings, names)
lapply(raw_dat$innings[[1]], names)
有两个列表元素,每个元素都有子元素。您可以通过以下方式访问这些
raw_dat$innings[[1]][[1]][["team"]] # raw_dat$innings[[1]][["1st innings"]][["team"]]
raw_dat$innings[[2]][[1]][["team"]] # raw_dat$innings[[2]][["2nd innings"]][["team"]]
上述函数解析了原始数据$innings
中的交付数据。要了解它的功能,请从内部进行操作
使用一条记录查看其工作原理
(注意lappy
,带p\u fun
,在raw\u dat$局[[1]]
和raw\u dat$局[[2]]]
上循环;因此这是外循环,lappy
,带fn
,在一局内循环传递;内环)
所以我们第一局的第一次投球
tmp = data.frame(ball=gsub("[^0-9]", "", names(tmp))[1], t(tmp))
colnames(tmp) = gsub("[0-9]", "", colnames(tmp))
tmp
# ball X..batsman X..bowler X..non_striker X..runs.batsman X..runs.extras X..runs.total
# 1 01 IR Bell DW Steyn MJ Prior 0 0 0
要查看lappy
的工作方式,请使用前三次交付(您需要在工作区中运行函数fn
)
因此,对于一局内的每一次投球,我们都会得到一个列表元素。然后我们使用rbind.fill
创建一个data.frame
如果我要尝试解析每个yaml文件,我会使用一个循环
以前三条记录为例,并添加匹配日期
tmp <- unzip(temp)[2:4]
all_raw_dat <- vector("list", length=length(tmp))
for(i in seq_along(tmp)) {
d = yaml.load_file(tmp[i])
all_raw_dat[[i]] <- cbind(date=d$info$date, plyr::rbind.fill(lapply(d$innings, p_fun)))
}
rbind.fill
不返回并在需要的地方用额外的列添加/更新行(a
仍然没有列z
),将其视为创建一个空数据框,列数等于在数据框列表中找到的唯一列数-unique(c(名称(a),名称(b))
。然后尽可能在每一行中填充这些值,否则将丢失(NA)..Hi!谢谢你,我已经试过了,它看起来很有效。虽然我将不得不花一点时间理解代码:)再次感谢!所以我花了一点时间在脚本上,认为我基本上理解了它背后的概念。但是有一些我不太明白。我已经把问题分成了几个单独的评论!再次感谢您将这些放在一起,它帮助我掌握了R中的数据操作,尽管有