2016-05-19 2 views
2

Я надеюсь векторизация следующего цикла:Vectorize мин() для матрицы

for (i in 1:n) { 
    for (j in 1:m) { 
     temp_mat[i,j]=min(temp_mat[i,j],1); 
    } 
} 

Я думал, что я мог сделать temp_mat=min(temp_mat,1), но это не дает мне желаемый результат. Есть ли способ векторизовать этот цикл, чтобы сделать его намного быстрее?

ответ

10

Просто используйте temp_mat <- pmin(temp_mat, 1). См. ?pmin для более широкого использования параллельных минимумов.

Пример:

set.seed(0); A <- matrix(sample(1:3, 25, replace = T), 5) 
#> A 
#  [,1] [,2] [,3] [,4] [,5] 
#[1,] 3 1 1 3 3 
#[2,] 1 3 1 2 3 
#[3,] 2 3 1 3 1 
#[4,] 2 2 3 3 2 
#[5,] 3 2 2 2 1 
B <- pmin(A, 2) 
#> B 
#  [,1] [,2] [,3] [,4] [,5] 
#[1,] 2 1 1 2 2 
#[2,] 1 2 1 2 2 
#[3,] 2 2 1 2 1 
#[4,] 2 2 2 2 2 
#[5,] 2 2 2 2 1 

обновление

Поскольку у вас есть опыт работы в области вычислительной науки, я хотел бы предоставить более подробную информацию.

pmin быстрый, но далекий от высокой производительности. Его префикс «parallel» предлагает только element-wise. Значение «векторизации» в R не совпадает с «векторизацией SIMD» в HPC. R - интерпретируемый язык, поэтому «векторизация» в R означает выбор для цикла уровня C, а не цикла уровня R. Поэтому pmin просто закодирован с тривиальным циклом С.

Реальные высокопроизводительные вычисления должны быть полезны для векторизации SIMD. Я считаю, что вы знаете встроенные функции SSE/AVX. Поэтому, если вы напишете простой код C, используя _mm_min_pd от SSE2, вы получите ~ 2 раза ускорение от pmin; если вы видите _mm256_min_pd от AVX, вы получите ~ 4 раза ускорение от pmin.

К сожалению, сам R не может выполнять SIMD. У меня есть ответ на сообщение в Does R leverage SIMD when doing vectorized calculations? относительно этой проблемы. На ваш вопрос, даже если вы связали свой R с HPC BLAS, pmin не будет пользоваться SIMD, просто потому, что pmin не включает никаких операций BLAS. Поэтому лучше сделать запись скомпилированного кода самостоятельно.

+0

Я не думаю, что это не имеет ничего общего с R будучи столбцам. 'pmin' возвращает минимальный размер элемента между переданными элементами, поэтому 1 просто принуждается к объекту тех же размеров. Например, если передаются разные векторы по размеру, вы получаете предупреждение о том, что элементы перерабатываются. – Gabe

+2

Хотя это не то, что запросил ОП, существует ряд способов реализации массовых параллельных вычислений в Р.Примеры включают пакеты 'snow',' multicore', 'foreach',' Rmpi', 'Rth',' gputools' и базовый пакет 'parallel', который объединил несколько из ранее ранее отдельных пакетов. Вот [хорошая ссылка] (https://books.google.com/books/about/Parallel_Computing_for_Data_Science.html?id=SsbECQAAQBAJ) о состоянии дел в этой теме. – RHertel

+0

«Например, проблема OP не может извлечь выгоду из этой формы, становится связанной с памятью. Настройка нескольких потоков приведет к замедлению». Зачем? Разве это не стандартная задача параллельного программирования, чтобы разбить матрицу на отдельные куски и позволить каждому обрабатывать отдельный поток? В этом случае нет необходимости связываться между потоками. Это выглядит как стандартный пример неловко параллельной ситуации, с которой можно легко обращаться с R. – RHertel

4

Вопрос немного запутанный, потому что min()is векторизованный. Для получения желаемого результата в этом конкретном случае, однако, не обязательно использовать эту функцию. Логическое подмножество обеспечивает, вероятно, более эффективную (и, конечно, более компактную) альтернативу.

Если я понял ваш желаемый результат правильно, модификация матрицы в исполнении вложенных циклов в коде может быть достигнут с помощью одной команды:

temp_mat[temp_mat > 1] <- 1 

Надеется, что это помогает.


set.seed(123) 
temp_mat <- matrix(2*runif(50),10) 
#> temp_mat 
#   [,1]  [,2]  [,3]  [,4]  [,5] 
# [1,] 0.5751550 1.91366669 1.7790786 1.92604847 0.2856000 
# [2,] 1.5766103 0.90666831 1.3856068 1.80459809 0.8290927 
# [3,] 0.8179538 1.35514127 1.2810136 1.38141056 0.8274487 
# [4,] 1.7660348 1.14526680 1.9885396 1.59093484 0.7376909 
# [5,] 1.8809346 0.20584937 1.3114116 0.04922737 0.3048895 
# [6,] 0.0911130 1.79964994 1.4170609 0.95559194 0.2776121 
# [7,] 1.0562110 0.49217547 1.0881320 1.51691908 0.4660682 
# [8,] 1.7848381 0.08411907 1.1882840 0.43281587 0.9319249 
# [9,] 1.1028700 0.65584144 0.5783195 0.63636202 0.5319453 
#[10,] 0.9132295 1.90900730 0.2942273 0.46325157 1.7156554 
temp_mat[temp_mat > 1] <- 1 
#> temp_mat 
#   [,1]  [,2]  [,3]  [,4]  [,5] 
# [1,] 0.5751550 1.00000000 1.0000000 1.00000000 0.2856000 
# [2,] 1.0000000 0.90666831 1.0000000 1.00000000 0.8290927 
# [3,] 0.8179538 1.00000000 1.0000000 1.00000000 0.8274487 
# [4,] 1.0000000 1.00000000 1.0000000 1.00000000 0.7376909 
# [5,] 1.0000000 0.20584937 1.0000000 0.04922737 0.3048895 
# [6,] 0.0911130 1.00000000 1.0000000 0.95559194 0.2776121 
# [7,] 1.0000000 0.49217547 1.0000000 1.00000000 0.4660682 
# [8,] 1.0000000 0.08411907 1.0000000 0.43281587 0.9319249 
# [9,] 1.0000000 0.65584144 0.5783195 0.63636202 0.5319453 
#[10,] 0.9132295 1.00000000 0.2942273 0.46325157 1.0000000