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

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

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
Можно непосредственно использовать логическую степень индексации MATLAB, чтобы выбрать допустимые тома конуса, 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

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

Похожие темы

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