【问题标题】:What is the fastest way to apply a function on each row of a matrix?在矩阵的每一行上应用函数的最快方法是什么?
【发布时间】:2016-09-05 17:51:25
【问题描述】:

到目前为止我已经搜索过,我知道有几种方法(1234)到目前为止我使用了以下代码:

Fv_calc(:,2) = arrayfun(@(n) MaxPositiveRoot2DegreePolynomial(QuadraticCoefficients(n,:)), 1:size(QuadraticCoefficients,1));  

其中 MaxPositiveRoot2DegreePolynomial 是以下函数:

function root = MaxPositiveRoot2DegreePolynomial(c)
    d = c./c(1);
    root = eig([0 -d(3);1 -d(2)]);
    condition = root == abs(root);
    root = root(condition);
    if isempty(root)
        root = 0;
    end
    root = max(root);
end  

其中 QuadraticCoefficients 是一个 62271x3 矩阵,每行包含一般二次方程的系数 abcax^2+bx+c 关于我要解决的问题,所有的根都是真实的,因此我使用了一个修改后的函数来查找根,以免浪费时间检查根是否真实。
通过分析代码,我发现函数 MaxPositiveRoot2DegreePolynomial 的每次运行大约需要 0.000047 秒,对于 62271 次运行大约需要 2.914925371 秒。但是代码

Fv_calc(:,2) = arrayfun(@(n) MaxPositiveRoot2DegreePolynomial(QuadraticCoefficients(n,:)), 1:size(QuadraticCoefficients,1));  

需要 3.198597803 才能运行。所以大约 0.283672431 仅由 arrayfun 占用。我想看看有什么办法可以减少这个时间?

【问题讨论】:

  • 你试过循环吗?虽然arrayfun(及其相关的*fun 系列)非常适合编写紧凑的代码,但它们会增加通常很重要的错误检查开销。基本 for 循环通过 QuadraticCoefficients 的运行时间大约是 R2015b 中 arrayfun 实现的一半。
  • 如果你花费超过 10 分钟尝试优化需要 3 秒的东西,那么你很有可能会花费比运行它更多的时间来优化,除非你正在编写一些东西必须实时运行超优化,在这种情况下,您可能无论如何都不应该使用 Matlab。
  • 你不能只使用二次公式的矢量化版本吗? sqrt 的开销必须比 eig 少。
  • @MatthewGunn 非常好的主意,然后我要写一个问题来帮助我决定是否使用 matlab。
  • @TroyHaskin 实际上我想 MEX gsl_poly_solve_quadratic 并使用它而不是 MaxPositiveRoot2DegreePolynomial。我问这个问题只是为了找到在矩阵的每一行上应用通用函数的最快方法

标签: performance matlab matrix vectorization


【解决方案1】:

这是一个完美的例子,它显示了你应该在哪里继续使用你的循环。我预期的矢量化解决方案最终比您的循环方法慢。

但这可能取决于您的 Matlab 版本,因为我已经在使用 Matlab R2015boptimzed JIT-Compiler,在旧版本中,矢量化方法可能更快。

[n,~] = size(C);
%// division
d = bsxfun(@rdivide,C,C(:,1));
%// create blocks for eigen matrix block procession
X = ( [zeros(n,1) ones(n,1) -d(:,3) -d(:,2)] ).'; %'
Y = reshape(X,2,[]);
%// use block processing to get eigenvalues of blocks
rt = blockproc(Y,[2 2],@(x) eig(x.data) ).'; %'
%// check if eigen values are real positives
condition = rt == abs(rt);
%// output filter
out = rt(condition);

基准测试

function [t] = bench()
    %// load your data
    DATA = load('matlab');
    C = DATA.QuadraticCoefficients;

    % functions to compare
    fcns = {
        @() thewaywewalk(C);
        @() sepideh(C);
    };

    % timeit
    t = zeros(2,1);
    for ii = 1:10;
        t = t + cellfun(@timeit, fcns);
    end
end

function out = thewaywewalk(C)  %thewaywewalk
    [n,~] = size(C);
    d = bsxfun(@rdivide,C,C(:,1));
    X = ( [zeros(n,1) ones(n,1) -d(:,3) -d(:,2)] ).'; %'
    Y = reshape(X,2,[]);
    rt = blockproc(Y,[2 2],@(x) eig(x.data) ).'; %'
    condition = rt == abs(rt);
    out = rt(condition);
end
function out = sepideh(C)  %sepideh
    [n,~] = size(C);
    out = zeros(n,1);
    for ii = 1:n
        c = C(ii,:);
        d = c./c(1);
        rt = eig([0 -d(3);1 -d(2)]);
        condition = rt == abs(rt);
        rt = rt(condition);
        if isempty(rt)
            rt = 0;
        end
        rt = max(rt);
        out(ii) = rt;
    end
end

ans =

    12.2086  %// thewaywewalk
     9.2176  %// sepideh

我仍然没有看到 if 条件的意义。

【讨论】:

  • 我已经为你上传了那个数组link
  • 事实上我正在为我的特殊问题做更多的实验。而且我还没有使用你的代码。但总的来说,如果你的答案比我的快。我暂时接受了
猜你喜欢
  • 2012-07-12
  • 2016-02-06
  • 2021-01-15
  • 2012-11-30
  • 1970-01-01
  • 2018-09-21
  • 1970-01-01
  • 2013-05-20
相关资源
最近更新 更多