MATLAB® оптимизирован для операций включающие матрицы и векторы. Процесс пересмотра основанного на цикле, ориентированного на скаляр кода, чтобы использовать матрицу MATLAB и векторные операции называется векторизацией. Векторизация вашего кода стоит по нескольким причинам:
Внешний вид: Векторизованный математический код появляется больше как математические выражения, найденные в учебниках, делая код легче понять.
Менее подверженный ошибкам: Без циклов векторизованный код часто короче. Меньше строк кода означает меньше возможностей ввести программные ошибки.
Производительность: Векторизованный код часто запускается намного быстрее, чем соответствующий код, содержащий циклы.
Этот код вычисляет синус 1 001 значения в пределах от от 0 до 10:
i = 0; for t = 0:.01:10 i = i + 1; y(i) = sin(t); end
Это - векторизованная версия того же кода:
t = 0:.01:10; y = sin(t);
Второй пример кода обычно выполняется быстрее, чем первое и является более эффективным использованием MATLAB. Скорость выполнения теста в вашей системе путем создания скриптов, которые содержат код, показанный, и затем используют tic
и функции toc
, чтобы измерить их время выполнения.
Этот код вычисляет совокупную сумму вектора в каждом пятом элементе:
x = 1:10000; ylength = (length(x) - mod(length(x),5))/5; y(1:ylength) = 0; for n= 5:5:length(x) y(n/5) = sum(x(1:n)); end
Используя векторизацию, можно записать намного более краткий процесс MATLAB. Этот код показывает один способ выполнить задачу:
x = 1:10000; xsums = cumsum(x); y = xsums(5:5:length(x));
Операторы массивов выполняют ту же операцию для всех элементов в наборе данных. Эти типы операций полезны для повторяющихся вычислений. Например, предположите, что вы собираете объем (V
) различных конусов путем записи их диаметра (D
) и высота (H
). Если вы собираете информацию всего для одного конуса, можно вычислить объем для того одного конуса:
V = 1/12*pi*(D^2)*H;
Теперь, соберите информацию относительно 10 000 конусов. Векторы D
и H
, каждый содержит 10 000 элементов, и вы хотите вычислить 10 000 объемов. На большинстве языков программирования необходимо настроить цикл, подобный этому коду MATLAB:
for n = 1:10000 V(n) = 1/12*pi*(D(n)^2)*H(n)); end
С MATLAB можно выполнить вычисление для каждого элемента вектора с подобным синтаксисом как скалярный случай:
% Vectorized Calculation
V = 1/12*pi*(D.^2).*H;
Помещая период (.
) перед операторами *
, /
и ^
, преобразовывают их в операторы массивов.
Операторы массивов также позволяют вам объединить матрицы различных размерностей. Это автоматическое расширение размера 1 размерность полезно для векторизации создания сетки, матричных и векторных операций и т.д.
Предположим, что матричный A
представляет экзаменационные отметки, строки которых обозначают различные классы. Вы хотите вычислить различие между средней оценкой и отдельной музыкой к каждому классу. Используя цикл, операция похожа:
A = [97 89 84; 95 82 92; 64 80 99;76 77 67;... 88 59 74; 78 66 87; 55 93 85]; mA = mean(A); B = zeros(size(A)); for n = 1:size(A,2) B(:,n) = A(:,n) - mA(n); end
Более прямой способ сделать это с A - mean(A)
, который избегает потребности цикла и значительно быстрее.
devA = A - mean(A)
devA = 18 11 0 16 4 8 -15 2 15 -3 -1 -17 9 -19 -10 -1 -12 3 -24 15 1
Даже при том, что A
7 3, матрица и mean(A)
1 3 вектор, MATLAB неявно расширяет вектор, как будто это имело тот же размер как матрица, и операция выполняется как нормальное поэлементное минус операция.
Требование размера для операндов - то, что для каждой размерности, массивы должны или иметь тот же размер или одного из них, 1. Если это требование удовлетворяется, то размерности, где один из массивов имеет размер 1, расширены, чтобы быть одного размера как соответствующая размерность в другом массиве. Для получения дополнительной информации см. "Совместимые размеры массивов для основных операций".
Другая область, где неявное расширение полезно для векторизации, - то, если вы работаете с многомерными данными. Предположим, что вы хотите выполнить функцию, F
, двух переменных, x
и y
.
F(x,y) = x*exp(-x2 - y2)
Чтобы выполнить эту функцию в каждой комбинации точек в x
и векторах y
, необходимо задать сетку значений. Для этой задачи необходимо избегать использования циклов, чтобы выполнить итерации через комбинации точки. Вместо этого если один из векторов является столбцом, и другой строка, то MATLAB автоматически создает сетку, когда векторы используются с оператором массивов, таким как x+y
или x-y
. В этом примере x
21 1, вектор и y
1 16 вектор, таким образом, операция производит 21 16 матрица путем расширения второго измерения x
и первой размерности y
.
x = (-2:0.2:2)'; % 21-by-1 y = -1.5:0.2:1.5; % 1-by-16 F = x.*exp(-x.^2-y.^2); % 21-by-16
В случаях, где вы хотите явным образом создать сетки, можно использовать функции ndgrid
и meshgrid
.
Логическое расширение объемной обработки массивов должно векторизовать сравнения и принятие решения. Операторы сравнения MATLAB принимают векторные входные параметры и возвращают векторные выходные параметры.
Например, предположите при сборе данных от 10 000 конусов, вы записываете несколько отрицательных величин для диаметра. Можно определить, какие значения в векторе допустимы с оператором >=
:
D = [-0.2 1.0 1.5 3.0 -1.0 4.2 3.14]; D >= 0
ans = 0 1 1 1 0 1 1
Vgood
, для которого соответствующие элементы D
являются неотрицательными:Vgood = V(D >= 0);
MATLAB позволяет вам выполнять логический AND или OR на элементах целого вектора с функциями all
и any
, соответственно. Можно выдать предупреждение, если все значения D
ниже нуля:
if all(D < 0) warning('All values of diameter are negative.') return end
MATLAB может также сравнить два вектора с совместимыми размерами, позволив вам ввести дальнейшие ограничения. Этот код находит все значения, где V является неотрицательным, и D
больше, чем H
:
V((V >= 0) & (D > H))
Чтобы помочь сравнению, MATLAB содержит специальные значения, чтобы обозначить переполнение, потерю значимости и неопределенные операторы, такие как Inf
и NaN
. Логические операторы isinf
и isnan
существуют, чтобы помочь выполнить логические тесты для этих специальных значений. Например, часто полезно исключить значения NaN
из вычислений:
x = [2 -1 0 3 NaN 2 NaN 11 4 Inf]; xvalid = x(~isnan(x))
xvalid = 2 -1 0 3 2 11 4 Inf
Inf == Inf
возвращает true; однако, NaN == NaN
всегда возвращает false.
При векторизации кода часто необходимо создавать матрицу с конкретным размером или структурой. Методы существуют для создания универсальных матриц. Например, вам может быть нужна матрица 5 на 5 равных элементов:
A = ones(5,5)*10;
v = 1:5; A = repmat(v,3,1)
A = 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
Функциональный repmat
обладает гибкостью в создании матриц из меньших матриц или векторов. repmat
создает матрицы путем повторения входной матрицы:
A = repmat(1:3,5,2) B = repmat([1 2; 3 4],2,2)
A = 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 B = 1 2 1 2 3 4 3 4 1 2 1 2 3 4 3 4
Во многих приложениях вычисления, сделанные на элементе вектора, зависят от других элементов в том же векторе. Например, вектор, x, может представлять набор. Как выполнить итерации через набор без for
, или цикл while
не очевиден. Процесс становится намного более ясным и синтаксис, менее громоздкий, когда вы используете векторизованный код.
Много различных путей существуют для нахождения избыточных элементов вектора. Один путь включает функциональный diff
. После сортировки векторных элементов равные смежные элементы производят нулевую запись, когда вы используете функцию diff
на том векторе. Поскольку diff(x)
производит вектор, который имеет тот меньше элемента, чем x
, необходимо добавить элемент, который не равен никакому другому элементу в наборе. NaN
всегда удовлетворяет это условие. Наконец, можно использовать логическую индексацию, чтобы выбрать уникальные элементы в наборе:
x = [2 1 2 2 3 1 3 2 1 3]; x = sort(x); difference = diff([x,NaN]); y = x(difference~=0)
y = 1 2 3
unique
:y=unique(x);
unique
, который функциональная сила обеспечивает большей функциональности, чем, необходим, и замедлите подписание своего кода. Используйте tic
и функции toc
, если вы хотите измерить уровень каждого фрагмента кода.Вместо того, чтобы просто возвращать набор или подмножество, x
, можно считать случаи элемента в векторе. После векторных видов можно использовать функцию find
, чтобы определить индексы нулевых значений в diff(x)
и показать, где элементы изменяют значение. Различие между последующими индексами от функции find
указывает на количество случаев для конкретного элемента:
x = [2 1 2 2 3 1 3 2 1 3]; x = sort(x); difference = diff([x,max(x)+1]); count = diff(find([1,difference])) y = x(find(difference))
count = 3 4 3 y = 1 2 3
find
не возвращает индексы для элементов NaN
. Можно считать количество NaN
и значений Inf
с помощью функций isinf
и isnan
.count_nans = sum(isnan(x(:))); count_infs = sum(isinf(x(:)));
Функция | Описание |
---|---|
all | Определите, являются ли все элементы массива ненулевыми или верными |
any | Определите, являются ли какие-либо элементы массива ненулевыми |
cumsum | Совокупная сумма |
diff | Разности и аппроксимация производных |
find | Найдите индексы и значения ненулевых элементов |
ind2sub | Индексы от линейного индекса |
ipermute | Инверсия переставляет размерности массива N-D |
logical | Преобразуйте числовые значения в logicals |
meshgrid | Прямоугольная сетка на 2D и 3-D пробеле |
ndgrid | Прямоугольная сетка на пробеле N-D |
permute | Перестройте размерности массива N-D |
prod | Произведение элементов массива |
repmat | Копирование массива |
reshape | Изменение размерности массива |
shiftdim | Сдвиг размерностей массива |
sort | Сортировка массива |
squeeze | Удалите одноэлементные размерности |
sub2ind | Преобразуйте индексы в линейные индексы |
sum | Сумма элементов массива |