私は、MATLAB言語がきれいではない、または特に一貫していないことに誰もが同意すると思います。でも気にしないで!私たちはまだ物事を成し遂げるためにそれを使わなければなりません。
物事を簡単にするためのあなたの好きなトリックは何ですか?回答ごとに1つ用意して、同意した場合に投票できるようにします。また、例を使って答えを説明してみてください。
組み込みのプロファイラーを使用して、コードのホット パーツがどこにあるかを確認します。
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 の要素のみが含まれます。
ヘルプコメントに「SEEALSO」行を追加して、他の機能ドキュメントにすばやくアクセスできるようにします。まず、最初のコメント行として関数の名前をすべて大文字で含める必要があります。通常のコメントヘッダー処理を実行してから、他の関連関数のコンマ区切りリストを使用してSEEALSOを配置します。
function y = transmog(x)
%TRANSMOG Transmogrifies a matrix X using reverse orthogonal eigenvectors
%
% Usage:
% y = transmog(x)
%
% SEE ALSO
% UNTRANSMOG, TRANSMOG2
コマンドラインで「helptransmog」と入力すると、このコメントヘッダーにすべてのコメントが表示され、リストされている他の関数のコメントヘッダーへのハイパーリンクが表示されます。
単一のコロンを使用して行列をベクトルに変換します。
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?) の 1 つでは,'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');
いつ追加されたかは不明ですが、R2006b の text()、title()、xlabel()、ylabel()、zlabel()、さらには legend() 関数で動作します。使用している構文が曖昧でないことを確認してください (そのため、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
(実行を停止し、デバッグ プロンプトに制御を渡します。これが、デバッグ プロンプトに K がある理由です。K>>
dbstop error
(エラーが発生した行で停止したデバッグ モードに自動的に移行します)MatlabからのJavaコードの呼び出し
多くの理由から、関数ハンドルを使用するのが好きです。1 つは、これらは私が 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);
そんな些細なことがカッコイイと思います。
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
min、max、mean、diff、sum、any、all、...などの集計関数を使用する場合は、ディメンションの指定を厳密に行ってください。
たとえば、次の行です。
reldiff = diff(a) ./ a(1:end-1)
ベクトル内の要素の相対的な差を計算するのにうまくいくかもしれませんが、ベクトルが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
>>
行列が1行のみで構成されるまで、通常は行列の列の最小値を計算するmin関数についても同じことが言えます。-次に、ディメンションパラメータで特に明記されていない限り、行全体で最小値が返され、アプリケーションが破損する可能性があります。
その結果、これらの集計関数のディメンションを設定すると、後でデバッグ作業をかなり節約できることをほぼ保証できます。
少なくとも私にとってはそうだったでしょう。:)
自動 for ループ用の cellfun と arrayfun。
代入の左側の条件付き引数:
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);
ああ、配列を逆にする
v = 1:10;
v_reverse = v(length(v):-1:1);
関数をすばやくテストできるようにするために、次の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;
後で、単体テスト スクリプトを追加して、さまざまな入力条件で関数をテストします。
配列操作用のコロン演算子。
@ ScottieT812 は、1 つ言及しています: 配列をフラット化しますが、配列のビットを選択する他のすべてのバリエーションがあります。
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);
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
これらは、「ToWorkspace」ブロックと「FromWorkspace」ブロックが結果を取得および配置する場所を制御します。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
パラメーターを使用してフォントサイズを小さくし、数値が互いにぶつからないようにします。これは、3Dグラフをいじくり回すことなく、2D関数の値を表示するのに最適です。
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
ベクトル化:
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);
これが私が頻繁に使用するものです:
% 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)) )
配列にインデックスを付けるという論理配列アプローチについて言及した人がいる一方で、find コマンドについて言及した人が誰もいなかったことに驚いています。
たとえば、x が NxMxO 配列の場合
x(x>20) は、NxMxO 論理配列を生成し、それを使用して x のインデックスを作成することで機能します (大きな配列があり、小さなサブセットを探している場合、これは不適切な場合があります)。
x(find(x>20)) は、x>20 を満たす x のインデックスのリスト (つまり、1xwhatever) を生成し、それによって x にインデックスを付けることによって機能します。私の経験では、「find」はそれ以上に使用する必要があります。
私が「トリック」と呼ぶもの
必要なサイズがわからない場合は、 end + 1 を使用して、配列とセル配列に拡張/追加できます (スライスの次元が一致する限り、より高い次元でも機能します。その場合、x を [] 以外に初期化する必要があります)。数値には適していませんが、ファイルの解析など、物事 (またはセル配列) の小さな動的リストには適していません。
例えば
>> x=[1,2,3] x = 1 2 3 >> x(終わり+1)=4 x = 1 2 3 4
多くの人が知らないもう1つの考えは、 for が任意のdim 1配列で動作することです。そのため、例を続ける
>> n = x の場合;disp(n);end 1 2 3 4
つまり、必要なのが x のメンバーだけである場合、それらにインデックスを付ける必要はありません。
これはセル配列でも機能しますが、要素がセルにラップされているため、少し面倒です。
>> el = {1,2,3,4} の場合;disp(el);end [1] [2] [3] [4]
したがって、要素を取得するには、それらに添字を付ける必要があります
>> el = {1,2,3,4} の場合;disp(el{1});end 1 2 3 4
それを回避するより良い方法があるかどうかは思い出せません。
x=repmat([1:10],3,1); % たとえば、x はデータの配列の例です
l=x>=3; % l は、特定の条件を満たす配列内の要素を強調表示するための論理ベクトル (1/0) です。
N=sum(sum(l));% N は、その条件を満たす要素の数です。
乾杯 -- 楽しいスクリプティング!