Как вы выполняете условное присваивание в массивах в Джулии?

В Октаве я могу

octave:1> A = [1 2; 3 4]
A =

   1   2
   3   4

octave:2> A(A>1) -= 1
A =

   1   1
   2   3

но в Джулии аналогичный синтаксис не работает.

julia> A = [1 2; 3 4]
2x2 Array{Int64,2}:
 1  2
 3  4

julia> A[A>1] -= 1
ERROR: `isless` has no method matching isless(::Int64, ::Array{Int64,2})
 in > at operators.jl:33

Как вы условно присваиваете значения определенным элементам массива или матрицы в Julia?


person sffc    schedule 11.04.2015    source источник


Ответы (3)


Ваша проблема не в задании как таковом, а в том, что A > 1 само по себе не работает. Вместо этого вы можете использовать поэлементный A .> 1:

julia> A = [1 2; 3 4];

julia> A .> 1
2×2 BitArray{2}:
 false  true
  true  true

julia> A[A .> 1] .-= 1000;

julia> A
2×2 Array{Int64,2}:
    1  -998
 -997  -996

Обновлять:

Обратите внимание, что в современной версии Julia (>= 0,7) нам нужно использовать ., чтобы сказать, что мы хотим транслировать действие (здесь вычитание на скаляр 1000), чтобы оно соответствовало размеру отфильтрованной цели слева. (В то время, когда этот вопрос был первоначально задан, нам нужна была точка в A .> 1, но не в .-=.)

person DSM    schedule 11.04.2015

В Julia v1.0 вы можете использовать функцию replace! вместо логического индексирования со значительным ускорением:

julia> B = rand(0:20, 8, 2);

julia> @btime (A[A .> 10] .= 10) setup=(A=copy($B))
  595.784 ns (11 allocations: 4.61 KiB)

julia> @btime replace!(x -> x>10 ? 10 : x, A) setup=(A=copy($B))
  13.530 ns ns (0 allocations: 0 bytes)

Для больших матриц разница колеблется в районе 10-кратного ускорения.

Причина ускорения заключается в том, что решение логической индексации основано на создании промежуточного массива, а replace! избегает этого.

Немного более лаконичный способ написания

replace!(x -> min(x, 10), A)

Однако с использованием min, похоже, нет никакого ускорения.

И вот еще одно решение, которое почти такое же быстрое:

A .= min.(A, 10)

и это также позволяет избежать ассигнований.

person DNF    schedule 23.10.2018

Чтобы это работало в Julia 1.0, нужно изменить = на .=. Другими словами:

julia> a = [1 2 3 4]

julia> a[a .> 1] .= 1

julia> a
1×4 Array{Int64,2}:
 1  1  1  1

В противном случае вы получите что-то вроде

ОШИБКА: MethodError: нет метода, соответствующего setindex_shape_check(::Int64, ::Int64)

person Ivan Toftul    schedule 28.08.2018