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

我想每个人都会同意 MATLAB 语言并不漂亮,或者说不是特别一致。不过没关系!我们还是得用它来完成任务。

你最喜欢的让事情变得简单的技巧是什么?让我们每个答案一个,这样人们可以投票,如果他们同意。另外,试着用一个例子来说明你的答案。

32314 次浏览

这里有一个简单的例子:

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

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

从 Matlab 调用 Java 代码

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

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

通过在帮助评论中添加“请参阅”一行,提供对其他功能文档的快速访问。首先,必须将函数的名称包含在所有大写字母中,作为第一个注释行。做你通常的评论标题的东西,然后把看到也与逗号分隔列表的其他相关功能。

function y = transmog(x)
%TRANSMOG Transmogrifies a matrix X using reverse orthogonal eigenvectors
%
% Usage:
%   y = transmog(x)
%
% SEE ALSO
% UNTRANSMOG, TRANSMOG2

当您在命令行输入“ help transmog”时,您将看到此注释标头中的所有注释,其中包含列出的其他函数的注释标头的超链接。

Cellfun 和 arrayfun 用于自动的 for 循环。

用于操作数组的冒号运算符。

@ ScottieT812提到了一个: 压平一个数组,但是还有其他所有选择数组位的变体:


x=rand(10,10);
flattened=x(:);
Acolumn=x(:,10);
Arow=x(10,:);


y=rand(100);
firstSix=y(1:6);
lastSix=y(end-5:end);
alternate=y(1:2:end);

使用 nargin 设置可选参数的默认值,并使用 nargout 设置可选输出参数

function hLine=myplot(x,y,plotColor,markerType)
% set defaults for optional paramters
if nargin<4, markerType='none'; end
if nargin<3, plotColor='k'; end


hL = plot(x,y,'linetype','-', ...
'color',plotColor, ...
'marker',markerType, ...
'markerFaceColor',plotColor,'markerEdgeColor',plotColor);


% return handle of plot object if required
if nargout>0, hLine = hL; end

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

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

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

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

profile on
% some lines of code
profile off
profile viewer

或者仅仅使用内置的 tictoc来获得快速计时:

tic;
% some lines of code
toc;

使用 ismember ()合并由文本标识符组织的数据。当你分析不同时期的条目时很有用,在我的例子中是公司符号,来来去去。

%Merge B into A based on Text identifiers
UniverseA = {'A','B','C','D'};
UniverseB = {'A','C','D'};


DataA = [20 40 60 80];
DataB = [30 50 70];


MergeData = NaN(length(UniverseA),2);


MergeData(:,1) = DataA;


[tf, loc] = ismember(UniverseA, UniverseB);


MergeData(tf,2) = DataB(loc(tf));


MergeData =


20    30
40   NaN
60    50
80    70

还有逆转数组

v = 1:10;
v_reverse = v(length(v):-1:1);

矢量化:

function iNeedle = findClosest(hay,needle)
%FINDCLOSEST find the indicies of the closest elements in an array.
% Given two vectors [A,B], findClosest will find the indicies of the values
% in vector A closest to the values in vector B.
[hay iOrgHay] = sort(hay(:)');  %#ok must have row vector


% Use histogram to find indices of elements in hay closest to elements in
% needle. The bins are centered on values in hay, with the edges on the
% midpoint between elements.
[iNeedle iNeedle] = histc(needle,[-inf hay+[diff(hay)/2 inf]]); %#ok


% Reversing the sorting.
iNeedle = iOrgHay(iNeedle);

下面是一些时不时有用的非显而易见的函数:

  • mfilename(返回当前运行的 MATLAB 脚本的名称)
  • dbstack(允许您访问 matlab 函数堆栈的名称和行号)
  • (停止执行并将控制权交给调试提示符; 这就是为什么在调试提示符 K>>中有一个 K
  • dbstop error(自动将您置于在触发错误的行处停止的调试模式)

图中公式的 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 ()函数中使用 R2006b。只要确保您正在使用的语法不是模棱两可的(因此,对于 Legend () ,您需要将字符串指定为单元格数组)。

使用 sim命令直接从脚本(而非交互式)执行 Simulink 模型。您可以从工作区变量获取参数,并在循环中重复运行 sim来模拟某些事情,同时改变参数以查看行为如何变化,并使用您喜欢的任何图形命令将结果绘制成图形。这比尝试以交互方式完成要容易得多,而且在可视化结果时,它比 Simulink 的“示波器”块提供了更多的灵活性。(尽管在模拟运行时,你不能使用它来实时看到发生了什么)

需要知道的一件非常重要的事情是 simset命令的 DstWorkspaceSrcWorkspace选项。这些模块控制“ To Workspace”和“ From Workspace”块从何处获取并放置它们的结果。Dstworkspace默认为当前工作区(例如,如果你从一个函数内部调用 sim,“ To Workspace”块将显示为可从同一个函数内部访问的变量) ,但是 SrcWorkspace默认为基础工作区,如果你想封装对 sim的调用,你需要将 SrcWorkspace设置为 current,这样就有了一个干净的界面来提供/检索模拟输入参数和输出。例如:

function Y=run_my_sim(t,input1,params)
% runs "my_sim.mdl"
% with a From Workspace block referencing I1 as an input signal
% and parameters referenced as fields of the "params" structure
% and output retrieved from a To Workspace block with name O1.
opt = simset('SrcWorkspace','current','DstWorkspace','current');
I1 = struct('time',t,'signals',struct('values',input1,'dimensions',1));
Y = struct;
Y.t = sim('my_sim',t,opt);
Y.output1 = O1.signals.values;

[c,h]=contourclabel(c,h,'fontsize',fontsize)绘制等高线图。我通常使用 fontsize参数来减小字体大小,这样数字就不会相互碰撞。这对于查看2-D 函数的值而不必使用3D 图形非常有用。

匿名函数,原因如下:

  1. 为一次性使用创建一个快速函数,比如3x ^ 2 + 2 x + 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);

赋值函数左边的条件参数:

t = (0:0.005:10)';
x = sin(2*pi*t);
x(x>0.5 & t<5) = 0.5;
% This limits all values of x to a maximum of 0.5, where t<5
plot(t,x);

我喜欢使用函数句柄有很多原因。首先,它们是我在 MATLAB 中发现的最接近指针的东西,因此您可以为对象创建类似引用的行为。你也可以用它们做一些简单的事情。例如,替换 switch 语句:

switch number,
case 1,
outargs = fcn1(inargs);
case 2,
outargs = fcn2(inargs);
...
end
%
%can be turned into
%
fcnArray = {@fcn1, @fcn2, ...};
outargs = fcnArray{number}(inargs);

我只是觉得这样的小事很酷。

了解你的 轴特性!您可以设置各种各样的东西来调整默认的绘图属性,从而达到您想要的效果:

set(gca,'fontsize',8,'linestyleorder','-','linewidth',0.3,'xtick',1:2:9);

(例如,将字体大小设置为8 pt,所有新行的行样式都为实线,宽度为0.3 pt,xtick 点为[13579])

Line 图表属性也很有用,但我发现自己使用坐标轴属性最多。

Matlab 的 Bsxfun阵列乐趣牢房乐趣Structfun非常有趣,通常会保存一个循环。

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

例如,这段代码将列向量 v 添加到矩阵 M 的每一列。

尽管如此,在应用程序的性能关键部分,您应该对这些函数进行基准测试,而不是使用普通的 for 循环,因为通常循环的速度更快。

在使用像 min、 max、 mean、 diff、 sum、 any、 all 这样的聚合函数时,要严格指定维数。

例如:

reldiff = diff(a) ./ a(1:end-1)

也许可以很好地计算向量中元素的相对差异,但是如果向量退化到只有一个元素,计算就会失败:

>> a=rand(1,7);
>> diff(a) ./ a(1:end-1)


ans =
-0.5822   -0.9935  224.2015    0.2708   -0.3328    0.0458


>> a=1;
>> diff(a) ./ a(1:end-1)
??? Error using ==> rdivide
Matrix dimensions must agree.

如果您为函数指定了正确的尺寸,这一行将返回一个空的1 × 0矩阵,这是正确的:

>> diff(a, [], 2) ./ a(1, 1:end-1)


ans =


Empty matrix: 1-by-0


>>

同样的道理也适用于最小函数,它通常计算矩阵上列的最小值,直到矩阵只包含一行为止。- 然后它将返回该行上的最小值,除非维度参数另有说明,并可能中断您的应用程序。

我几乎可以保证,随后设置这些聚合函数的维度将为您稍后节省相当多的调试工作。

至少对我来说是这样的。 :)

令我惊讶的是,当人们提到索引数组的逻辑数组方法时,却没有人提到 find 命令。

例如,如果 x 是一个 NxMxO 数组

X (x > 20)的工作原理是生成一个 NxMxO 逻辑数组并使用它来索引 x (如果数组很大并且正在寻找一个小的子集,那么索引 x 会很糟糕

X (find (x > 20))的工作原理是生成满足 x > 20的 x 的索引的列表(即1xwhatever) ,然后根据它对 x 进行索引。根据我的经验,“ find”应该比实际使用的更多。

我更愿意称之为“把戏”

如果你不知道数组和单元格数组的大小,你可以使用 end + 1来增长/附加数组和单元格数组(只要切片的尺寸匹配,也可以使用更高的尺寸——所以在这种情况下,你必须将 x 初始化为[]以外的东西)。不适用于数字,但适用于小的动态列表(或单元格数组) ,例如解析文件。

例如:。

>> x=[1,2,3]
x =  1     2     3
>> x(end+1)=4
x =  1     2     3     4

另一个许多人不知道的是,for 对于任何 dim 1数组都是有效的,所以我们继续这个例子

>> for n = x;disp(n);end
1
2
3
4

这意味着如果只需要 x 的成员,就不需要对它们进行索引。

这种方法也适用于单元格数组,但是有点烦人,因为在它们行走时,元素仍然包装在单元格中:

>> for el = {1,2,3,4};disp(el);end
[1]
[2]
[3]
[4]

所以要得到元素,你必须给它们下标

>> for el = {1,2,3,4};disp(el{1});end
1
2
3
4

我不记得还有比这更好的办法了。

- 你可以创建一个 Matlab 快捷方式到一个名为 startup.m 的初始化文件。在这里,我为 Matlab 会话定义了格式、输出的精度和绘图参数(例如,我使用较大的绘图轴/字体大小,以便。当我把它们放在演示文稿中时,就可以清楚地看到无花果。)看到一个好的博客文章从一个开发人员关于它 http://blogs.mathworks.com/loren/2009/03/03/whats-in-your-startupm/

你可以使用“ load”函数加载整个数字 ASCII 文件。这并不是特别快,但可以快速完成原型的工作(这难道不应该是 Matlab 的座右铭吗?)

- 如前所述,结肠操作和矢量化是救命稻草。螺丝循环。

使用 xlim 和 ylim 绘制垂直和水平线。例如:

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

    line(xlim, [10 10])

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

    line([5 5], ylim)

为了能够快速测试一个函数,我使用 nargin如下:

function result = multiply(a, b)
if nargin == 0 %no inputs provided, run using defaults for a and b
clc;
disp('RUNNING IN TEST MODE')
a = 1;
b = 2;
end


result = a*b;

稍后,我将添加一个单元测试脚本来测试函数的不同输入条件。

X = repmat ([1:10] ,3,1) ;% say,x 是一个示例数组数据

L = x > = 3;% 1是一个逻辑向量(1s/0s) ,用于突出显示数组中满足某个条件的元素。

N = sum (sum (l)) ;% N 是满足给定条件的元素数。

干杯,脚本快乐!

询问“为什么”(有助于让我在凌晨3点从 Matlab 运行时调试的恍惚状态中清醒过来... ...)

运行在线算法时使用 persistent(静态)变量。它可以加快贝叶斯机器学习等领域的代码,在这些领域中,模型为新样本进行迭代训练。例如,为了计算独立的对数可能性,我首先从头计算对数可能性,然后通过将先前计算的对数可能性和附加的对数可能性相加来更新它。

与其给出一个更专业的机器学习问题,不如让我给出一个一般的在线平均代码,我采用的是 从这里:

function av = runningAverage(x)
% The number of values entered so far - declared persistent.
persistent n;
% The sum of values entered so far - declared persistent.
persistent sumOfX;
if x == 'reset' % Initialise the persistent variables.
n = 0;
sumOfX = 0;
av = 0;
else % A data value has been added.
n = n + 1;
sumOfX = sumOfX + x;
av = sumOfX / n; % Update the running average.
end

然后,调用将给出以下结果

runningAverage('reset')
ans = 0
>> runningAverage(5)
ans = 5
>> runningAverage(10)
ans = 7.5000
>> runningAverage(3)
ans = 6
>> runningAverage('reset')
ans = 0
>> runningAverage(8)
ans = 8

以下是我经常使用的方法:

% 有用的缩写

flat=@(x) x(:);


% print basic statistics
stats=@(x) sprintf('mean +/- s.d. \t= %f +/- %f\nmin, max \t\t= %f, %f\nmedian, mode \t= %f, %f', ...
mean(flat(x)), std(flat(x)), min(flat(x)), max(flat(x)), median(flat(x)), mode(flat(x)) );


nrows=@(x) size(x,1);
ncols=@(x) size(x,2);
nslices=@(x) size(x,3);


% this is just like ndims except it returns 0 for an empty matrix and
% ignores dimensions of size 0.
ndim=@(x) length(find(size(x)));

这些缩写对于查找图像小区域中像素值的平均值和标准差非常有用。我会用以下逻辑:

PhantomData = Phantom () ;

stats( phantomData(50:80, 50:80) )

如果我想在标题中放入一个图像的大小,该怎么办?

(phantomData) ;

title( sprintf('The image size is %d by %d by %d.', nrows(phantomData), ncols(phantomData), nslices(phantomData)) )