从XML文件随机采样到R中的数据帧

时间:2013-12-21 13:33:57

标签: xml r random dataframe large-files

如何从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>
...

每个“产品”的行数不相等。打开文件前,最后的记录数是未知的。

2 个答案:

答案 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)相结合,允许我们检索当前值,并将它们全部放在一个闭包中,这样我们就有了一种工厂封装变量nisku

的模式
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>