Matlab单元格字符串数组:查找重复的字符串并操纵相应的数据

use*_*166 4 string matlab unique-index cell-array

我有一大组数据(约100万个条目),存储为具有多列和多行的单元格.我的问题是我需要识别同时发生的条目,然后操纵其他列,以便删除重复日期的行而不会丢失所有信息.

可以如此初始化这种数据的子集的示例;

data = {'10:30', 100; '10:30', 110; '10:31', 115;'10:32', 110}
Run Code Online (Sandbox Code Playgroud)

也就是说,我有一个带有一列字符串(表示时间)的单元格,以及另一列(实际数据中有很多)的双精度单元格.

我的代码应该注意重复的10:30(可能有很多这样的重复),然后能够接受相应的双精度(100和110)作为某些函数的输入f(100,110),然后从中删除重复的行数据.

也就是说,如果函数是平均值,那么我应该有一个类似的输出

data =
       '10:30' [105]
       '10:31' [115]
       '10:32' [110]
Run Code Online (Sandbox Code Playgroud)

如果循环足够快,这将非常简单,但是对于我的数据集,即使尝试涉及循环的解决方案也没有意义.

我已经到了

[uniqueElements, firstUniquePosition, commonSets] = unique(data(:,1));
Run Code Online (Sandbox Code Playgroud)

经过多次摆弄后,会产生一些看似有用的信息,

uniqueElements = 

    '10:30'
    '10:31'
    '10:32'

firstUniquePosition =

     1
     3
     4

commonSets =

     1
     1
     2
     3
Run Code Online (Sandbox Code Playgroud)

但我无法弄清楚如何制作一个矢量化语句,允许我操纵具有常见日期的元素.

我想它会涉及cellfun某些方面,但我不知道matlab的功能是否足以实现它而没有朝着正确的方向发展.

the*_*alk 5

这是一份工作accumarray:

[times,~,subs] = unique(data(:,1));
idx = 1:size(data,1);
meanOfCommonTimes = accumarray(subs(:),idx(:),[],@(x) mean( [data{x,2}] ))

output = [times num2cell(meanOfCommonTimes)]
Run Code Online (Sandbox Code Playgroud)
output = 

    '10:30'    [105]
    '10:31'    [115]
    '10:32'    [110]
Run Code Online (Sandbox Code Playgroud)

谈论100万个元素和性能:考虑使用datenum函数将时间数据存储为数值.

times = datenum(data(:,1),'hh:mm');
Run Code Online (Sandbox Code Playgroud)

并将数据保存在双数组中:

vals = cell2mat(data(:,2));
Run Code Online (Sandbox Code Playgroud)

然后计算速度提高10倍!

[~,~, subs] = unique(times);
meanOfCommonTimes = accumarray(subs(:),vals(:),[],@mean);
Run Code Online (Sandbox Code Playgroud)

但请注意.转换也需要相当长的时间.如果你稍后进行了很多计算,那就可以了.


基准

function [t] = bench()
    data = {'10:30', 100; '10:30', 110; '10:31', 115;'10:32', 110};
    data = [repmat(data, 200000, 1)]; % I use a matrix rather than a cell array for the simplicity of randomly generating example data

    % functions to compare
    fcns = {
        @() thewaywewalk(data);
        @() Cecilia(data);
    };

    thewayw = timeit(fcns{1})
    Ceci = timeit(fcns{2})
end

function Z = Cecilia(data)
    [uniqueElements, ~, commonSets] = unique(data(:,1));

    num_unique = length(uniqueElements);
    Z = zeros(num_unique, 1);
    for ii = 1:num_unique
        Z(ii) = mean([data{commonSets==ii, 2}]);
    end
end
function Z = thewaywewalk(data)
    [~,~,subs] = unique(data(:,1));
    idx = 1:size(data,1);
    Z = accumarray(subs(:),idx(:),[],@(x) mean( [data{x,2}] ));
end
Run Code Online (Sandbox Code Playgroud)

对于具有800000行的数组,结果几乎相等.

thewayw =  1.1483
Ceci = 1.0957
Run Code Online (Sandbox Code Playgroud)

但同样,accumarray之前转换为双倍会有很大的利润,但在这种情况下,循环的性能应该保持不变.