2014-05-18 31 views
5

Czy saveRDS i readRDS, odpowiednio, zapisać i przywrócić wszystkie atrybuty obiektu, w tym te utworzone przez aplikację (przez attr)? Próbowałem użyć tego podejścia zamiast save i , próbując znaleźć obejście mojego problemu, które jest poniżej powiązane. Jednak nie wydaje się, aby tak było, chyba że robię coś złego: Can I access R data objects' attributes without fully loading objects from file?.Zachowanie saveRDS() i readRDS() w odniesieniu do atrybutów obiektów

Odpowiedz

10

Tak, robią:

test <- structure(1:10, names=LETTERS[1:10], color='red', xxx='yyy') 
attr(test, which='uuu') <- 'zzz' 
test 
## A B C D E F G H I J 
## 1 2 3 4 5 6 7 8 9 10 
## attr(,"color") 
## [1] "red" 
## attr(,"xxx") 
## [1] "yyy" 
## attr(,"uuu") 
## [1] "zzz" 
saveRDS(test, '/tmp/test.rds') 
test2 <- readRDS('/tmp/test.rds') 
identical(test, test2) 
## [1] TRUE 

R opiera się głównie na tych funkcji (jak również ich warianty). Na przykład są one używane do zapisywania obszaru roboczego użytkownika. Tak więc byłoby dziwne, gdyby nie przechowywały atrybutów.

Należy jednak pamiętać, że nie można z nich przechować niektórych "dynamicznie utworzonych" obiektów. Obejmuje to plik i SQL db połączeń tymczasowych SQL koparki, ładowarki itp wyników An przykład RCPP skompilowanych funkcji:

library('Rcpp') 
library('inline') 
cppFunction("int one() { return 1; }") 
one() # it works 
## [1] 1 
one # contains a pointer to dynamically allocated mem chunk 
## function() 
## .Primitive(".Call")(<pointer: 0x7f52c33a7680>) 
saveRDS(one, '/tmp/one.rds') 

Teraz ponownie uruchomić R ...

one <- readRDS('/tmp/one.rds') 
one # the pointer is no longer valid 
## function() 
## .Primitive(".Call")(<pointer: (nil)>) 
one() # doesn't work 
## Error in .Primitive(".Call")(<pointer: (nil)>) : 
## NULL value passed as symbol address 
+0

Wielkie dzięki! +1 i zaakceptuj swoją odpowiedź. Cóż, myślę, że to oznacza, że ​​mój problem może być gdzieś indziej. Czy może to być sposób w jaki konstruuję nazwy, używając 'as.name'? A może coś jeszcze? Byłbym wdzięczny, gdybyś rzucił okiem na moje oryginalne pytanie, powiązane powyżej. –

+1

Upewnij się, że którykolwiek z obiektów, które próbujesz serializować (przechowywać), nie zawiera wskaźników do dynamicznie przydzielanej pamięci (spróbuj 'unlist (request)' lub sth). Jeśli tak, powinny zostać w jakiś sposób przekształcone w obiekty "czystego R". – gagolews

+1

Doceń swoją aktualizację i skomentuj dynamiczne obiekty. Dziękuję! :-) –

3

saveRDS() zapewnia znacznie lepsze rozwiązanie do problemu i do ogólnego zapisu i ładowania obiektów utworzonych za pomocą R. saveRDS() serializuje obiekt R z do formatu, który można zapisać. Wikipedia opisuje to w ten sposób

... serializacji jest proces przekształcania struktury danych lub obiekt stan w formacie, który może być przechowywany (na przykład w buforze pamięci pliku lub lub przesyłane przez sieć linku połączenie) i "wskrzeszeni" później w tym samym lub w innym środowisku komputerowym.

save() robi to samo, ale z jedną istotną różnicą: saveRDS() nie oszczędza zarówno obiektu i jego nazwę to tylko oszczędza reprezentację obiektu. W rezultacie zapisany obiekt może zostać załadowany do nazwanego obiektu w R, który jest inny od nazwy, którą miał przy pierwotnej serializacji.

Możemy to zilustrować za pomocą poniższego modelu

ls() [1] "mod" 
saveRDS(mod, "mymodel.rds") 
mod2 <- readRDS("mymodel.rds") 
ls() [1] "mod" "mod2" 
identical(mod, mod2, ignore.environment = TRUE) [1] TRUE 

(Zauważ, że dwa modelowe obiekty mają różne środowiska w swoich reprezentacjach więc musimy zignorować to podczas testowania ich tożsamości.)

You” Zauważ, że w wywołaniu saveRDS() nazwałem plik z rozszerzeniem .rds. Wydaje się, że jest to konwencja używana dla serializowanych obiektów tego typu; R często korzysta z tej reprezentacji, na przykład pakiet meta-danych i baz danych używanych przez help.search(). W przeciwieństwie do rozszerzenia .rda jest często używany do obiektów serializowanych przez save().

Tak więc masz to; saveRDS() i readRDS() są najnowszymi dodatkami do mojego codziennego przepływu pracy.

Uwaga: saveRDS() nie jest zamiennikiem zamiennym dla save(). Główna różnica polega na tym, że save() może zapisać wiele obiektów do pliku w jednym wywołaniu, , podczas gdy saveRDS(), będąc funkcją niższego poziomu, działa z pojedynczym obiektem naraz. Jest to cecha dla mnie, biorąc pod uwagę powyższy przypadek użycia, ale jeśli zaoszczędzisz sobie więcej czasu na niż na kilku obiektach w tym samym czasie, saveRDS() może nie być dla Ciebie idealny. Druga znacząca różnica polega na tym, że saveRDS() zapomina o oryginalnej nazwie obiektu; w przypadku użycia powyżej jest to również korzystne. Jeśli zachowanie oryginalnej nazwy jest dla Ciebie ważne, , nie ma powodu, aby rezygnować z używania save() do saveRDS().

+0

Po prostu przebiegłem twoją odpowiedź. +1 i dzięki - to dobry dodatek do zaakceptowanej odpowiedzi. –