Какой твой любимый трюк в MATLAB / Octave?

77

Думаю, все согласятся с тем, что язык MATLAB не очень хорош или особенно последователен. Но не бери в голову! Мы все еще должны использовать его, чтобы все было сделано.

Каковы ваши любимые трюки для облегчения дела? Пусть есть один ответ, чтобы люди могли проголосовать за них, если они согласны. Также попробуйте проиллюстрировать свой ответ на примере.

Теги:
octave

31 ответ

42

Используя встроенный профилировщик, чтобы узнать, где находятся горячие части моего кода:

profile on
% some lines of code
profile off
profile viewer

или просто используя встроенные tic и toc, чтобы получить быстрые тайминги:

tic;
% some lines of code
toc;
33

Непосредственное извлечение элементов матрицы, удовлетворяющих определенному условию, с использованием логических массивов:

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

Теперь xpart содержит только те элементы из x, которые лежат в указанном диапазоне.

  • 0
    В Matlab вы можете использовать функцию find, чтобы сделать то же самое.
  • 10
    Но найти гораздо медленнее. Логическое индексирование выполняется намного быстрее, если только вам не нужно знать индексы совпадений.
29

Обеспечьте быстрый доступ к другой документации по функциям, добавив строку "СМОТРИТЕ ТАКЖЕ" в комментарии справки. Во-первых, вы должны указать имя функции во всех кепках в качестве первой строки комментария. Сделайте свой обычный заголовок комментария, затем добавьте SEE ALSO с разделенным запятыми списком других связанных функций.

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

Когда вы вводите "help transformog" в командной строке, вы увидите все комментарии в этом заголовке комментария, с гиперссылками к заголовкам комментариев для других перечисленных функций.

24

Векторизация циклов. Есть много способов сделать это, и интересно посмотреть на циклы в коде и посмотреть, как они могут быть векторизованы. Эффективность поразительно быстрее с векторными операциями!

  • 0
    так ли это сейчас, когда у Matlab есть JIT-компилятор? Было бы интересно посмотреть.
23

Поверните матрицу в вектор, используя один двоеточие.

x = rand(4,4);
x(:)
  • 1
    Как бы вы сделали это для субматрицы? Допустим, x = rand (20, 20); Я хочу превратить х (1:10, 1:10) в вектор. Y = изменить форму (x (: 10, 1:10), [], 1) или y = x (1:10, 1:10) -> y = y (:) мои единственные варианты? Само собой разумеется, что x (1:10, 1:10) (:) не будет работать.
  • 0
    @Drazick, вы можете получить доступ к элементам x с помощью многомерных указателей или одномерного индекса. myElems = [1:10 21:30 31:40...181:190]; y = x(myElems);
Показать ещё 3 комментария
21

Matlab bsxfun, arrayfun, cellfun, и structfun довольно интересны и часто сохраняйте цикл.

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

Этот код, например, добавляет вектор-столбец v к каждому столбцу матрицы M.

Хотя в критичных для производительности частях приложения вы должны сравнивать эти функции с тривиальным циклом for, потому что часто петли все еще быстрее.

20

Анонимные функции по нескольким причинам:

  • чтобы сделать быструю функцию для одноразовых применений, например 3x ^ 2 + 2x + 7. (см. список ниже). Это полезно для таких функций, как 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);
  • 0
    Отличное замечание об использовании в скриптах!
  • 0
    В конце 4-й строки отсутствует знак ")".
Показать ещё 3 комментария
19

Режим 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');

Не уверен, когда они добавили его, но он работает с R2006b в функциях text(), title(), xlabel(), ylabel(), zlabel() и даже legend(). Просто убедитесь, что используемый вами синтаксис не является двусмысленным (поэтому с легендой() вам нужно указать строки как массивы ячеек).

  • 0
    Однако Matlab выдаст ошибку в вашем примере, потому что векторы, переданные в команду plot имеют разную длину. Я полагаю, вы пытаетесь построить две линии, верно? Вам нужно использовать точку с запятой в матрице, передаваемой вашей команде plot, чтобы Matlab знал, что это две отдельные серии, например, так: plot(t,sin(2*pi*[t ; t+0.25]));
18

Использование xlim и ylim для рисования вертикальных и горизонтальных линий. Примеры:

  • Нарисуйте горизонтальную линию при y = 10:

    line(xlim, [10 10])

  • Нарисуйте вертикальную линию при x = 5:

    line([5 5], ylim)

  • 0
    Это потрясающе!
  • 1
    Это не всегда работает. Лимиты не обновляются в режиме реального времени. В этом случае вызов drawnow заставит его обновить их.
17

Вот пример:

Я считаю, что синтаксис списка с разделителями-запятыми весьма полезен для построения вызовов функций:

% 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}{:}
12

Здесь куча неочевидных функций, которые время от времени полезны:

  • mfilename (возвращает имя текущего запущенного MATLAB script)
  • dbstack (дает вам доступ к именам и номерам строк стека функций Matlab)
  • keyboard (останавливает выполнение и дает возможность управления запросом на отладку, поэтому в приглашении отладки K>>
  • dbstop error (автоматически отключает режим отладки в строке, которая вызывает ошибку)
11

Мне нравится использовать функциональные дескрипторы по многим причинам. Во-первых, это самая близкая вещь, которую я нашел в 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);

Я просто думаю, что такие вещи классные.

11

Использование 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
  • 8
    Я считаю, что функции легче поддерживать, если они используют, если они if exist('plotColor', 'var') ... , потому что тогда вы используете имя аргумента, а не только номер его аргумента.
  • 0
    @rescdsk хороший момент, спасибо
10

Вызов кода Java из Matlab

5

Чтобы быстро проверить функцию, я использую 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;

Впоследствии я добавляю unit test script для проверки функции для разных условий ввода.

5

Быть строгим с указанием размеров при использовании функций агрегации, таких как 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

>> 

То же самое относится к min-функции, которая обычно вычисляет минимумы по столбцам на матрице, пока матрица не состоит только из одной строки. - Затем он вернет минимум по строке, если параметр измерения не указывает иначе, и, возможно, нарушит ваше приложение.

Я почти гарантирую вам, что, следовательно, настройка этих функций агрегации позволит вам в дальнейшем немного отладить работу.

По крайней мере, это было бы для меня.:)

  • 0
    это терпит неудачу, потому что matlab не C / C ++: вы должны использовать a(1:end) вместо a(1:end-1)
  • 1
    это не является ошибкой: результат diff примененный к вектору размера n, имеет размер n-1.
5

Знайте свои свойства оси! Существуют всевозможные вещи, которые вы можете настроить, чтобы настроить свойства построения по умолчанию, чтобы делать то, что вы хотите:

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

(в качестве примера, устанавливает шрифт в 8pt, linestyles всех новых строк, чтобы все были сплошными, а их ширина - 0,3pt, а xtick - [1 3 5 7 9])

Line и figure свойства также полезно, но я больше всего использую свойства оси.

5

условные аргументы в левой части присваивания:

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);
5

О, и измените массив

v = 1:10;
v_reverse = v(length(v):-1:1);
  • 6
    Хм. Я бы просто использовал flipud() или fliplr() для этого. Однако в сочетании с шагами это более полезно. например, v (конец: -4: 1), например.
  • 0
    Мне нравится мой путь против flipud () / fliplr (), потому что вам не нужно знать, есть ли у вас вектор столбца или вектор строки.
Показать ещё 1 комментарий
5

Оператор двоеточия для манипуляции массивами.

@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);
  • 1
    lastSix = y (end-5: end); Ваша версия возвращает 7 элементов.
  • 0
    Спасибо @jonas - снова по одному!
5

cellfun и arrayfun для автоматических циклов.

4

Задание "почему" (полезно для того, чтобы сотрясать меня из теста Matlab runtime-fail debugging trance в 3 часа...)

4

Использование 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

Использование 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
  • 0
    persistent опасно, потому что вы не можете напрямую установить внутреннее состояние, а это значит, что вы не можете правильно выполнить тестирование. Кроме того, это означает, что вы можете использовать функцию только в одном месте одновременно. Например, если вы хотите вычислить промежуточные средние для двух отдельных величин, вам необходимо скопировать файл, чтобы разделить состояния.
  • 0
    Это правда, что мы должны избегать его использования, если это не помогает, поскольку это может привести к неожиданным проблемам, которые трудно заметить. В моей задаче я делаю некоторые онлайн-модификации для нескольких переменных, так что это значительно улучшило скорость кода. Следует использовать это с осторожностью.
3

Контурные графики с [c,h]=contour и clabel(c,h,'fontsize',fontsize). Обычно я использую параметр fontsize, чтобы уменьшить размер шрифта, чтобы числа не попадали друг в друга. Это отлично подходит для просмотра значений двухмерных функций без необходимости гасить 3D-графики.

3

Выполнение модели Simulink непосредственно из script (а не интерактивно) с помощью команды 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;
3

Векторизация:

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);
2

Здесь я часто использую:

% 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)) )

код >

2

х = repmat ([1:10], 3,1); % say, x - пример массива данных

л = х >= 3; % l является логическим вектором (1s/0s), чтобы выделить те элементы в массиве, которые удовлетворяли бы определенному условию.

N = сумма (сумма (l));% N - количество элементов, удовлетворяющих данному условию.

cheers - счастливые скрипты!

  • 0
    и если x является 3D, тогда вам нужна другая sum () для вычисления N. Я бы использовал N = sum(I(:)); вместо этого, работает с любой размерностью.
  • 0
    Или даже numel(x>=3)
2

-Вы можете сделать ярлык Matlab для файла инициализации с именем startup.m. Здесь я определяю форматирование, точность вывода и параметры графика для моего сеанса Matlab (например, я использую более крупный размер/размер шрифта, так что .fig можно увидеть явно, когда я помещаю их в презентации.) См. Хороший сообщение блога от одного из разработчиков об этом http://blogs.mathworks.com/loren/2009/03/03/whats-in-your-startupm/.

-Вы можете загрузить весь цифровой файл ascii с помощью функции "load". Это не особенно быстро, но быстро выполняет задание для прототипирования (не должен ли это быть девизом Matlab?)

- Как упоминалось, оператор двоеточия и векторизация являются спасателями. Винтовые петли.

2

Я удивлен, что, хотя люди упоминали подход логического массива индексации массива, никто не упомянул команду find.

например. если x - массив NxMxO

x (x > 20) работает, создавая логический массив NxMxO и используя его для индекса x (что может быть плохо, если у вас большие массивы и вы ищете небольшое подмножество

x (find (x > 20)) работает, генерируя список (т.е. 1x любой) индексов x, удовлетворяющих x > 20, и индексируя x им. "find" следует использовать больше, чем есть, по моему опыту.

Больше, что я бы назвал "трюками"

вы можете расти/присоединяться к массивам и массивам ячеек, если вы не знаете размер, который вам понадобится, используя end + 1 (также работает с более высокими размерами, если размеры совпадения совпадений - так вам придется инициализировать x для чего-то другого, кроме [] в этом случае). Не подходит для чисел, но для небольших динамических списков вещей (или массивов ячеек), например. разбор файлов.

например.

>> x=[1,2,3]
x =  1     2     3
>> x(end+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

Я не могу вспомнить, есть ли более хороший способ.

  • 0
    Использование find в таких ситуациях - плохая идея, потому что это избыточно и медленнее. Лично я нахожу логический подход более ясным, потому что он также избегает дополнительного беспорядка.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню