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));
Операторы Array выполняют ту же операцию для всех элементов в наборе данных. Эти типы операций полезны для повторных вычислений. Например, предположим, что вы собираете объем (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;
Примечание
Размещение периода (.
) перед операторами *
, /
, и ^
, преобразует их в операторы массива.
Операторы Array также позволяют вам комбинировать матрицы различных размерностей. Это автоматическое расширение размерностей size-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
В случаях, когда необходимо явно создать сетки, можно использовать meshgrid
и ndgrid
функций.
Логическим расширением массовой обработки массивов является векторизация сравнений и принятия решений. Операторы сравнения 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 позволяет вам выполнять логическое И ИЛИ на элементах целого вектора с функциями 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
значений с использованием isnan
и isinf
функций.count_nans = sum(isnan(x(:))); count_infs = sum(isinf(x(:)));
Функция | Описание |
---|---|
all | Определите, все ли элементы массива ненулевые или true |
any | Определите, являются ли какие-либо элементы массива ненулевыми |
cumsum | Совокупная сумма |
diff | Разности и аппроксимации производных |
find | Найдите индексы и значения ненулевых элементов |
ind2sub | Индексы из линейного индекса |
ipermute | Обратная перестановка размерностей N-D массива |
logical | Преобразуйте числовые значения в логики |
meshgrid | Прямоугольная сетка в 2-D и трехмерном пространстве |
ndgrid | Прямоугольная сетка в N-D пространстве |
permute | Переставьте размерности N-D массива |
prod | Произведение элементов массива |
repmat | Повторите копии массива |
reshape | Перестроить массив |
shiftdim | Сдвиньте размеры |
sort | Сортировка массива |
squeeze | Удалите синглтонные размерности |
sub2ind | Преобразуйте индексы в линейные индексы |
sum | Сумма элементов массива |