Диаграмма огромных объемов данных - PullRequest
16 голосов
/ 27 января 2011

В настоящее время мы используем ZedGraph, чтобы нарисовать линейную диаграмму некоторых данных. Входные данные поступают из файла произвольного размера, поэтому мы не знаем, какое максимальное количество точек данных заранее. Однако, открыв файл и прочитав заголовок, мы можем узнать, сколько точек данных в файле.

Формат файла по существу [время (двойной), значение (двойной)]. Однако записи не являются одинаковыми по оси времени. Может не быть никаких точек между, скажем, t = 0 сек и t = 10 сек, но может быть 100K между интервалом t = 10 сек и t = 11 сек и т. Д.

Например, наш файл тестового набора данных составляет ~ 2,6 ГБ и имеет 324 млн. Точек. Мы хотели бы показать весь график пользователю и позволить ему перемещаться по графику. Однако загрузка 324M точек в ZedGraph не только невозможна (мы работаем на 32-разрядной машине), но и бесполезна, поскольку нет смысла иметь так много точек на экране.

Использование функции FilteredPointList в ZedGraph также, по-видимому, не подлежит сомнению, поскольку для этого требуется сначала загрузить все данные, а затем выполнить фильтрацию этих данных.

Итак, если мы ничего не упустили, похоже, что наше единственное решение - как-то - уничтожить данные, однако, продолжая работать над этим, мы сталкиваемся с множеством проблем:

1- Как мы уничтожаем данные, которые поступают неравномерно во времени?

2 - Поскольку все данные не могут быть загружены в память, любой алгоритм должен работать на диске и поэтому должен быть тщательно спроектирован.

3- Как мы справляемся с увеличением и уменьшением, особенно, когда данные не однородны по оси X.

Если данные были однородными, при начальной загрузке графика мы могли бы Seek() по заранее определенному количеству записей в файле, выбирать каждые N других образцов и передавать их в ZedGraph. Однако, поскольку данные не являются единообразными, мы должны быть более разумными в выборе образцов для отображения, и мы не можем придумать какой-либо интеллектуальный алгоритм, который бы не считывал весь файл.

Я прошу прощения, поскольку этот вопрос не имеет четкой специфики, но я надеюсь, что смогу объяснить природу и масштабы нашей проблемы.

Мы находимся на 32-битной Windows, .NET 4.0.

Ответы [ 4 ]

8 голосов
/ 27 января 2011

Я нуждался в этом раньше, и это нелегко сделать.Я закончил писать свой собственный компонент графика из-за этого требования.В итоге получилось лучше, потому что я добавил все необходимые функции.

В основном вам нужно получить диапазон данных (минимальное и максимальное возможное / необходимое значение индекса), разделить на сегменты (скажем,100 сегментов), а затем определите значение для каждого сегмента по некоторому алгоритму (среднее значение, медианное значение и т. Д.).Затем вы строите график на основе этих 100 элементов.Это гораздо быстрее, чем пытаться построить миллионы точек: -).

Так что то, что я говорю, похоже на то, что вы говорите.Вы упоминаете, что не хотите отображать все элементы X, потому что между элементами может быть длительный промежуток времени (значения индекса по оси x).Я хочу сказать, что для каждого подразделения данных определите, какое значение является наилучшим, и примите это как точку данных.Мой метод основан на значениях индекса, поэтому в вашем примере нет данных между значениями индекса от 0 сек до 10 сек. Я бы все равно поместил туда точки данных, они бы просто имели одинаковые значения между собой.

Дело в том,суммировать данные, прежде чем строить их.Тщательно продумайте свои алгоритмы, чтобы сделать это, есть много способов сделать это, выберите тот, который подходит для вашего приложения.

Вам может не понравиться не писать свой собственный компонент графика и просто написать суммирование данныхалгоритм.

4 голосов
/ 28 января 2011

Я бы подошел к этому в два этапа:

  1. Предварительная обработка данных
  2. Отображение данных

Шаг 1 Файл должен быть предварительно обработанв двоичный файл фиксированного формата.При добавлении индекса к формату это будет int, double, double.См. Эту статью для сравнения скорости:

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

Затем вы можете разбить файл на временные интервалы, скажем, один раз в час или день, что даст вам простой способ выразитьдоступ к различным временным интервалам.Вы также можете просто сохранить один большой файл и иметь индексный файл, который скажет вам, где найти определенное время:

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

Используя один из этих методов, вы сможете быстро найти любой блок данных по времени, по индексу или имени файла, или по количеству записей, благодаря фиксированному байтуформат.

Шаг 2 Способы отображения данных 1. Просто отобразите каждую запись по индексу.2. Нормализуйте данные и создайте совокупные панели данных со значениями открытия, максимума, минимума и закрытия.а.По времени б.По количеству записей c.По разнице между значениями

Для более возможных способов агрегирования неоднородных наборов данных вы можете рассмотреть различные методы, используемые для агрегирования торговых данных на финансовых рынках.Конечно, для скорости рендеринга в реальном времени вы захотите создать файлы с уже агрегированными данными.

3 голосов
/ 28 января 2011

1- Как мы можем децитировать данные, которые не поступают равномерно во времени?

( Примечание - я предполагаю, что ваш файл данных загрузчика находится в текстовом формате.)

В аналогичном проекте мне пришлось читать файлы данных размером более 5 ГБ.Единственный способ, которым я мог разобрать это, было, читая это в таблицу RDBMS.Мы выбрали MySQL, потому что он упрощает импорт текстовых файлов в таблицы данных.(Интересно отметить, что я был на 32-битной машине с Windows и не мог открыть текстовый файл для просмотра, но MySQL прочитал его без проблем.) Другой привилегией было то, что MySQL screaming, screaming fast .

Как только данные были в базе данных, мы могли легко отсортировать их и количественно определить большие объемы данных в единичные перефразированные запросы (используя встроенные функции сводки SQL, такие как SUM).MySQL может даже считывать результаты своих запросов обратно в текстовый файл для использования в качестве данных загрузчика.

Короче говоря, использование такого большого количества данных требует использования инструмента, который может обобщать данные.MySQL отвечает всем требованиям (каламбур ... бесплатно).

1 голос
/ 04 января 2018

Относительно простая альтернатива, которую я нашел, это сделать следующее:

  1. Повторяйте данные в небольших точечных группировках (скажем, от 3 до 5 точек за раз - чем больше группа, тем быстрее будет работать алгоритм, но менее точной будет агрегация).
  2. Вычислите минимальное и максимальное значения для небольшой группы.
  3. Удалите все точки, которые не минимальные или максимальные из этой группы (т. Е. Вы оставляете только 2 пункта из каждой группы и пропускаете остальные).
  4. Продолжайте циклически перебирать данные (повторяя этот процесс) от начала до конца, удаляя точки до тех пор, пока у агрегированного набора данных не будет достаточно маленькое количество точек, в которых он может быть нанесен на карту без удушения ПК.

Я использовал этот алгоритм в прошлом, чтобы брать наборы данных ~ 10 миллионов точек до порядка ~ 5K точек без каких-либо явных видимых искажений на графике.

Идея в том, что, отбрасывая точки, вы сохраняете пики и впадины, чтобы «сигнал», видимый на конечном графике, не «усреднялся вниз» (обычно, если при усреднении вы увидите пики и долины становятся менее заметными).

Другое преимущество заключается в том, что вы всегда видите «настоящие» точки данных на конечном графике (в нем отсутствует куча точек, но точки, которые были на самом деле в исходном наборе данных, поэтому, если вы наводите курсор мыши на что-то, вы может показывать фактические значения x & y, потому что они реальные, а не усредненные).

Наконец, это также помогает решить проблему отсутствия постоянного интервала по оси X (опять же, у вас будут реальные точки вместо усреднения позиций по оси X).

Я не уверен, насколько хорошо этот подход будет работать с сотнями миллионов точек данных, как у вас, но, возможно, стоит попробовать.

...