【问题标题】:How to join tables in Matlab (2018) by matching time intervals?如何通过匹配时间间隔在 Matlab (2018) 中加入表格?
【发布时间】:2023-03-19 21:17:01
【问题描述】:

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

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

【问题讨论】:

    标签: matlab timestamp time-series data-mining matlab-table


    【解决方案1】:

    这实际上可以在一行代码中完成。假设您的 ValidTo 值总是在下一行的 ValidFrom 之前结束(在您的示例中就是这样),您只需要使用您的 ValidFrom 值。首先,使用datenum 将这些和您的RefDate 值转换为序列号。然后使用discretize 函数将RefDate 值合并为边缘,使用ValidFrom 值作为边缘,这将为您提供B 中的行索引,其中包含A 中的每次时间。然后使用该索引提取p1p2 值并将它们附加到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 
    

    上述解决方案应该适用于B 中任意数量的列pN

    如果A 中的任何时间不属于B 中的任何范围,则必须将解决方案分成多行,以便检查索引是否从@987654341 返回@ 包含 NaN 值。假设您想从 C 中排除这些行,这将是新的解决方案:

    index = discretize(datenum(A.RefDate), datenum(B.ValidFrom));
    C = [A(~isnan(index), :) B(index(~isnan(index)), 3:end)];
    

    【讨论】:

    • 如果A 中的RefDateB 中找不到匹配项,则上述(不错的)代码将失败。
    • 非常感谢您的回答。我什至没有想到datenum。一旦我发现了 NaN 问题,这就奏效了。我现在看到的也已经被你解决了。你的修复比我想出的要优雅得多。
    【解决方案2】:

    以下代码完全符合您的要求:

    % 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
    

    【讨论】:

    • 谢谢。这有一些方面可以改进我目前的方法,但是有数百个 p1,p2 列,所以单独的方法是行不通的。
    • 希望这可以帮助(R2018b):https://it.mathworks.com/help/matlab/ref/outerjoin.html
    • 我查看了文档。但是我还没有找到像 SQL 中的 ON 那样工作的东西。在 SQL 中,我可以更详细地指定键。我正在寻找类似的东西。这可能是 Matlab 中不存在的。
    • @Schae:我明白你的意思。即使我没有找到加入两个表的“本机”解决方案,我也更新了我的代码以更一般的方式解决您的问题:现在唯一的强制性列是 A.RefDateB.ValidFromB.ValidTo。跨度>
    猜你喜欢
    • 2021-02-18
    • 2011-05-07
    • 2012-08-11
    • 2014-02-09
    • 1970-01-01
    • 2021-03-25
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多