你最喜欢的MATLAB/Octave编程技巧是什么?

73

我认为每个人都会同意,MATLAB语言并不美观,也不特别一致。但没关系!我们仍然必须使用它来完成任务。

您有哪些使事情变得更容易的技巧?让我们每个回答提供一个技巧,以便人们可以投票支持他们。此外,请尝试用示例说明您的答案。

31个回答

39

使用内置分析器查看代码中的热点部分:

profile on
% some lines of code
profile off
profile viewer

或者只需使用内置的tictoc来快速获取时间:

tic;
% some lines of code
toc;

31

使用逻辑数组直接提取满足特定条件的矩阵元素:

x = rand(1,50) .* 100;
xpart = x( x > 20 & x < 35);

现在xpart只包含那些落在指定范围内的x元素。


在Matlab中,您可以使用函数“find”基本上完成相同的操作。 - devin
10
但是查找速度非常慢。逻辑索引要快得多,除非你需要知道匹配项的索引。 - Marc

28

在帮助文档中添加“SEE ALSO”行,可以快速访问其他函数的文档。首先,您必须在所有大写字母作为第一条注释行中包含函数名称。执行通常的注释头部处理,然后使用逗号分隔的其他相关函数列表来放置“SEE ALSO”。

function y = transmog(x)
%TRANSMOG Transmogrifies a matrix X using reverse orthogonal eigenvectors
%
% Usage:
%   y = transmog(x)
%
% SEE ALSO
% UNTRANSMOG, TRANSMOG2
当您在命令行中键入“help transmog”时,您将看到此注释头中的所有注释,并带有其他列出功能的注释标题的超链接。

23

使用单个冒号将矩阵转换为向量。

x = rand(4,4);
x(:)

1
如何对子矩阵进行操作? 假设: x = rand(20, 20); 我想将 x(1:10, 1:10) 转换为向量。y=reshape(x(:10, 1:10), [], 1) 或 y=x(1:10, 1:10)-> y=y(:) 是我的唯一选择吗?不用说,x(1:10, 1:10)(:) 是行不通的。 - Royi
@Drazick,您可以使用多维索引或单维索引来访问x的元素。myElems = [1:10 21:30 31:40...181:190]; y = x(myElems); - Scottie T
假设我有一张图片-I。要计算它的方差,我会这样做:var(I(:))。 如果我想计算其中一部分的方差-I(1:20, 1:20)。 var(var(I(1:20, 1:20))不行(是错误的)。 我知道的选项是y = I(1:20, 1:20) -> var(y(:))或y=reshape(I(1:20, 1:20), [], 1) -> var(y(:))。我的问题是是否有一种方法可以在不重新分配矩阵的情况下对矩阵的子矩阵应用冒号运算符? 谢谢。 - Royi
@Drazick:你应该把那个作为一个单独的问题。另外,也许sub2ind可以帮助。 - Tobias Kienzler
@Drazick:feval(@(x) x(:), x(1:3,1:3)) - Szymon Bęczkowski

22

向量化循环。有很多方法可以实现,寻找代码中的循环并思考如何将其向量化是一件有趣的事情。使用向量操作可以让性能惊人地提高!


现在Matlab有JIT编译器,这种情况还存在吗?看起来很有趣。 - Matt

20

匿名函数有几个原因:

  1. 可以快速创建一次性使用的函数,例如3x^2+2x+7(见下面的代码)。这对于像quadfminbnd这样需要将函数作为参数传递的函数非常有用。在脚本中(不带函数头的.m文件)也很方便,因为与真正的函数不同,您无法包含子函数。
  2. 用于闭包 - 尽管匿名函数有点受限制,因为似乎没有办法在其中进行赋值以改变状态。

.

% quick functions
f = @(x) 3*x.^2 + 2*x + 7;
t = (0:0.001:1);
plot(t,f(t),t,f(2*t),t,f(3*t));

% closures (linfunc below is a function that returns a function,
% and the outer functions arguments are held for the lifetime
% of the returned function.
linfunc = @(m,b) @(x) m*x+b;
C2F = linfunc(9/5, 32);
F2C = linfunc(5/9, -32*5/9);

关于在脚本中使用的观点很好! - lightw8
第四行末尾缺少一个 ')'。 - petrichor
感谢您的解释...我仍然对这种语言中所有这些荒谬的限制感到惊讶。 - Michael
Octave允许进行内联赋值,我认为这解决了你的第二个问题。 - Griffin

19

Matlab的bsxfun, arrayfun, cellfunstructfun非常有趣,通常可以避免使用循环。

M = rand(1000, 1000);
v = rand(1000,    1);
c = bsxfun(@plus, M, v);

例如,此代码将向矩阵M的每列添加列向量v。

但是,在应用程序的性能关键部分中,您应该将这些函数与普通for循环进行基准测试,因为循环通常更快。


18

图表中公式的 LaTeX 模式:在最近的一个版本(R2006?)中,您可以在函数调用末尾添加额外参数,'Interpreter','latex'以使用 LaTeX 渲染。以下是一个示例:

t=(0:0.001:1);
plot(t,sin(2*pi*[t ; t+0.25]));
xlabel('t'); 
ylabel('$\hat{y}_k=sin 2\pi (t+{k \over 4})$','Interpreter','latex');
legend({'$\hat{y}_0$','$\hat{y}_1$'},'Interpreter','latex');

我不确定什么时候添加的,但它可以在text()、title()、xlabel()、ylabel()、zlabel()甚至是legend()函数中使用。只需确保你使用的语法不会产生歧义(因此在legend()中需要将字符串指定为单元数组)。


Matlab会抛出一个错误,因为传递给“plot”命令的向量长度不同。我猜你是想画两条线,对吧?你需要在传递给plot命令的矩阵中加上一个分号,这样Matlab就知道它是两个不同的序列了,例如:plot(t,sin(2*pi*[t; t+0.25])); - Ricardo Altamirano

17

使用xlim和ylim绘制垂直和水平线,示例:

  1. 在y=10处绘制一条水平线:

    line(xlim, [10 10])

  2. 在x=5处绘制一条垂直线:

    line([5 5], ylim)


1
这并不总是有效的。限制并非实时更新。在这种情况下,调用 drawnow 将强制更新它们。 - Memming

16

以下是一个快速示例:

我发现逗号分隔列表语法非常有用,可以用于构建函数调用:

% Build a list of args, like so:
args = {'a', 1, 'b', 2};
% Then expand this into arguments:
output = func(args{:})

1
不确定MATLAB是否支持,但在Octave中,您可以以类似的方式为多个变量分配值:[one two three four] = {1 2 3 4}{:} - Griffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接