XML'den R veri çerçevesine nasıl ayrıştırılır


103

XML'i R veri çerçevesine ayrıştırmaya çalıştım, bu bağlantı bana çok yardımcı oldu:

xml dosyasından bir R veri çerçevesi nasıl oluşturulur

Ama yine de sorunumu çözemedim:

İşte kodum:

data <- xmlParse("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")
xmlToDataFrame(nodes=getNodeSet(data1,"//data"))[c("location","time-layout")]
step1 <- xmlToDataFrame(nodes=getNodeSet(data1,"//location/point"))[c("latitude","longitude")]
step2 <- xmlToDataFrame(nodes=getNodeSet(data1,"//time-layout/start-valid-time"))
step3 <- xmlToDataFrame(nodes=getNodeSet(data1,"//parameters/temperature"))[c("type="hourly"")]

Sahip olmak istediğim veri çerçevesi şöyle:

latitude  longitude   start-valid-time   hourly_temperature
29.803     -82.411  2013-06-19T15:00:00-04:00    91
29.803     -82.411  2013-06-19T16:00:00-04:00    90

Sıkıştım xmlToDataFrame(), Herhangi bir yardım çok takdir edilecektir, teşekkürler.

Yanıtlar:


103

XML biçimindeki veriler nadiren xmlToDataFrameişlevin çalışmasına izin verecek şekilde düzenlenir . Listelerdeki her şeyi çıkarmanız ve ardından listeleri bir veri çerçevesinde birbirine bağlamanız daha iyidir:

require(XML)
data <- xmlParse("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")

xml_data <- xmlToList(data)

Örnek verileriniz söz konusu olduğunda, konum ve başlangıç ​​zamanını almak oldukça basittir:

location <- as.list(xml_data[["data"]][["location"]][["point"]])

start_time <- unlist(xml_data[["data"]][["time-layout"]][
    names(xml_data[["data"]][["time-layout"]]) == "start-valid-time"])

Sıcaklık verileri biraz daha karmaşıktır. İlk önce sıcaklık listelerini içeren düğüme gitmeniz gerekir. Sonra her iki listeyi de çıkarmanız, her birinin içine bakmanız ve değerlerinden biri olarak "saatlik" olanı seçmeniz gerekir. Ardından, yalnızca bu listeyi seçmeniz, ancak yalnızca "değer" etiketine sahip değerleri tutmanız gerekir:

temps <- xml_data[["data"]][["parameters"]]
temps <- temps[names(temps) == "temperature"]
temps <- temps[sapply(temps, function(x) any(unlist(x) == "hourly"))]
temps <- unlist(temps[[1]][sapply(temps, names) == "value"])

out <- data.frame(
  as.list(location),
  "start_valid_time" = start_time,
  "hourly_temperature" = temps)

head(out)
  latitude longitude          start_valid_time hourly_temperature
1    29.81    -82.42 2013-06-19T16:00:00-04:00                 91
2    29.81    -82.42 2013-06-19T17:00:00-04:00                 90
3    29.81    -82.42 2013-06-19T18:00:00-04:00                 89
4    29.81    -82.42 2013-06-19T19:00:00-04:00                 85
5    29.81    -82.42 2013-06-19T20:00:00-04:00                 83
6    29.81    -82.42 2013-06-19T21:00:00-04:00                 80

95

Hem performans hem de netlik için xpath'i daha doğrudan kullanın .

time_path <- "//start-valid-time"
temp_path <- "//temperature[@type='hourly']/value"

df <- data.frame(
    latitude=data[["number(//point/@latitude)"]],
    longitude=data[["number(//point/@longitude)"]],
    start_valid_time=sapply(data[time_path], xmlValue),
    hourly_temperature=as.integer(sapply(data[temp_path], as, "integer"))

giden

> head(df, 2)
  latitude longitude          start_valid_time hourly_temperature
1    29.81    -82.42 2014-02-14T18:00:00-05:00                 60
2    29.81    -82.42 2014-02-14T19:00:00-05:00                 55

13
Bu gerçekten kabul edilen cevap olmalı. Daha özlü ve xpath, listeler üzerinde yinelemekten çok daha iyi performansa sahip.
SchaunW

Mükemmel cevap. W3schools öğreticisinin xpath öğrenmek için resmi xpath sayfasından daha iyi bir yer olabileceğini unutmayın .
Laurent Bergé

40

İşte xml2 kullanarak kısmi bir çözüm. Çözümü daha küçük parçalara bölmek, genellikle her şeyin dizildiğinden emin olmayı kolaylaştırır:

library(xml2)
data <- read_xml("http://forecast.weather.gov/MapClick.php?lat=29.803&lon=-82.411&FcstType=digitalDWML")

# Point locations
point <- data %>% xml_find_all("//point")
point %>% xml_attr("latitude") %>% as.numeric()
point %>% xml_attr("longitude") %>% as.numeric()

# Start time
data %>% 
  xml_find_all("//start-valid-time") %>% 
  xml_text()

# Temperature
data %>% 
  xml_find_all("//temperature[@type='hourly']/value") %>% 
  xml_text() %>% 
  as.integer()

8
Faydalı cevap. Karşılaşan başka biri varsa, işte Hadley tarafından xml2 kullanımı üzerine bir eğiticinin
Richard Erickson

9

Aşağıdaki kodu deneyebilirsiniz:

# Load the packages required to read XML files.
library("XML")
library("methods")

# Convert the input xml file to a data frame.
xmldataframe <- xmlToDataFrame("input.xml")
print(xmldataframe)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.