【问题标题】:how to vectorize with xml data?如何使用 xml 数据进行矢量化?
【发布时间】:2010-12-22 09:51:29
【问题描述】:

假设,我有这个 xml 文件:

<?xml version="1.0" encoding="UTF-8" ?>
<TimeSeries>
  <timeZone>1.0</timeZone>
  <series>
    <header/>
    <event date="2009-09-30" time="10:00:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:15:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:30:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:45:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="11:00:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="11:15:00" value="0.0" flag="2"></event>
  </series>
  <series>
    <header/>
    <event date="2009-09-30" time="08:00:00" value="1.0" flag="2"></event>
    <event date="2009-09-30" time="08:15:00" value="2.6" flag="2"></event>
    <event date="2009-09-30" time="09:00:00" value="6.3" flag="2"></event>
    <event date="2009-09-30" time="09:15:00" value="4.4" flag="2"></event>
    <event date="2009-09-30" time="09:30:00" value="3.9" flag="2"></event>
    <event date="2009-09-30" time="09:45:00" value="2.0" flag="2"></event>
    <event date="2009-09-30" time="10:00:00" value="1.7" flag="2"></event>
    <event date="2009-09-30" time="10:15:00" value="2.3" flag="2"></event>
    <event date="2009-09-30" time="10:30:00" value="2.0" flag="2"></event>
  </series>
  <series>
    <header/>
    <event date="2009-09-30" time="10:00:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:15:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:30:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="10:45:00" value="0.0" flag="2"></event>
    <event date="2009-09-30" time="11:00:00" value="0.0" flag="2"></event>
  </series>
</TimeSeries>

假设我想对其系列元素做一些事情,并且我想将“矢量化可矢量化”的建议付诸实践...我导入 XML 库并执行以下操作:

R> library("XML")
R> doc <- xmlTreeParse('/home/mario/Desktop/sample.xml')
R> TimeSeriesNode <- xmlRoot(doc)
R> seriesNodes <- xmlElementsByTagName(TimeSeriesNode, "series")
R> length(seriesNodes)
[1] 3
R> (function(x){length(xmlElementsByTagName(x[['series']], 'event'))}
+ )(seriesNodes)
[1] 6
R> 

我不明白为什么我应该只得到将函数应用于第一个元素的结果:我曾期望三个值,就像 seriesNodes 的长度一样,如下所示:

R> mapply(length, seriesNodes)
series series series 
     7     10      6 

哎呀!我已经给出了答案:“使用mapply”:

R> mapply(function(x){length(xmlElementsByTagName(x, 'event'))}, seriesNodes)
series series series 
     6      9      5 

但后来我看到了以下问题:R-inferno 告诉我我是“循环隐藏”,而不是“矢量化”!我可以完全避免循环吗? ...

【问题讨论】:

    标签: xml r language-features


    【解决方案1】:

    您也可以使用xpathApplyxpathSApply——这些函数使用XPath 规范提取节点集,然后对每个集执行一个函数。这两个功能都由XML 包提供。为了使用这些函数,必须使用 xmlInternalTreeParse 或将 xmlTreeParseuseInternalNodes 选项设置为 true 来解析 XML 文档:

    require( XML )
    
    countEvents <- function( series ){
    
      events <- xmlElementsByTagName( series, 'event' )
      return( length( events ) ) 
    
    }
    
    doc <- xmlTreeParse( "sample.xml", useInternalNodes = T )
    
    xpathSApply( doc, '/TimeSeries/series', countEvents )
    [1] 6 9 5
    

    我不知道它是否“更快”,但对于任何了解 XPath 语法以及apply 函数如何运行的人来说,代码绝对更干净且非常明确。

    【讨论】:

    • xpathSApply 的帮助也特别有启发性(而且我一直在使用 XML 包!)。
    【解决方案2】:

    由于seriesNodes 是一个节点列表,因此没有简单的方法可以避免隐式循环。像获取长度这样的简单操作不是计算密集型的,所以我不会因为无法矢量化而失眠。

    请注意,您可以使用sapply(seriesNodes, length),而不是mapply,因为length 函数只有一个参数。

    “正确的 R 方式”是使用 (s|m)apply 调用来提取有用数据位的向量,然后以通常的方式分析这些向量。

    最后,如果您真的很想向量化计数事件,请使用names(unlist(seriesNodes)),然后在"series.name" 的每次出现之间计算"series.children.event.name" 的出现次数。这无疑是丑陋的,可能比sapply 调用慢。

    【讨论】:

      猜你喜欢
      • 2010-09-29
      • 2017-05-29
      • 2017-02-24
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-16
      • 1970-01-01
      相关资源
      最近更新 更多