exponenta event banner

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

Использование векторизации

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     1
Для выбора допустимых объемов конуса можно непосредственно использовать логическую мощность индексирования MATLAB. 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 значения с использованием 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

Сумма элементов массива

Связанные темы

Внешние веб-сайты