16

我们目前正在使用 ZedGraph 来绘制一些数据的折线图。输入数据来自任意大小的文件,因此,我们事先不知道最大数据点数是多少。但是,通过打开文件并读取文件头,我们可以找出文件中有多少个数据点。

文件格式本质上是[time (double), value (double)]。但是,这些条目在时间轴上并不统一。在 t = 0 sec 和 t = 10 sec 之间可能没有任何点,但在 t = 10 sec 和 t = 11 sec 之间可能有 100K 个整数,依此类推。

例如,我们的测试数据集文件约为 2.6 GB,它有 324M 点。我们想向用户展示整个图表并让她浏览图表。然而,将 324M 点加载到 ZedGraph 不仅是不可能的(我们在 32 位机器上),而且也没有用处,因为在屏幕上有这么多点是没有意义的。

使用 ZedGraph 的 FilteredPointList 功能似乎也不成问题,因为这需要首先加载整个数据,然后对该数据执行过滤。

因此,除非我们遗漏任何东西,否则我们唯一的解决方案似乎是 - 以某种方式 - 抽取数据,但是随着我们不断努力,我们遇到了很多问题:

1- 我们如何抽取未及时统一到达的数据?

2-由于无法将整个数据加载到内存中,因此任何算法都需要在磁盘上运行,因此需要仔细设计。

3- 我们如何处理放大和缩小,尤其是当数据在 x 轴上不均匀时。

如果数据是统一的,在初始加载图时,我们可以Seek()通过文件中预定义的条目数量,每隔 N 个样本选择一次并将其提供给 ZedGraph。但是,由于数据不统一,我们必须更加智能地选择要显示的样本,并且我们无法提出任何不必读取整个文件的智能算法。

我很抱歉,因为这个问题没有尖锐的特异性,但我希望我能解释我们问题的性质和范围。

我们使用的是 Windows 32 位、.NET 4.0。

4

4 回答 4

9

I've needed this before, and it's not easy to do. I ended up writing my own graph component because of this requirement. It turned out better in the end because I put in all the features we needed.

Basically, you need to get the range of data (min and max possible/needed index values), subdivide it into segments (let's say 100 segments), and then determine a value for each segment by some algorithm (average value, median value, etc.). Then you plot based on those summarized 100 elements. This is much faster than trying to plot millions of points :-).

So what I am saying is similar to what you are saying. You mention you do not want to plot every X element because there might be a long stretch of time (index values on the x-axis) between elements. What I am saying is that for each subdivision of data determine what is the best value, and take that as the data point. My method is index value-based, so in your example of no data between the 0 sec and 10-sec index values I would still put data points there, they would just have the same values among themselves. The point is to summarize the data before you plot it. Think through your algorithms to do that carefully, there are lots of ways to do so, choose the one that works for your application. You might get away with not writing your own graph component and just write the data summarization algorithm.

于 2011-01-27T20:54:40.970 回答
4

我将分两步解决这个问题:

  1. 预处理数据
  2. 显示数据

步骤 1 将文件预处理为二进制固定格式文件。向格式添加索引,它将是 int,double,double。有关速度比较,请参阅本文:

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

然后,您可以将文件分解为时间间隔,例如每小时或每天一个,这将为您提供一种简单的方法来表示访问不同的时间间隔。你也可以只保留一个大文件并有一个索引文件,它告诉你在哪里可以找到特定的时间,

1,1/27/2011 8:30:00
13456,1/27/2011 9:30:00

通过使用其中一种方法,由于固定的字节格式,您将能够通过索引或文件名或条目数快速找到任何数据块。

步骤 2 显示数据的方法 1. 只需按索引显示每条记录。2. 规范化数据并创建具有开盘价、最高价、最低价、收盘价的聚合数据条。一个。按时间 b. 按记录计数 C. 按值之间的差异

有关聚合非统一数据集的更多可能方法,您可能需要查看用于聚合金融市场交易数据的不同方法。当然,为了实时渲染的速度,您可能希望使用已经聚合的数据创建文件。

于 2011-01-27T21:22:47.117 回答
3

1- 我们如何抽取未及时统一到达的数据?

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

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

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

长话短说,消耗这么多数据要求使用可以汇总数据的工具。MySQL 符合要求(双关语……它是免费的)。

于 2011-01-27T21:01:42.950 回答
2

我发现这样做的一个相对简单的替代方法是执行以下操作:

  1. 迭代小点分组中的数据(比如一次 3 到 5 个点 - 组越大,算法运行得越快,但聚合的准确性越低)。
  2. 计算小组的最小值和最大值。
  3. 从该组中删除所有不是最小值或最大值的点(即,您只从每组中保留 2 个点并忽略其余点)。
  4. 继续循环遍历数据(重复此过程)从头到尾删除点,直到聚合数据集具有足够少的点,可以在不阻塞 PC 的情况下绘制图表。

我过去曾使用此算法将约 1000 万点的数据集降低到约 5K 点的数量级,而图形没有任何明显的可见失真。

这里的想法是,在丢弃点的同时,您保留了峰值和谷值,因此在最终图表中查看的“信号”不会“平均下降”(通常,如果进行平均,您会看到峰值和山谷变得不那么突出)。

另一个优点是您总是在最终图表上看到“真实”数据点(它缺少一堆点,但那里的点实际上在原始数据集中,因此,如果您将鼠标悬停在某些东西上,您可以显示实际的 x 和 y 值,因为它们是真实的,而不是平均的)。

最后,这也有助于解决 x 轴间距不一致的问题(同样,您将拥有实点而不是平均 X 轴位置)。

我不确定这种方法在你拥有的数百万个数据点的情况下效果如何,但它可能值得一试。

于 2018-01-04T17:33:25.683 回答