你如何在Julia中的数组中执行条件赋值?

时间:2015-04-11 02:24:35

标签: octave julia

在Octave,我可以做到

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

   1   2
   3   4

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

   1   1
   2   3

但是在Julia中,等效语法不起作用。

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中有条件地为某些数组或矩阵元素赋值?

3 个答案:

答案 0 :(得分:16)

您的问题本身并不是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中的点,但不需要.-=中的点。)

答案 1 :(得分:3)

要使其在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)匹配的方法

答案 2 :(得分:3)

在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)

这也避免了分配。