如何通过匹配时间间隔在 Matlab (2018) 中连接表?



我有两个表A和B。我想根据它们的有效时间间隔加入它们。

A 具有产品质量(不规则时间(,B 在生产期间具有每小时设置。我需要创建一个像 C 这样的表,其中包含所有 A 的 RefDate 的参数 p1 和 p2,这些参数属于 B 的 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

这实际上可以在一行代码中完成。假设您的ValidTo值总是在下一行的ValidFrom之前结束(在您的示例中确实如此(,您只需要使用ValidFrom值。首先,使用datenum将这些值和您的RefDate值转换为序列号。然后使用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 

上述解决方案应该适用于BpN的任意数量的列。

如果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

最新更新