大规模数据绘图

16
我们目前正在使用ZedGraph绘制一些数据的折线图。输入数据来自任意大小的文件,因此我们不知道预先使用多少数据点。但是,通过打开文件并读取头文件,我们可以找出文件中有多少数据点。
文件格式基本上是[时间(双精度)、值(双精度)]。然而,时间轴上的条目不均匀。例如,在t = 0秒和t = 10秒之间可能没有任何点,但在t = 10秒和t = 11秒之间可能有100K个条目,依此类推。
例如,我们的测试数据集文件大小约为2.6 GB,共有324M个点。我们想向用户显示整个图表,并让她浏览图表。然而,将324M个点加载到ZedGraph上不仅不可能(我们在32位机器上),而且也没有必要在屏幕上有这么多点。
使用ZedGraph的FilteredPointList功能也似乎不可行,因为那需要先加载整个数据,然后对该数据进行过滤。
因此,除非我们缺失了什么,否则看起来我们唯一的解决方案就是 - 以某种方式 - 减少数据量,但是随着我们不断地努力,我们遇到了很多问题:
1- 如何减少不按照时间到达的数据?
2- 由于整个数据无法加载到内存中,任何算法都需要在磁盘上工作,因此需要仔细设计。
3- 如何处理缩放,特别是当数据在x轴上不均匀时。
如果数据是均匀的,在图表的初始加载时,我们可以按预定义的文件条目数量进行Seek(),并选择每个N个样本,并将其馈送给ZedGraph。但是,由于数据不均匀,我们必须更加聪明地选择要显示的样本,并且我们无法想出任何智能算法,它不必读取整个文件。
很抱歉问题没有非常明确的具体性,但我希望我能够解释我们问题的性质和范围。
我们使用的是Windows 32位、.NET 4.0。
4个回答

9

我以前也需要过这个,但这并不容易。最终,由于这个需求,我写了自己的图形组件。结果更好,因为我加入了我们需要的所有功能。

基本上,您需要获取数据范围(最小和最大可能/所需索引值),将其细分为段(假设100个段),然后通过某种算法(平均值、中位数等)确定每个段的值。然后根据这些总结的100个元素进行绘图。这比试图绘制数百万个点要快得多 :-)。

所以我说的与你说的类似。你提到你不想绘制每个X元素,因为可能在元素之间有很长一段时间(x轴上的索引值)。我所说的是,在细分数据的每个部分中确定最佳值,并将其作为数据点。我的方法是基于索引值的,因此在您的示例中,在0秒和10秒索引值之间没有数据的情况下,我仍会在那里放置数据点,它们只会在彼此之间具有相同的值。 重点是在绘制之前对数据进行总结。仔细考虑如何执行算法,有很多方法可以选择,选择适合您的应用程序的方法即可。 您可能可以不编写自己的图形组件,只需编写数据汇总算法即可。


同意你的最后一点。适当地总结数据将减轻显示x个场景的头痛。 - Daniel Szabo
gmagana:是的,我认为这听起来像是一种解决方法。我只担心每当用户想要缩放时,我们就必须重新读取和重新总结文件。我们考虑过一些缓存算法,但由于图表上的数据在任何时间点都会被减少,缓存这些点可能没有意义。 - SomethingBetter
@SomethingBetter:是的,缩放是我编写自己的代码的原因之一。我们需要像谷歌金融图表(例如,http://www.google.com/finance?q=msft)那样的东西,所以我从头开始编写了它。 - Gabriel Magana

4
我会分两步来处理这个问题:
  1. 数据预处理
  2. 展示数据

第一步 该文件应该被预处理成一个二进制固定格式的文件。 在格式中添加索引,它将是int、double、double。 参见本文进行速度比较:

http://www.codeproject.com/KB/files/fastbinaryfileinput.aspx

你可以将文件分成时间间隔,例如每小时或每天一个,这样可以轻松地访问不同时间间隔。你也可以保留一个大文件,并有一个索引文件告诉你在哪里找到特定的时间点。
使用其中一种方法,你可以通过时间、索引或文件名快速查找任何数据块,或者通过条目数量查找,因为它是固定字节格式。
步骤2 展示数据的方式: 1.按索引显示每个记录。 2.归一化数据并创建具有开盘价、最高价、最低价和收盘价值的聚合数据条。 a.按时间 b.按记录计数 c.按值之间的差异
对于聚合非均匀数据集的更多可能方法,您可以查看金融市场中聚合交易数据所使用的不同方法。当然,为了实时渲染速度,您需要创建带有已聚合数据的文件。

3

1- 如何处理时间不均匀的数据?

(注意 - 我假设您的加载器数据文件是文本格式。)

在一个类似的项目中,我必须读取超过5GB大小的数据文件。唯一的方法是将其读入RDBMS表格中进行解析。我们选择了MySQL,因为它使得将文本文件导入数据表变得非常简单。(有趣的是--我使用32位Windows机器无法打开文本文件以查看内容,但MySQL却毫无问题地读取了它。)另一个好处是MySQL非常快。

一旦数据进入数据库,我们就可以轻松地对其进行排序,并将大量数据量化为单个概括性查询(使用内置SQL汇总函数如SUM)。MySQL甚至可以将其查询结果读回到文本文件中作为加载器数据使用。

长话短说,消耗这么多数据需要使用能够概括数据的工具。MySQL符合要求(免费)。


很有趣,将所有这些数据先存入数据库可能需要很多时间,但我想如果我们要一遍又一遍地分析相同的数据,这可能会有所帮助。尽管如此,这并没有解决我们的根本问题:如何读取这些数据,总结出合理数量的要点并在图表中展示。--谢谢 - SomethingBetter

2
我发现一个相对简单的替代方案,可以按照以下步骤进行:
  1. 将数据分组迭代处理(每次处理3到5个点 - 组大小越大,算法处理速度越快,但聚合精度会降低)。
  2. 计算小组的最小值和最大值。
  3. 从该组中删除所有不是最小或最大值的点(即仅保留每组中的2个点并省略其余点)。
  4. 循环遍历数据(重复此过程),从开始到结束删除点,直到聚合数据集具有足够少的点数,可以在不阻塞电脑的情况下绘制图表。
我以前使用过这种算法,将约1000万个点的数据集缩减到了约5000个点的级别,而且没有明显的可见图形失真。
这里的思路是,在扔掉点的同时,保留峰谷值,因此在最终图形中查看“信号”时,它不会被“平均掉”(通常,如果进行平均,您将看到峰谷值变得不那么突出)。
另一个优点是,您始终可以在最终图表上看到“真实”的数据点(虽然缺少了一些点,但是那里的点实际上是原始数据集中存在的,因此如果您将鼠标悬停在某个位置,可以显示实际的x和y值,因为它们是真实的,而不是平均值)。
最后,这也有助于解决没有一致的x轴间距的问题(同样,您将拥有真实的点而不是平均X轴位置)。
我不确定像您所拥有的数亿个数据点是否适用于这种方法,但是可能值得一试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接