【问题标题】:Fastest & most flexible way to chart over 2 million rows of flat file data?以最快、最灵活的方式绘制超过 200 万行平面文件数据?
【发布时间】:2011-07-04 10:20:12
【问题描述】:

我正在一个平面文件中收集一些系统数据,格式如下:

YYYY-MM-DD-HH24:MI:SS DD1 DD2 DD3 DD4

其中 DD1-DD4 是四项数据。 该文件的一个示例是这样的:

2011-02-01-13:29:53 16 8 7 68
2011-02-01-13:29:58 13 8 6 110
2011-02-01-13:30:03 26 25 1 109
2011-02-01-13:30:08 13 12 1 31
2011-02-01-13:30:14 192 170 22 34
2011-02-01-13:30:19 16 16 0 10
2011-02-01-13:30:24 137 61 76 9
2011-02-01-13:30:29 452 167 286 42
2011-02-01-13:30:34 471 177 295 11
2011-02-01-13:30:39 502 192 309 10

该文件超过 200 万行,每五秒有一个数据点。

我需要将这些数据绘制成图表,以便从中获得意义。

我的尝试

目前我已经尝试使用各种 unix 工具(awk、sed 等)使用 gnuplot 和 rrdtool。这两种方法都有效,但每次我想以不同的方式查看数据时,似乎都需要大量的切碎和重新切割数据。 我的直觉是 rrdtool 是正确的方法,但目前我正在努力将数据足够快地输入其中,部分原因是我必须将时间戳转换为 Unix 纪元。我的理解也是,如果我决定想要一个新的聚合粒度,我必须重建 rrd(这对于实时收集是有意义的,但不是这样的追溯加载)。这些事情让我觉得我可能使用了错误的工具。

将数据收集到平面文件是固定的 - 例如,我无法将集合直接通过管道传输到 rrdtool。

我的问题

我希望人们对制作图表的最佳方式提出意见。我有这些要求:

  1. 应该尽可能快地创建图表(不仅仅是渲染,还要设置渲染)
  2. 它应该尽可能灵活 - 我需要处理图表才能工作 找出数据的最佳粒度(5 秒可能太细了)
  3. 它应该能够在必要时聚合 (MAX/AVG/etc)
  4. 它应该是可重复的,新的数据文件进来时
  5. 理想情况下,我希望能够将 DD1 与 DD2 或上周的 DD1 与本周的 DD1 叠加
  6. Unix 或 Windows,不管。不过更喜欢 *nix :-)

有什么建议吗?

【问题讨论】:

  • 我添加了 R 标签,因为 Kodner 在海滩。 (混蛋)
  • 谢谢大家的回答,好像只能接受一个但是都很好!
  • @RobinMoffatt 你的问题怎么不是固执己见而我的呢?您专门提出了与我类似的问题,但您投票结束了我的问题。 stackoverflow.com/questions/65071679/…抱歉不知道其他引起注意的方法

标签: r graph gnuplot flat-file rrdtool


【解决方案1】:

这是一个非常好的问题。我很高兴看到一些 R 人参与进来。我也认为 R 是完成这项工作的合适工具,尽管它是我的主要锤子,所以对我来说,一切看起来有点像钉子。

需要一些 R 概念来应对这一挑战。在我看来,您需要以下内容(括号中的引用):

  1. 将数据导入 R。(R Import Export Guide)
  2. 将数据放入适当的时间序列结构中。 (XTS Vignette PDF)
  3. 有点阴谋。 (Quick-R intro to graphics)

这是使用 2mm 点的示例代码。如果您注意到,我没有说明绘制所有 2 毫米点。它很慢,而且信息量不大。但这应该会给您一些入门的想法。如果您决定跳下 R 兔子洞,请随时提出更具体的问题!

require( xts )
require( lubridate )

## set up some example data
dataLength <- 2e6
startTime <- ymd_hms("2011-02-01-13-29-53")
fistFullOfSeconds <- 1:dataLength
date <- startTime + fistFullOfSeconds
DD1 <- rnorm( dataLength )
DD2 <- DD1 + rnorm(dataLength, 0, .1 )
DD3 <- rnorm( dataLength, 10, 2)
DD4 <- rnorm( dataLength )

myXts <- xts(matrix( c( DD1, DD2, DD3, DD4 ), ncol=4 ), date)

## now all the data are in the myXts object so let's do some
## summarizing and visualization

## grabbing just a single day from the data
## converted to data.frame to illustrate default data frame plotting
oneDay <- data.frame( myXts["2011-02-02"] ) 
plot( oneDay )

DD1和DD2的关系有点跳出来

boxplot( oneDay )

箱线图是统计图形的饼图。你爱恨的情节。我们在这里的时候也可以link to this

## look at the max value of each variable every minute
par(mfrow=c(4,1)) ## partitions the graph window
ep <- endpoints(myXts,'minutes')
plot(period.apply(myXts[,1],INDEX=ep,FUN=max))
plot(period.apply(myXts[,2],INDEX=ep,FUN=max))
plot(period.apply(myXts[,3],INDEX=ep,FUN=max))
plot(period.apply(myXts[,4],INDEX=ep,FUN=max))

即使在一分钟的分辨率下,我也不确定这是否具有信息性。应该可能是子集。

【讨论】:

  • 很好的答案 JD,很好地说明了一些使这些事情比基本 R 功能更容易的附加包。
  • 同意。但是一定要玩 a) 'alpha blending' 以允许过度绘图(并非所有图形设备都支持它),b) 很棒的 hexbin 包,或者像 JD 那样 c) 子采样。对于数据的设置方式来说,每分钟一次仍然过于细粒度(有第二个间隔)。
  • @Dirk re:每一分钟——确实如此。在最初在分钟时间步执行之后,我编辑了我的答案以处理每小时聚合,这只是一团糟。
  • @JD 为什么必须将myXts 加载为xts(matrix( c( DD1, DD2, DD3, DD4 ), ncol=4 ), date) 而不是xts( c( DD1, DD2, DD3, DD4) )
  • @Lao, DD1-4 是每个向量。如果你做 c( DD1, DD2, DD3, DD4) 你得到一个向量的四倍长。我希望 4 个向量中的每一个都是 xts 对象中的“列”
【解决方案2】:

这里有一些 R 代码,用于在 2000000 行的 4 列中处理 8000000 个数字:

> d=matrix(runif(8000000),ncol=4)
> dim(d)
[1] 2000000       4
> plot(d[1:1000,1])
> plot(d[1:1000,1],type='l')
> plot(d[1:10000,1],type='l')

现在开始有点慢了:

> plot(d[1:100000,1],type='l')

两列的相关性如何:

> cor(d[,1],d[,2])
[1] 0.001708502

——瞬间。傅里叶变换?

> f=fft(d[,1])

也是即时的。不过不要尝试绘制它。

让我们绘制其中一列的细化版本:

> plot(d[seq(1,2000000,len=1000),1],type='l')

——瞬间。

真正缺少的是一个交互式绘图,您可以在其中缩放和平移整个数据集。

【讨论】:

  • 为了搞笑和乐趣,我加载了你的 d 矩阵并在 ggplot 中弄乱了 alpha 参数。花了大约 2 分钟,但我能够用qplot(d[,1], d[,2], alpha = 1/100) 制作this 非常丰富的情节。我认为您对数据集“精简”版本的概念将成为处理如此多数据的方式。
  • @chase,我把它用彩色打印出来挂在墙上。我将其命名为“黑暗”。
  • @jd - 我认为如果我们在其中添加colour = rnorm(100) 或其他内容,我们可以用它们制作一个系列。把这个“免费和开源”的东西变成盈利的圣地!
  • 让它们在黑光下发光,所有统计数据的学生都会让它们挂在宿舍里。我们可以在这里拥有下一个伟大的“天鹅绒猫王”
【解决方案3】:

这是一个示例,与您拥有的数据有关,如加载到 R 中、聚合等...

首先,将一些虚拟数据写入文件:

stime <- as.POSIXct("2011-01-01-00:00:00", format = "%Y-%d-%m-%H:%M:%S")
## dummy data
dat <- data.frame(Timestamp = seq(from = stime, by = 5, length = 2000000),
                  DD1 = sample(1:1000, replace = TRUE),
                  DD2 = sample(1:1000, replace = TRUE),
                  DD3 = sample(1:1000, replace = TRUE),
                  DD4 = sample(1:1000, replace = TRUE))
## write it out
write.csv(dat, file = "timestamp_data.txt", row.names = FALSE)

然后我们可以定时读取 200 万行。为了加快速度,我们告诉 R 文件中列的类:"POSIXct" 是 R 中存储您拥有的时间戳的一种方式。

## read it in:
system.time({
             tsdat <- read.csv("timestamp_data.txt", header = TRUE,
                                 colClasses = c("POSIXct",rep("integer", 4)))
            })

在我普通的笔记本电脑上,大约需要 13 秒来读取和格式化内部 unix 时间。

   user  system elapsed 
 13.698   5.827  19.643 

可以通过多种方式进行聚合,一种是使用aggregate()。说聚合到小时平均值/平均值:

## Generate some indexes that we'll use the aggregate over
tsdat <- transform(tsdat,
                   hours   = factor(strftime(tsdat$Timestamp, format = "%H")),
                   jday    = factor(strftime(tsdat$Timestamp, format = "%j")))
## compute the mean of the 4 variables for each minute
out <- aggregate(cbind(Timestamp, DD1, DD2, DD3, DD4) ~ hours + jday, 
                 data = tsdat, FUN = mean)
## convert average Timestamp to a POSIX time
out <- transform(out,
                 Timestamp = as.POSIXct(Timestamp, 
                                        origin = ISOdatetime(1970,1,1,0,0,0)))

那(创建out 的行)在我的笔记本电脑上需要大约 16 秒,并给出以下输出:

> head(out)
  hours jday           Timestamp      DD1      DD2      DD3      DD4
1    00  001 2010-12-31 23:29:57 500.2125 491.4333 510.7181 500.4833
2    01  001 2011-01-01 00:29:57 516.0472 506.1264 519.0931 494.2847
3    02  001 2011-01-01 01:29:57 507.5653 499.4972 498.9653 509.1389
4    03  001 2011-01-01 02:29:57 520.4111 500.8708 514.1514 491.0236
5    04  001 2011-01-01 03:29:57 498.3222 500.9139 513.3194 502.6514
6    05  001 2011-01-01 04:29:57 515.5792 497.1194 510.2431 496.8056

使用plot()函数可以实现简单的绘图:

plot(DD1 ~ Timestamp, data = out, type = "l")

我们可以通过以下方式覆盖更多变量,例如:

ylim <- with(out, range(DD1, DD2))
plot(DD1 ~ Timestamp, data = out, type = "l", ylim = ylim)
lines(DD2 ~ Timestamp, data = out, type = "l", col = "red")

或通过多个面板:

layout(1:2)
plot(DD1 ~ Timestamp, data = out, type = "l", col = "blue")
plot(DD2 ~ Timestamp, data = out, type = "l", col = "red")
layout(1)

这一切都是通过基本的 R 功能完成的。其他人已经展示了附加包如何使处理日期更容易。

【讨论】:

    猜你喜欢
    • 2013-10-29
    • 2014-04-25
    • 1970-01-01
    • 2018-07-01
    • 2023-03-22
    • 2016-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多