我想每个人都会同意 MATLAB 语言不漂亮,或者特别一致。但是没关系!我们仍然必须使用它来完成工作。
你最喜欢的让事情变得更简单的技巧是什么?让我们每个答案都有一个,这样人们可以在他们同意的情况下投票。另外,试着用一个例子来说明你的答案。
使用内置分析器查看我的代码的热门部分在哪里:
profile on
% some lines of code
profile off
profile viewer
或仅使用内置tic
并toc
获得快速计时:
tic;
% some lines of code
toc;
使用逻辑数组直接提取矩阵中满足特定条件的元素:
x = rand(1,50) .* 100;
xpart = x( x > 20 & x < 35);
现在 xpart 仅包含 x 中位于指定范围内的那些元素。
通过在帮助注释中添加“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”时,您将在此注释标题中看到所有注释,并带有指向列出的其他功能的注释标题的超链接。
使用单个冒号将矩阵转换为向量。
x = rand(4,4);
x(:)
向量化循环。有很多方法可以做到这一点,在你的代码中寻找循环并看看它们如何被向量化是很有趣的。向量运算的性能惊人地快!
匿名函数,原因如下:
quad
和fminbnd
以函数作为参数的函数很有用。它在脚本(不以函数头开头的.m 文件)中也很方便,因为与真正的函数不同,您不能包含子函数。.
% 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);
图形中公式的 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(),您需要将字符串指定为元胞数组)。
使用 xlim 和 ylim 绘制垂直和水平线。例子:
在 y=10 处画一条水平线:
line(xlim, [10 10])
在 x=5 处绘制垂直线:
line([5 5], ylim)
这是一个简单的例子:
我发现逗号分隔的列表语法对于构建函数调用非常有用:
% Build a list of args, like so:
args = {'a', 1, 'b', 2};
% Then expand this into arguments:
output = func(args{:})
这里有一堆不时有用的非显而易见的函数:
mfilename
(返回当前运行的 MATLAB 脚本的名称)dbstack
(让您可以访问 matlab 函数堆栈的名称和行号)keyboard
(停止执行并将控制权交给调试提示;这就是为什么在调试提示中有一个 KK>>
dbstop error
(自动使您进入调试模式,在触发错误的行停止)使用 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
从 Matlab 调用 Java 代码
我喜欢使用函数句柄有很多原因。一方面,它们是我在 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);
我只是觉得像这样的小东西很酷。
cellfun 和 arrayfun 用于自动 for 循环。
哦,反转一个数组
v = 1:10;
v_reverse = v(length(v):-1:1);
用于操作数组的冒号运算符。
@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);
赋值左侧的条件参数:
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);
在使用 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
>>
最小函数也是如此,它通常计算矩阵上列的最小值,直到矩阵仅包含一行。- 然后它将返回该行的最小值,除非维度参数另有说明,并且可能会破坏您的应用程序。
我几乎可以向您保证,因此设置这些聚合函数的维度将为您以后节省相当多的调试工作。
至少对我来说是这样。:)
为了能够快速测试一个功能,我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;
稍后,我添加了一个单元测试脚本来测试不同输入条件的函数。
使用 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
询问“为什么”(有助于让我在凌晨 3 点从 Matlab 运行时失败调试恍惚状态中惊醒……)
使用命令直接从脚本(而不是交互式)执行 Simulink 模型sim
。您可以执行诸如从工作区变量中获取参数之类的操作,并sim
在循环中重复运行以模拟某些内容,同时改变参数以查看行为如何变化,并使用您喜欢的任何图形命令绘制结果。比尝试以交互方式执行此操作要容易得多,并且在可视化结果时,它为您提供比 Simulink“示波器”块更大的灵活性。(虽然你不能用它来查看模拟运行时实时发生的事情)
要知道的一个非常重要的事情是命令的DstWorkspace
和SrcWorkspace
选项simset
。这些控制“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]=contour
带有和的等高线图clabel(c,h,'fontsize',fontsize)
。我通常使用该fontsize
参数来减小字体大小,这样数字就不会相互碰撞。这对于查看 2-D 函数的值非常有用,而无需处理 3D 图形。
矢量化:
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);
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
- 您可以创建一个名为 startup.m 的初始化文件的 Matlab 快捷方式。在这里,我为我的 Matlab 会话定义了格式、输出精度和绘图参数(例如,我使用更大的绘图轴/字体大小,以便在我将它们放在演示文稿中时可以清楚地看到 .fig。)来自其中一位开发人员的博客文章http://blogs.mathworks.com/loren/2009/03/03/whats-in-your-startupm/。
- 您可以使用“加载”功能加载整个数字 ascii 文件。这不是特别快,但可以快速完成原型设计工作(这不应该是 Matlab 的座右铭吗?)
- 如前所述,冒号运算符和矢量化是救命稻草。螺旋环。
令我惊讶的是,虽然人们提到了索引数组的逻辑数组方法,但没有人提到 find 命令。
例如,如果 x 是一个 NxMxO 数组
x(x>20) 通过生成 NxMxO 逻辑数组并使用它来索引 x 工作(如果您有大型数组并且正在寻找一个小子集,这可能会很糟糕
x(find(x>20)) 的工作原理是生成满足 x>20 的 x 的索引列表(即 1xwhatever),并通过它索引 x。根据我的经验,应该更多地使用“查找”。
更多我称之为“技巧”的东西
如果你不知道你需要的大小,你可以增长/追加到数组和单元格数组,通过使用 end + 1 (也适用于更高的维度,只要切片的维度匹配 - 所以你会在这种情况下,必须将 x 初始化为 [] 以外的其他值)。不适用于数值,但适用于小型动态列表(或元胞数组),例如解析文件。
例如
>> x=[1,2,3] x = 1 2 3 >> x(结束+1)=4 x = 1 2 3 4
另一个很多人不知道的想法是适用于任何 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
我不记得是否有更好的方法。
x=repmat([1:10],3,1); % 说,x 是一个示例数据数组
l=x>=3;% l 是一个逻辑向量(1s/0s),用于突出显示数组中满足特定条件的那些元素。
N=sum(sum(l));% N 是满足给定条件的元素个数。
干杯——快乐的脚本!
这是我经常使用的:
% useful abbreviations
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) )
如果我想将图像的大小放在标题中怎么办?
imagesc( phantomData );
title( sprintf('The image size is %d by %d by %d.', nrows(phantomData), ncols(phantomData), nslices(phantomData)) )