2011-08-12 50 views
2

我有一些JSON格式的數據,我想對其進行一些可視化處理。數據(大約10MB的JSON)加載非常快,但將其重新塑造成可用的形式需要幾分鐘的時間,只有100,000行。我有一些工作,但我認爲它可以做得更好。轉換JSON數據的性能問題

從我的sample data開始,這可能是最容易理解的。

假設你在/tmp運行以下命令:

curl http://public.west.spy.net/so/time-series.json.gz \ 
    | gzip -dc - > time-series.json 

你應該能夠看到(過了一會兒)我的期望輸出這裏:

require(rjson) 

trades <- fromJSON(file="/tmp/time-series.json")$rows 


data <- do.call(rbind, 
       lapply(trades, 
         function(row) 
          data.frame(date=strptime(unlist(row$key)[2], "%FT%X"), 
             price=unlist(row$value)[1], 
             volume=unlist(row$value)[2]))) 

someColors <- colorRampPalette(c("#000099", "blue", "orange", "red"), 
           space="Lab") 
smoothScatter(data, colramp=someColors, xaxt="n") 

days <- seq(min(data$date), max(data$date), by = 'month') 
smoothScatter(data, colramp=someColors, xaxt="n") 
axis(1, at=days, 
     labels=strftime(days, "%F"), 
     tick=FALSE) 
+1

下面的算法答案是最大加速比來自哪裏,但我發現RJSONIO在某些測試中比rjson快(並且在解析各種JSON結構時更可靠)。可能值得嘗試一下 - 使用方法是相同的。 – Noah

+0

感謝您的指針。我幾乎任意挑選。 – Dustin

回答

5

使用plyr可以獲得40倍的加速比。這裏是代碼和基準比較。一旦你有了數據框,就可以完成到日期的轉換,因此我已經將它從代碼中移除,以便於蘋果與蘋果的比較。我確信存在更快的解決方案。

f_ramnath = function(n) plyr::ldply(trades[1:n], unlist)[,-c(1, 2)] 
f_dustin = function(n) do.call(rbind, lapply(trades[1:n], 
       function(row) data.frame(
        date = unlist(row$key)[2], 
        price = unlist(row$value)[1], 
        volume = unlist(row$value)[2])) 
       ) 
f_mrflick = function(n) as.data.frame(do.call(rbind, lapply(trades[1:n], 
       function(x){ 
        list(date=x$key[2], price=x$value[1], volume=x$value[2])}))) 

f_mbq = function(n) data.frame(
      t(sapply(trades[1:n],'[[','key')),  
      t(sapply(trades[1:n],'[[','value'))) 

rbenchmark::benchmark(f_ramnath(100), f_dustin(100), f_mrflick(100), f_mbq(100), 
    replications = 50) 

test   elapsed relative 
f_ramnath(100) 0.144  3.692308  
f_dustin(100) 6.244  160.102564  
f_mrflick(100) 0.039  1.000000  
f_mbq(100)  0.074  1.897436 

編輯。 MrFlick的解決方案導致額外的3.5倍加速。我已經更新了我的測試。

+0

我從中學到了很多東西。非常感謝。 :) – Dustin

+0

很酷。讓我們知道您在處理100k行時獲得的加速!將有助於知道 – Ramnath

+0

關於mbq的注意事項:即使我們正在處理strptime,它應該至少可以提取日期列。 – Dustin

0

是配料的選擇嗎?一次處理1000行可能取決於json的深度。你真的需要轉換所有的數據嗎?我不確定r和你在處理什麼,但我正在考慮一種通用的方法。

也請看看這個:http://jackson.codehaus.org/:高性能JSON處理器。

+0

那麼,任何工作都很好,但我不希望〜100k行是很難執行一些轉換。不過,我確實需要立即爲情節提供所有的結果數據。行幾乎是你在那裏看到的:日期,價格,音量。由於源代碼,它周圍有一堆JSON,但源代碼非常方便。 – Dustin

+0

你不能不斷更新你生成的json批次的情節? – Baz1nga

+0

我不知道,但說實話,*感覺*不必要。閱讀JSON需要幾秒鐘。生成完整的情節大約需要一秒鐘。將JSON數據轉換爲我可以輸入到「smoothScatter」中的東西需要幾分鐘時間。看來,必須有另一種方式。 – Dustin

3

我在IRC這是顯著更快,這裏值得一提的接收到另一個轉型的MrFlick:

data <- as.data.frame(do.call(rbind, 
           lapply(trades, 
            function(x) {list(date=x$key[2], 
                price=x$value[1], 
                volume=x$value[2])}))) 

這似乎是沒有建立內部框架顯著快發。

+0

是的。他的解決方案比我的速度快3.5倍。我已經更新了我的基準比較。如果你能'不接受'我的回答,那我們就能得到更快的解決方案! – Ramnath

+0

我還不能接受我的數據,但你的分析包括所有的變化。非常感謝。 – Dustin

3

您正在對單個元素進行矢量化操作,效率非常低。價格和體積可以提取這樣的:

t(sapply(trades,'[[','value')) 

和日期這樣的:

strptime(sapply(trades,'[[','key')[c(F,T)],'%FT%X') 

現在只有一些糖和完整的代碼如下所示:

data.frame(
strptime(sapply(trades,'[[','key')[c(F,T)],'%FT%X'), 
t(sapply(trades,'[[','value')))->data 
names(data)<-c('date','price','volume') 

在我的筆記本整個集合在0.7s左右被轉換,而10k第一行(10%)使用原始算法大約8s。

+0

不錯的方法,但由mrflick的解決方案仍然勝過2× – Ramnath

+0

@Ramnath嘗試在更大的數據上進行基準測試。即使在你的實現不太理想的情況下,我的版本也會超過mrflick的大約500行,並且整個集合的速度略快1.5倍。 – mbq

+0

@Ramnath在我的機器上,在mbq的解決方案中使用'as.data.frame'可以使得它僅在100行上達到最快,並且隨着您使用更多的行,邊距也會增長很多。 – joran