2010-06-24 4 views
2

J'essaie de prendre une liste et de sérialiser chaque élément et de le placer dans un fichier CSV avec une clé pour créer un fichier texte avec des paires clé/valeur. En fin de compte, cela va passer par le streaming Hadoop alors avant que vous posiez la question, je pense que cela doit vraiment être dans un fichier texte. (mais je suis ouvert à d'autres idées) Tout semblait assez simple au début. Mais je n'arrive pas à faire en sorte que la sérialisation fonctionne comme je le veux (still).R: Création d'un fichier CSV à partir d'objets sérialisés

Si je fais ceci:

> rawToChar(serialize("blah", NULL, ascii=T)) 
[1] "A\n2\n133888\n131840\n16\n1\n9\n4\nblah\n" 

Alors j'ai ces satanés \ n qui bousiller mon analyse syntaxique CSV plus tard. Je pourrais entrer et remplacer le \ n avec une autre chaîne, ce que je ne suis pas opposé à faire. Cela semble un peu en désordre, cependant.

L'autre option qui est venu à l'esprit est en omettant le rawToChar() appel et le pompage du ascii brut dans un fichier texte:

> serialize("blah", NULL, ascii=T) 
[1] 41 0a 32 0a 31 33 33 38 38 38 0a 31 33 31 38 34 30 0a 31 36 0a 31 0a 39 0a 
[26] 34 0a 62 6c 61 68 0a 

Eh bien, si je vide juste que dans un fichier texte que je vais \ n après chaque élément de la liste. Donc, j'ai essayé de faire un peu de pâte/effondrement:

> ser <- serialize("blah", NULL, ascii=T) 
> ser2 <- paste(ser, collapse="") 
> ser2 
[1] "410a320a3133333838380a3133313834300a31360a310a390a340a626c61680a" 

Maintenant, c'est une valeur que je peux écrire dans un fichier texte CSV! Seulement ... comment est-ce que je le rends à nouveau brut plus tard? Prenons juste le premier élément hex: 41 Je ne peux même pas comprendre comment créer une liste d'éléments bruts et enfoncer une valeur hexadécimale 41 dans l'un des éléments. Lorsque j'essaie de mettre une valeur hexadécimale brute dans une liste brute, je me retrouve avec quelque chose comme ceci:

> r <- raw(1) 
> r[1] <- 41 
Error in r[1] <- 41 : 
    incompatible types (from double to raw) in subassignment type fix 
> r[1] <- as.raw(41) 
> r[1] 
[1] 29 

Crap! 29! = 41 (sauf pour de très grandes valeurs de 29 et de très petites valeurs de 41, bien sûr)

Des idées pour casser cet écrou?

+0

Commentaire: Avez-vous utilisé RHIPE? http://www.stat.purdue.edu/~sguha/rhipe/ – mcpeterson

+0

avez-vous essayé avec 'writeBin' et' readBin'? – nico

+0

RHIPE ressemble à un projet vraiment soigné. Si j'avais un cluster Hadoop local, je l'utiliserais probablement. Mon flux va finalement dans un moteur Amzn EMR Hadoop, cependant. –

Répondre

3

Le paquet caTools a un codeur-décodeur Base64 que vous pouvez utiliser:

> library(caTools) 
> s<-base64encode(serialize("blah",NULL)) 
> s 
[1] "WAoAAAACAAIKAQACAwAAAAAQAAAAAQAAAAkAAAAEYmxhaA==" 
> unserialize(base64decode(s,"raw")) 
[1] "blah" 
+0

Cela semble très prometteur! Je vais tester ce matin. Merci! –

+0

Je l'ai testé et ça marche ... mais j'ai parfois des résultats qui ne correspondent pas exactement. Peut-être un problème de virgule flottante. Je vais poser cette question spécifique dans un autre post. –

+0

question de suivi ajouté ici: http://stackoverflow.com/questions/3119037/r-serialize-base64-encode-decode-of-text-not-exactly-matching –

0

Peut-être que vous vouliez as.raw(65) à la place 65 (en décimal) est 41 (en hexadécimal)

> as.hexmode(65) 
[1] "41" 

En ce qui concerne l'encodage, vous pouvez travailler avec des données binaires dans le streaming Hadoop?

+0

Hadoop peut fonctionner avec des binaires, mais le mode streaming, d'après ce que je peux comprendre, nécessite du texte. –

1

grâce à jmoy pour sa grande réponse. J'ai utilisé sa recommandation et cela fonctionne très bien. Pour les futurs auto-stoppeurs qui se retrouvent ici, je laisse mes fonctions pour transformer une liste en fichiers texte CSV sérialisés, puis les réintégrer dans des listes. Je marque ce message en tant que wiki de communauté. N'hésitez pas à l'éditer s'il y a une façon plus simple de faire ceci:

listToCsv <- function(inList, outFileName){ 
    require(caTools) 
    if (is.list(inList) == F) 
     stop("listToCsv: The input list fails the is.list() check.") 
    fileName <- outFileName 
    cat("", file=fileName, append=F) 

    i <- 1 
    for (item in inList) { 
    myLine <- paste(i, ",", base64encode(serialize(item, NULL, ascii=T)), "\n", sep="") 
    cat(myLine, file=fileName, append=T) 
    i <- i+1 
    } 
} 

csvToList <- function(inFileName){ 
    require(caTools) 
    linesIn <- readLines(fileName, n=-1) 
    outList <- NULL 

    i <- 1 
    for (line in linesIn){ 
    outList[[i]] <- unserialize(base64decode(strsplit(linesIn[[i]], split=",")[[1]][[2]], "raw")) 
    i <- i+1 
    } 
    return(outList) 
} 
Questions connexes