如何从R?
中的大型XML文件中获取给定大小的样本与阅读简单的随机行不同,此处必须保留R文件的XML结构,以便将其读入正确的data.frame。
一种可能的解决方案是读取整个文件然后对行进行采样,但是是否可以只读取必要的块?
文件中的样本:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<sku>967190</sku>
<productId>98611</productId>
...
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>
...
每个“产品”的行数不相等。打开文件前,最后的记录数是未知的。
答案 0 :(得分:3)
不是读取整个文件,而是可以使用closure
来处理您感兴趣的节点的事件解析。为了达到目的,我将从一个随机抽样的策略开始文件。一次处理一个记录。如果i
记录小于或等于要保留的记录的数量n
,则将其存储,否则以概率n / i
存储它。这可以实现为
i <- 0L; n <- 10L
select <- function() {
i <<- i + 1L
if (i <= n)
i
else {
if (runif(1) < n / i)
sample(n, 1)
else
0
}
}
的行为如下:
> i <- 0L; n <- 10L; replicate(20, select())
[1] 1 2 3 4 5 6 7 8 9 10 1 5 7 0 1 9 0 2 1 0
这告诉我们要保留前10个元素,然后我们用元素11替换元素1,用元素12替换元素5,用元素13替换元素7,然后删除第14个元素等。替换变得不那么频繁,因为我变得多了大于n。
我们将此作为product
处理程序的一部分使用,它为我们感兴趣的结果预先分配空间,然后每次遇到“产品”节点时,我们测试是否选择,如果是,将其添加到我们在适当位置的当前结果
sku <- character(n)
product <- function(p) {
i <- select()
if (i)
sku[[i]] <<- xmlValue(p[["sku"]])
NULL
}
'select'和'product'处理程序与一个函数(get
)相结合,允许我们检索当前值,并将它们全部放在一个闭包中,这样我们就有了一种工厂封装变量n
,i
和sku
sampler <- function(n)
{
force(n) # otherwise lazy evaluation could lead to surprises
i <- 0L
select <- function() {
i <<- i + 1L
if (i <= n) {
i
} else {
if (runif(1) < n / i)
sample(n, 1)
else
0
}
}
sku <- character(n)
product <- function(p) {
i <- select()
if (i)
sku[[i]] <<- xmlValue(p[["sku"]])
NULL
}
list(product=product, get=function() list(sku=sku))
}
然后我们准备好了
products <- xmlTreeParse("foo.xml", handler=sampler(1000))
as.data.frame(products$get())
一旦处理的节点数i
相对于n
变大,这将与文件的大小成线性关系,因此您可以通过开始时了解其是否表现良好原始文件的子集。
答案 1 :(得分:1)
以下是基于您提供的XML文件的示例。
xml <- '<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<sku>967190</sku>
<productId>98611</productId>
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>
<product>
<sku>967191</sku>
<productId>98612</productId>
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>
<product>
<sku>967192</sku>
<productId>98613</productId>
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>
</products>
'
# parse
p <- xmlParse(xml)
# get nodes
nodes <- xpathApply(p, '//product')
# return a random sample of notes
nodes[sample(seq_along(nodes), 2)]
结果如下:
> nodes[sample(seq_along(nodes), 2)]
[[1]]
<product>
<sku>967191</sku>
<productId>98612</productId>
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>
[[2]]
<product>
<sku>967190</sku>
<productId>98611</productId>
<listingId/>
<sellerId/>
<shippingRestrictions/>
</product>