2010-06-25 62 views
3

我的previous question關於使用serialize()創建對象的CSV我從jmoy得到了一個很好的回答,他推薦了我的序列化文本的base64編碼。那正是我所期待的。奇怪的是,當我嘗試在實踐中使用它時,我得到的結果看起來不錯,但並不完全符合我在序列化/編碼過程中運行的結果。R:序列化base64對文本的編碼/解碼不完全匹配

下面的示例將帶有3個向量的列表並序列化每個向量。然後,每個矢量都以base64編碼,並與一個鍵一起寫入文本文件。關鍵僅僅是矢量的索引號。然後我反過來從csv讀取每一行。在最後你可以看到一些項目不匹配完全匹配。這是浮點問題嗎?還有別的嗎?

require(caTools) 

randList <- NULL 
set.seed(2) 

randList[[1]] <- rnorm(100) 
randList[[2]] <- rnorm(200) 
randList[[3]] <- rnorm(300) 

#delete file contents 
fileName <- "/tmp/tmp.txt" 
cat("", file=fileName, append=F) 

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

linesIn <- readLines(fileName, n=-1) 

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

#floating point issue? 
identical(randList, parsedThing) 

for (i in 1:length(randList[[1]])) { 
    print(randList[[1]][[i]] == parsedThing[[1]][[i]]) 
} 

i<-3 
randList[[1]][[i]] == parsedThing[[1]][[i]] 

randList[[1]][[i]] 
parsedThing[[1]][[i]] 

下面是刪節輸出:

> #floating point issue? 
> identical(randList, parsedThing) 
[1] FALSE 
> 
> for (i in 1:length(randList[[1]])) { 
+ print(randList[[1]][[i]] == parsedThing[[1]][[i]]) 
+ } 
[1] TRUE 
[1] TRUE 
[1] FALSE 
[1] FALSE 
[1] TRUE 
[1] FALSE 
[1] TRUE 
[1] TRUE 
[1] FALSE 
[1] FALSE 
... 
> 
> i<-3 
> randList[[1]][[i]] == parsedThing[[1]][[i]] 
[1] FALSE 
> 
> randList[[1]][[i]] 
[1] 1.587845 
> parsedThing[[1]][[i]] 
[1] 1.587845 
> 
+0

其實,我們看不到,你是與輸出有點太經濟。 – 2010-06-25 16:16:09

回答

2

在您的通話ascii=Tserialize正在R請勿不精確的二進制小數二進制轉換時,序列化和反序列化造成的值有所不同。如果你刪除ascii=T,你會得到和現在一樣的數字,它是一個二進制表示,它被寫出來。

base64encode可以編碼原始矢量,所以它不需要ascii=T

serialize使用的二進制表示是architecture independent,因此您可以在一臺機器上愉快地序列化並在另一臺機器上反序列化。

參考:http://cran.r-project.org/doc/manuals/R-ints.html#Serialization-Formats

+0

很好的答案!謝謝! – 2010-06-26 18:12:29

2

JD:我跑我的Linux機器的代碼片斷,然後看着由randList計算的區別[[1]] [[i]] - parsedThing [[1]] [[I]]。

是的,值是不同的,但只在我的機器的浮點容差水平。典型的區別是-4.440892e-16 - 這非常小。有些差異是零。

保存/恢復引入(微小)變化水平並不讓我感到驚訝。任何重要的數據轉換都會導致「搖擺」最低有效數字的風險。

+0

歡迎來到SO,Paul。很高興有你在船上。 – Shane 2010-06-25 17:49:26

+0

這正是我認爲這是一個浮點舍入類型的錯誤。雖然噪音非常小,但我對引入噪音有點驚訝。這只是我的經驗之外,所以我想我會問起原因。假設這個「足夠接近」,我在代碼中向前滾動。很高興你在這裏! – 2010-06-25 18:02:42

+0

很高興來到這裏! – pteetor 2010-06-25 18:16:41

2

好的,現在你已經顯示了輸出結果,我可以向你解釋你在做什麼(在Paul的帶領下)。

由於這是一個已知的問題(例如參見本R FAQ entry),你應該扣起來,並使用來自RUnit

  • identical()
  • all.equal()
  • 功能中的任何一個,如checkEquals

總之,你使用的base64編碼似乎沒有錯。您只是採用了的錯誤定義,確切地說是。但是,嘿,我們是經濟學家和低於一萬億或兩個東西是無論如何舍入誤差...

+0

我曾在一家會計師事務所工作過一段時間,所以當我無法準確再現某些事物*時,耳道內會發出癢癢的聲音。謝謝你給我一個完整的檢查。 – 2010-06-25 18:17:14

+0

請參閱(經典)[每位計算機科學家應瞭解的浮點算術知識](http://docs.sun.com/source/806-3568/ncg_goldberg.html)。你我不是計算機科學家,但我們在電視上偶爾玩一個。 – 2010-06-25 18:21:13

+0

我以前實際上已經閱讀過大片。我擔心這些想法會被啤酒取代。我想責怪我的孩子擦掉我的大腦,但這可能不現實。這是啤酒。 – 2010-06-25 18:32:49