Как объединить таблицы в Matlab (2018), сопоставляя временные интервалы?
У меня есть две таблицы A и B. Я хочу присоединиться к ним на основании их временных интервалов.
A имеет качество продукции (нерегулярное время), а B имеет почасовые настройки в течение периода производства. Мне нужно создать таблицу типа C, которая включает параметры p1 и p2 для всех RefDates A, которые попадают во временной диапазон ValidFrom от ValidTo.
A
RefDate result
'11-Oct-2017 00:14:00' 17
'11-Oct-2017 00:14:00' 19
'11-Oct-2017 00:20:00' 5
'11-Oct-2017 01:30:00' 25
'11-Oct-2017 01:30:00' 18
'11-Oct-2017 03:03:00' 28
B
ValidFrom ValidTo p1 p2
'11-Oct-2017 00:13:00' '11-Oct-2017 01:12:59' 2 1
'11-Oct-2017 01:13:00' '11-Oct-2017 02:12:59' 3 1
'11-Oct-2017 02:13:00' '11-Oct-2017 03:12:59' 4 5
'11-Oct-2017 03:13:00' '11-Oct-2017 04:12:59' 6 1
'11-Oct-2017 04:13:00' '11-Oct-2017 05:12:59' 7 9
Мне нужно получить что-то подобное.
C
RefDate res p1 p2
'11-Oct-2017 00:14:00' 17 2 1
'11-Oct-2017 00:14:00' 19 2 1
'11-Oct-2017 00:20:00' 5 2 1
'11-Oct-2017 01:30:00' 25 3 1
'11-Oct-2017 01:30:00' 18 3 1
'11-Oct-2017 03:03:00' 28 4 5
Я знаю, как сделать это в SQL, и я думаю, что я понял, как сделать это строка за строкой в MatLab, но это ужасно медленно. Набор данных довольно большой. Я просто предполагаю, что должен быть более элегантный способ, который я просто не мог найти.
То, что вызвало сбой многих моих подходов, - это то, что столбец RefDate не уникален.
редактировать: реальные таблицы имеют тысячи строк и сотни переменных.
C (in reality)
RefDate res res2 ... res200 p1 p2 ... p1000
11-Oct-2017 00:14:00 17 2 1
11-Oct-2017 00:14:00 19 2 1
11-Oct-2017 00:20:00 5 2 1
11-Oct-2017 01:30:00 25 3 1
11-Oct-2017 01:30:00 18 3 1
11-Oct-2017 03:03:00 28 4 5
2 ответа
Это на самом деле может быть сделано в одной строке кода. Предполагая ваш ValidTo
значение всегда заканчивается непосредственно перед ValidFrom
в следующем ряду (что он делает в вашем примере), вам нужно только использовать ValidFrom
ценности. Во-первых, конвертировать те и ваши RefDate
значения к порядковым номерам дат, используя datenum
, Затем используйте discretize
функция для бин RefDate
значения с использованием ValidFrom
значения как ребра, которые дадут вам индекс строки в B
который содержит каждый раз в A
, Затем используйте этот индекс, чтобы извлечь p1
а также p2
ценности и добавить их к A
:
>> C = [A B(discretize(datenum(A.RefDate), datenum(B.ValidFrom)), 3:end)]
C =
RefDate result p1 p2
______________________ ______ __ __
'11-Oct-2017 00:14:00' 17 2 1
'11-Oct-2017 00:14:00' 19 2 1
'11-Oct-2017 00:20:00' 5 2 1
'11-Oct-2017 01:30:00' 25 3 1
'11-Oct-2017 01:30:00' 18 3 1
'11-Oct-2017 03:03:00' 28 4 5
Вышеупомянутое решение должно работать для любого количества столбцов pN
в B
,
Если есть какие-либо времена в A
которые не попадают ни в один из диапазонов B
вам придется разбить решение на несколько строк, чтобы вы могли проверить, возвращен ли индекс из discretize
содержит NaN
ценности. Предполагая, что вы хотите исключить эти строки из C
, это было бы новым решением:
index = discretize(datenum(A.RefDate), datenum(B.ValidFrom));
C = [A(~isnan(index), :) B(index(~isnan(index)), 3:end)];
Следующий код делает именно то, что вы просите:
% convert to datetime
A.RefDate = datetime(A.RefDate);
B.ValidFrom = datetime(B.ValidFrom);
B.ValidTo = datetime(B.ValidTo);
% for each row in A, find the matching row in B
i = cellfun(@find, arrayfun(@(x) (x >= B.ValidFrom) & (x <= B.ValidTo), A.RefDate, 'UniformOutput', false), 'UniformOutput', false);
% find rows in A that where not matched
j = cellfun(@isempty, i, 'UniformOutput', false);
% build the result
C = [B(cell2mat(i),:) A(~cell2mat(j),:)];
% display output
C