R-ohjelmointi.org

Tilastotieteellistä ohjelmointia R-kielellä

XML:n käsittelyä R:llä

Kirjoitin, että tulen tämän vuoden aikana käsittelemään muutamia Omegahat-projektin tuottamia funktiokirjastoja ja tarjoamaan esimerkkejä, että miten niiden avulla voidaan tehostaa R:n käyttöä. Tämä artikkeli käsittelee Omegahatin tuottamaa XML-funktiokirjastoa.

Nykypäivänä data liikkuu useassa muodossa ja XML-muoto on ottanut paikkansa datan ”kuvaamisessa”. XML toimiii tiedonvälityksessä (esim. sanomavälityksessä järjestelmien välillä) ja yhteenä formaattina datan tallennuksessa. Tilastoanalyysien lähtökohtana saattaa olla, että data on XML-muodossa ja se täytyy ”kääntää” käsittelyä varten johonkin helpompaan muotoon. Omegahat on tehnyt XML-funktiokirjaston mm. juuri tällaisia tilanteita varten. Alla käydään läpi yksinkertaisen esimerkin avulla XML-muotoisen datan käsittelyä. Esimerkeissä käytetään ahkerasti XPath-kyselykieltä.

Asennetaan XML-paketti, otetaan se käyttöön ja haetaan w3schools-sivuilta XML-esimerkkitiedosto.

install.packages("XML")
library(XML)
books <- "http://www.w3schools.com/XQuery/books.xml"

Käytetään seuraavaksi funktiota xmlTreeParse pyöräyttämään XML-data R:n ymmärtämään muotoon.

#xmlTreeParse
doc <- xmlTreeParse(books, useInternalNodes = TRUE)
doc

XML-tiedosto näyttää tältä:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<bookstore>
  <book category="COOKING">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="CHILDREN">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="WEB">
    <title lang="en">XQuery Kick Start</title>
    <author>James McGovern</author>
    <author>Per Bothner</author>
    <author>Kurt Cagle</author>
    <author>James Linn</author>
    <author>Vaidyanathan Nagarajan</author>
    <year>2003</year>
    <price>49.99</price>
  </book>
  <book category="WEB">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

Haetaan muutamia tietoja dokumentista.

#xmlRoot
# -- palauttaa top level noodista lähtien dokumentin
xmlRoot(doc)
 
#xmlSize
# -- katsotaan kuinka monta sub-elementtiä tästä xml-docista löytyy
xmlSize(doc)
 
#names.XMLNode
# -- Palautetaan lista book-nodeista
r <- xmlRoot(doc)
names(r)
r[names(r) == "book"]

Haetaan XML-dokumentista noodeja ja dataa XPath-kielellä.

#xpathSApply
# -- Heataan kaikkien kirjojen otsikot
xpathSApply(doc, "/bookstore/book/title", xmlValue)
 
# -- Heataan vain ensimmäisen kirjan otsikko
xpathSApply(doc, "/bookstore/book[1]/title", xmlValue)
 
# -- Heataan hinnat ja muutetaan ne numeerisiksi
xpathSApply(doc, "/bookstore/book/price", 
function(x) as.numeric(xmlValue(x)))
 
# -- Heataan kirjan otsikko, jonka hinta on alle 30 dollaria
xpathSApply(doc, "/bookstore/book[price<30]/title", xmlValue)
 
# -- Heataan bookin kaikki nodet
xpathSApply(doc, "/bookstore/book/child::node()", xmlValue)
 
# -- Heataan kaikki nodet, jotka on kaksi tasoa bookstorea alempana
xpathSApply(doc, "/bookstore/*/*/self::node()", xmlValue)
 
# -- Haetaan kaikki nodet, joissa kirjan kategoria on web
xpathSApply(doc, "/bookstore/book[@category='WEB']/child::node()", 
xmlValue)
 
#getNodeSet
# -- Heataan bookin child-nodet ja niiden arvot
nd <- getNodeSet(doc, "/bookstore/book/child::node()")
sapply(nd, function(x) xmlValue(x))
 
# -- Haetaan kaikki book-node category-attribuuttien arvot
nd <- getNodeSet(doc, "/bookstore/book[@category]")
sapply(nd, function(x) xmlGetAttr(x, "category"))
 
#xmlAttrs
# -- haetaan book-elemettien attribuutit
xpathSApply(doc, "/bookstore/book", xmlAttrs)
 
#xmlGetAttr
# -- haetaan title-noodin lang-attribuuttien arvot
xpathSApply(doc, "/bookstore/book/title", 
function(x) xmlGetAttr(x, "lang"))
 
#xmlName
# -- haetaan book noodin lapsien nimet
xpathSApply(doc, "/bookstore/book/child::node()", xmlName)

Muutetaan XML-tiedosto data.frameksi, jotta sitä voidaan jatkokäsitellä R:llä helpommin. Ensimmäisessä esimerkissä käytetään toista XML-esimerkkitiedostoa.

#xml:n tweakkaus data.frameksi
f <- system.file("exampleData", "mtcars.xml", package="XML")
d <- xmlTreeParse(f, useInternalNodes = TRUE)
d
g <- xpathApply(d, "/dataset/record", xmlValue)
rows <- do.call(rbind, sapply(g, strsplit, "\\s+"))
DF <- data.frame(rows[,-1])
DF[] <- lapply(DF, function(x) as.numeric(as.character(x)))
colnames(DF) <- xpathSApply(d, "/dataset/variables/child::node()", 
xmlValue)
rownames(DF) <- xpathSApply(d, "/dataset/record", xmlAttrs)
DF
identical(DF, mtcars)
 
#xmlToList
# -- käytetään plyr-kirjastoa apuna
install.packages("plyr")
library(plyr)
ldply(xmlToList(doc), function(x) {data.frame(x[!names(x)=="author"])})
#Tai
ldply(xmlToList(doc), data.frame)

Viimeisin komento kääntää books.xml-esimerkkitiedostomme data.frameksi ja palauttaa sen näin:

> ldply(xmlToList(doc), data.frame)
   .id        title.text title..attrs              author year price   .attrs    author.1   author.2   author.3               author.4
1 book  Everyday Italian           en Giada De Laurentiis 2005 30.00  COOKING        <NA>       <NA>       <NA>                   <NA>
2 book      Harry Potter           en        J K. Rowling 2005 29.99 CHILDREN        <NA>       <NA>       <NA>                   <NA>
3 book XQuery Kick Start           en      James McGovern 2003 49.99      WEB Per Bothner Kurt Cagle James Linn Vaidyanathan Nagarajan
4 book      Learning XML           en         Erik T. Ray 2003 39.95      WEB        <NA>       <NA>       <NA>                   <NA>


Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *