倍频程组统计计算,累加数组和用户定义函数返回第三列的值



需要明确的是,以下内容不是我的原始问题,它的数据要大得多,并且此代码位于更大的应用程序和代码库中。 我已经将我的工作简化为最简单的示例,现在该示例具有玩具或教学大小,以便清晰,开发和单元测试,因为这对这些目的以及在stackexchange上共享有很大帮助。我在R方面经验丰富,但在八度(Matlab)方面没有经验。这是八度版本 4.0.0 的代码。我似乎坚持翻译组计算,如R的tapply()或by(),以及编写和调用用户定义的函数(加上一些比内置函数更多的处理),但现在是用八度语言编写的。

起始状态是一个数组 a,如下所示:

a = [5 1 8 0; 2 1 9 0; 2 3 3 0; 5 3 9 0]
a =
5   1   8   0
2   1   9   0
2   3   3   0
5   3   9   0

我需要做的过程基本上是这样的:按第 1 列分组,在第 3 列中找到最小统计数据,返回存储在同一行的第 2 列中的值,并将值写入第 4 列。 我不想使用任何可选包。内置的累加数组和 min 函数一起让我非常接近,但我还没有找到所需的语法。Matlab 似乎在不同版本上开发了许多版本的参数传递语法,请注意我的代码需要在 Octave 4.0.0 中运行。

所需的最终状态是相同的数组 a,但第 4 列已更新,如下所示:

a =
5   1   8   1
2   1   9   3
2   3   3   3
5   3   9   1

在所有失败的尝试中,我最好的几个差点失误和最有趣的事情的代码片段(未显示,因为有很多页面的尝试不起作用)是:

[x,y] = min(a(a(:,1)==5,3),[],1)
x =  8
y =  1

请注意,y 是组中行的索引,但不是 a 数组中的行,只要我稍后进行计算以将索引从组相对转换为全局相对,并在其中读取 a(y,2) 的值,这是每行的正确答案值。

>> [x,y] = min(a(a(:,1)==2,3),[],1)
x =  3
y =  2
>> [~,y] = min(a(a(:,1)==2,3),[],1);
>> y
y =  2

请注意,y 是我从 min() 中所需要的,因为它是感兴趣行的索引。

>> accumarray(a(:,1), a(:,3), [], @([~,y]=min([],[],1)))
parse error:
syntax error

请注意,使用某种语法,我需要将累加数组的参数 1 和 2 确定的值组传递给其第一个参数中的 min()。

我最终需要在 min() 返回行索引 y 后的组计算中发生这样的事情:

a(y,4) = a(y,2); % y is the desired row index found by min() within each group

因此,我尝试编写一个以可能更简单的语法命名的函数:

>> function idx = ccen(d)
[~,y]=min(d,[],1);
idx=a(y,2);
end
>> accumarray(a(:,1), a(:,3), [], @ccen)
error: 'a' undefined near line 3 column 5
error: called from
ccen at line 3 column 4
accumarray at line 345 column 14

在我看来,令我惊讶的是,一个无法访问功能 ccen。现在我该怎么办?感谢您的阅读。

在 MATLAB/Octave 中声明函数时,在作用域之外声明的任何变量(默认情况下)都不可访问。 这意味着即使您有 a 的声明,当您创建该函数时,a 也无法在该函数范围内访问。

您可以做的是修改ccen以便将a提供给函数,以便在调用函数时可以访问变量。 之后,在调用accumarray时围绕对ccen的调用包装一个匿名函数。 但是,匿名函数确实可以捕获未显式声明为函数输入变量的变量的范围:

所以首先:

function idx = ccen(a, d) %// Change
    [~,y]=min(d,[],1);
    idx=a(y,2);
end

现在。。。

out = accumarray(a(:,1), a(:,3), [], @(x) ccen(a,x)); %// Change last parameter

此调用是可以接受的,因为匿名函数在创建时捕获a。 请注意匿名函数中的x是如何从accumarray调用中传入的内容。 您只需将其作为第二个参数转发给ccen并保持a不变。 这不会改变函数的运行方式。它只是解决范围问题。

我在八度中得到以下内容:

octave:10> a = [5 1 8 0; 2 1 9 0; 2 3 3 0; 5 3 9 0]
a =
   5   1   8   0
   2   1   9   0
   2   3   3   0
   5   3   9   0
octave:11> function idx = ccen(a,d)
> [~,y]=min(d,[],1);
> idx=a(y,2);
> end
octave:12> out = accumarray(a(:,1), a(:,3), [], @(x) ccen(a,x))
out =
   0
   1
   0
   0
   1

最新更新