Могу ли я ускорить вычисления между R и Sqlite, используя data.tables? - PullRequest
0 голосов
/ 03 июля 2019

У меня есть база данных sqlite около 1,4 миллиона строк и 16 столбцов.

Мне нужно выполнить операцию на 80 000 идентификаторов:

  1. Получить все строки, связанные с этим идентификатором
  2. преобразовать в объект даты R и отсортировать по дате
  3. Рассчитать разницу между двумя самыми последними датами

Для каждого идентификатора, который я запрашивал sqlite из R, используя dbSendQuery и dbFetch для шага 1, тогда как шаги 2 и 3 выполняются в R. Есть ли более быстрый способ? Быстрее или медленнее будет загрузить всю таблицу sqlite в data.table?

Ответы [ 2 ]

1 голос
/ 04 июля 2019

Если вы делаете все это в R и извлекаете строки из базы данных 80,0000 раз в цикле ... у вас, вероятно, будут лучшие результаты, если вы сделаете все это за один раз в sqlite.

Имеется таблица скелетов, такая как:

CREATE TABLE data(id INTEGER, timestamp TEXT);
INSERT INTO data VALUES (1, '2019-07-01'), (1, '2019-06-25'), (1, '2019-06-24'),
                        (2, '2019-04-15'), (2, '2019-04-14');
CREATE INDEX data_idx_id_time ON data(id, timestamp DESC);

запрос типа:

SELECT id
     , julianday(first_ts)
       - julianday((SELECT max(d2.timestamp)
                    FROM data AS d2
                    WHERE d.id = d2.id AND d2.timestamp < d.first_ts)) AS days_difference
FROM (SELECT id, max(timestamp) as first_ts FROM data GROUP BY id) AS d
ORDER BY id;

даст вам

id          days_difference
----------  ---------------
1           6.0
2           1.0

Альтернатива для современных версий sqlite (3.25 или новее) (РЕДАКТИРОВАТЬ: В тестовой базе данных с 16 миллионами строк и 80000 различных идентификаторов она работает значительно медленнее, чем приведенная выше, поэтому вы не хотите использовать ее на самом деле ):

WITH cte AS
 (SELECT id, timestamp
       , lead(timestamp, 1) OVER id_by_ts AS next_ts
       , row_number() OVER id_by_ts AS rn
  FROM data
  WINDOW id_by_ts AS (PARTITION BY id ORDER BY timestamp DESC))
SELECT id, julianday(timestamp) - julianday(next_ts) AS days_difference
FROM cte
WHERE rn = 1
ORDER BY id;

(Индекс необходим для производительности для обеих версий. Вероятно, вы захотите запустить ANALYZE в таблице в какой-то момент после ее заполнения и создания ваших индексов.)

1 голос
/ 03 июля 2019

Я сильно зависит от того, как вы работаете над этой проблемой.

Обычно загрузка всего запроса в память, а затем выполнение операции будет происходить быстрее, чем то, что я испытал и увидел на графике, я не могу сейчас показать вам эталонный тест. Если логически это имеет смысл, мы надеемся, что вам нужно повторить несколько операций несколько раз для нескольких data.frames. Как вы можете видеть здесь, 80k строк довольно быстро, быстрее, чем 3x 26xxx строк.

enter image description here

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

Здесь вы можете найти информацию, как это сделать: http://jaehyeon -kim.github.io / 2015/03 / Parallel-Processing-на-Single-Machine-Part-I

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