2010-08-04 4 views
3

Je ne pense pas que cela a déjà été demandé, mais existe-t-il un moyen de combiner l'information d'une liste avec plusieurs niveaux et une structure inégale dans une trame de données de format «long»?convertir une liste hiérarchique inégale en une trame de données

Plus précisément:

library(XML) 
library(plyr) 
xml.inning <- "http://gd2.mlb.com/components/game/mlb/year_2009/month_05/day_02/gid_2009_05_02_chamlb_texmlb_1/inning/inning_5.xml" 
xml.parse <- xmlInternalTreeParse(xml.inning) 
xml.list <- xmlToList(xml.parse) 
## $top$atbat 
## $top$atbat$pitch 
##    des    id   type    x    y 
##   "Ball"   "310"    "B"   "70.39"  "125.20" 

Si ce qui suit est la structure:

> llply(xml.list, function(x) llply(x, function(x) table(names(x)))) 
$top 
$top$atbat 
.attrs pitch 
    1  4 
$top$atbat 
.attrs pitch 
    1  4 
$top$atbat 
.attrs pitch 
    1  5 
$bottom 
$bottom$action 
    b des event  o pitch player  s 
    1  1  1  1  1  1  1 
$bottom$atbat 
.attrs pitch 
    1  5 
$bottom$atbat 
.attrs pitch 
    1  5 
$bottom$atbat 
.attrs pitch runner 
    1  5  1 
$bottom$atbat 
.attrs pitch runner 
    1  7  1 
$.attrs 
$.attrs$num 
character(0) 
$.attrs$away_team 
character(0) 
$.attrs$ 

Ce que je voudrais avoir une trame de données à partir du vecteur du nom de la catégorie pas , le long avec le bon (top, atbat, bottom). Par conséquent, je devrais ignorer les niveaux qui ne rentrent pas dans un data.frame en raison du nombre différent de colonnes. Quelque chose comme ceci:

first second third des  x 
1 top atbat pitch Ball 70.29 
2 top atbat pitch Strike 69.24 
3 bottom atbat pitch Out 67.22 

Y at-il une manière élégante de faire ceci? Merci!

+0

question connexe: http://stackoverflow.com/questions/2067098/how-to-transformer-xml-data-into-a-data-frame – apeescape

Répondre

5

Je ne sais pas à propos de l'élégance, mais cela fonctionne. Ceux qui sont plus familiers avec Plyr pourraient probablement fournir une solution plus générale.

cleanFun <- function(x) { 
    a <- x[["atbat"]] 
    b <- do.call(rbind,a[names(a)=="pitch"]) 
    c <- as.data.frame(b) 
} 
ldply(xml.list[c("top","bottom")], cleanFun)[,1:5] 
    .id    des id type  x 
1 top   Ball 310 B 70.39 
2 top Called Strike 311 S 118.45 
3 top Called Strike 312 S 86.70 
4 top In play, out(s) 313 X 79.83 
5 bottom   Ball 335 B 15.45 
6 bottom Called Strike 336 S 77.25 
7 bottom Swinging Strike 337 S 99.57 
8 bottom   Ball 338 B 106.44 
9 bottom In play, out(s) 339 X 134.76 
1

La fonction .id pour le ldply() est agréable, mais il semble qu'ils se chevauchent une fois que vous faites une autre ldply().

Voici fonction assez générale qui utilise rbind.fill():

aho <- ldply(llply(xml.list[[1]], function(x) ldply(x, function(x) rbind.fill(data.frame(t(x)))))) 
> aho[1:5,1:4] 
    .id              des id type 
1 pitch              Ball 310 B 
2 pitch            Called Strike 311 S 
3 pitch            Called Strike 312 S 
4 pitch           In play, out(s) 313 X 
5 .attrs Alexei Ramirez lines out to second baseman Ian Kinsler. <NA> <NA> 

Le .id pour la deuxième ldply() manque parce que nous avions déjà un .id. Nous pourrions résoudre ce problème en nommant le premier .id sous un nom différent, mais cela ne semble pas cohérent.

aho2 <- ldply(llply(xml.list[[1]], function(x) { 
    out <- ldply(x, function(x) rbind.fill(data.frame(t(x)))) 
    names(out)[1] <- ".id2" 
    out 
})) 
> aho2[1:5,1:4] 
    .id .id2              des id 
1 atbat pitch              Ball 310 
2 atbat pitch            Called Strike 311 
3 atbat pitch            Called Strike 312 
4 atbat pitch           In play, out(s) 313 
5 atbat .attrs Alexei Ramirez lines out to second baseman Ian Kinsler. <NA> 
Questions connexes