使用varfun进行分组的最大值索引

时间:2015-02-09 21:18:14

标签: matlab sorting matlab-table

我有一张包含Ids和Dates的表格。我想检索每个Id的最大日期索引。

我最初的做法是这样的: varfun(@ max,table,'Grouping Variables','Id','InputVariables','Date');

这显然给了我日期而不是索引。 我注意到max函数将在指定时返回maxvalue和maxindex: [max_val,max_idx] = max(values);

如何使用max定义匿名函数来检索max_idx?然后我会在var_fun中使用它来获取我的结果。

我不想在max()上声明一个封面函数(而不是anon func): 我正在使用脚本而不想创建另一个函数文件 2.我不愿意将当前脚本更改为函数

感谢一百万人,

2 个答案:

答案 0 :(得分:3)

我假设你的 ID是正整数而你的日期是数字

如果您想要每个ID的最大日期,那么accumarray具有max功能将是一个完美的案例。在下文中,我将使用f来表示传递给accumarray的泛型函数。

你想要索引的最大值使它变得有点棘手(而且更有趣!)。问题是对应于给定Id的日期将传递给f,而不会引用其原始索引。因此,基于f的{​​{1}}无法提供帮助。但您可以将索引“通过”max作为日期的虚部

所以:如果你想要每个Id只有一个最大化索引(即使有几个):

accumarray

请注意,此处的函数result = accumarray(t.Id,... %// col vector of Id's t.Date+1j*(1:size(t,1)).', ... %'// col vector of Dates (real) and indices (imag) [], ... %// default size for output @(x) imag(x(find(real(x)==max(real(x))),1))); %// function f 最大化 real 部分,然后提取虚构部分,其中包含原始索引。

或者,如果您希望所有最大化每个Id的索引:

f

如果您的 ID是字符串:使用unique的第三个输出将它们转换为数字标签,然后按上述步骤操作:

result = accumarray(t.Id,...  %// col vector of Id's
    t.Date+1j*(1:size(t,1)).', ... %'// col vector of Dates (real) and indices (imag)
    [], ... %// default size for output
    @(x) {imag(x(find(real(x)==max(real(x)))))}); %// function f

然后

[~, ~, NumId] = unique(t.Id);

result = accumarray(NumId,...  %// col vector of Id's
    t.Date+1j*(1:size(t,1)).', ... %'// col vector of Dates (real) and indices (imag)
    [], ... %// default size for output
    @(x) imag(x(find(real(x)==max(real(x))),1))); % function f

答案 1 :(得分:2)

我认为varfun是正确的方法,因为

  

varfun(func,A)将函数func分别应用于每个变量       表A

如果您想将其应用于多个列,这只会有意义。

简单方法:

简单地使用循环方法:首先使用unique查找不同的ID,然后为每个ID找到最大日期的索引。 (这假设您的日期采用数字格式,可以使用max直接比较。) 我确实将变量table重命名为t,否则我们将覆盖内置函数table

uniqueIds = unique(t.Id);
for i = 1:numel(uniqueIds)
    equalsCurrentId = t.Id==uniqueIds(i); 
    globalIdxs = find(equalsCurrentId);
    [~, localIdxsOfMax] = max(t.Date(equalsCurrentId));
    maxIdxs{i} = globalIdxs(localIdxsOfMax);
end

正如您所提到的,Ids实际上是字符串而不是数字,您必须更改行:equalsCurrentId = t.Id==uniqueIds(i);

 equalsCurrentId = strcmp(t.Id, uniqueIds{i});

使用accumarray的方法:

如果您更喜欢更紧凑的风格,可以使用受Luis Mendo's answer启发的此解决方案,该解决方案适用于数字和字符串ID:

[uniqueIds, ~, global2Unique] = unique(t.Id);
maxDateIdxsOfIdxSubset = @(I) {I(nth_output(2, @max, t.Date(I)))};
maxIdxs = accumarray(global2Unique, 1:length(t.Id), [], maxDateIdxsOfIdxSubset);

这使用 gnovice nth_output great answer

用法:

以上两种解决方案都会产生:带有对应uniqueIds - 数组cell的向量maxIdxs,其中maxIdxs{i}uniqueIds(i)的最大日期的索引{1}}。 如果您只需要一个索引,即使有多个条目达到最大值,请使用以下内容删除不需要的数据:

maxIdxs = cellfun(@(X) X(1), maxIdxs);