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
В случаях, когда требуется явно создать сетки, можно использовать meshgrid и ndgrid функции.
Логическим расширением массовой обработки массивов является векторизация сравнений и принятия решений. Операторы сравнения MATLAB принимают векторные входы и обратные векторные выходы.
Например, предположим, что при сборе данных из 10000 конусов записывается несколько отрицательных значений диаметра. Определить, какие значения в векторе действительны, можно с помощью >= оператор:
D = [-0.2 1.0 1.5 3.0 -1.0 4.2 3.14]; D >= 0
ans =
0 1 1 1 0 1 1Vgood, для которого соответствующие элементы 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 3unique функция: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 | Определите, являются ли все элементы массива ненулевыми или истинными |
any | Определите, являются ли элементы массива ненулевыми |
cumsum | Совокупная сумма |
diff | Различия и приблизительные производные |
find | Найти индексы и значения ненулевых элементов |
ind2sub | Подстрочные индексы из линейного индекса |
ipermute | Обратные перестановочные размеры N-D массива |
logical | Преобразование числовых значений в логические |
meshgrid | Прямоугольная сетка в пространстве 2-D и 3-D |
ndgrid | Прямоугольная сетка в пространстве N-D |
permute | Перегруппировка размеров массива N-D |
prod | Произведение элементов массива |
repmat | Повторные копии массива |
reshape | Изменить форму массива |
shiftdim | Размеры сдвига |
sort | Сортировка элементов массива |
squeeze | Удаление одиночных размеров |
sub2ind | Преобразование подстрочных индексов в линейные индексы |
sum | Сумма элементов массива |