2009-12-02 80 views
4

让我们说,我有这样的XML文件:如何使用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-魔族告诉我,我是‘循环隐藏’,而不是‘矢量化’!我可以避免循环吗? ...

回答

3

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

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语法以及函数如何操作的人来说,它绝对更清晰并且非常明确。

+0

来自xpathSApply的帮助也特别有启发性(我仍然使用XML包!)。 – mariotomo 2009-12-03 07:51:44

3

由于seriesNodes是节点列表,因此没有简单的方法可以避免隐式循环。简单的操作如获得长度不是计算密集型的,所以我不会失去任何睡眠而不能进行矢量化。

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

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

最后,如果您真的非常想要引导计数事件,请使用names(unlist(seriesNodes)),然后在"series.name"的每次出现之间计算出"series.children.event.name"的发生次数。这无疑是更丑陋的,并且可能比sapply电话慢。