2011-08-12 51 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