Julia 中矩阵之间的逐行运算
Row-wise operations between matrices in Julia
我正在尝试将以下 Python 代码(来自 SMT GEKPLS)的等价物翻译成 Julia:
def differences(X, Y):
D = X[:, np.newaxis, :] - Y[np.newaxis, :, :]
return D.reshape((-1, X.shape[1]))
所以,给定这样的输入:
X = np.array([[1.0,1.0,1.0], [2.0,2.0,2.0]])
Y = np.array([[1.0,2.0,3.0], [4.0,5.0,6.0], [7.0,8.0,9.0]])
diff = differences(X,Y)
我们得到如下所示的输出(差异):
[[ 0. -1. -2.]
[-3. -4. -5.]
[-6. -7. -8.]
[ 1. 0. -1.]
[-2. -3. -4.]
[-5. -6. -7.]]
使用 Julia 代码执行此操作的有效方法是什么?我希望 X 和 Y 输入矩阵非常大。
经过一番思考,得出了这个函数:
function differences(X, Y)
Rx = repeat(X, inner=(size(Y, 1), 1))
Ry = repeat(Y, size(X, 1))
Rx - Ry
end
希望对您有所帮助。
这是一个避免 repeat
的版本,它会产生不必要的数据重复:
function diffs_row(X, Y)
N = size(X, 2)
return reshape(reshape(X', 1, N, :) .- Y', N, :)'
end
所有伴随词 '
的原因是在 Julia 中操作 row-wise 并不是很自然。 Julia 数组是 column-major,因此 reshape
将检索数据 column-wise。如果您决定改为更改数据的方向,您可以写
function diffs_col(X, Y)
N = size(X, 1)
return reshape(reshape(X, N, 1, :) .- Y, N, :)
end
相反。
人们在将 numpy 代码翻译成 Julia 时经常看到这一点。 Numpy 是原生的 row-major,所以翻译起来有点别扭。在许多情况下,您应该考虑将数据布局更改为主要列。
这可能比其他替代方案更快,同时仍然易于理解。
[x .- y for x ∈ X for y ∈ Y]
6-element Vector{Vector{Float64}}:
[0.0, -1.0, -2.0]
[-3.0, -4.0, -5.0]
[-6.0, -7.0, -8.0]
[1.0, 0.0, -1.0]
[-2.0, -3.0, -4.0]
[-5.0, -6.0, -7.0]
我不喜欢 numpy
的一件事是,必须准确记住每个函数以及输入参数的组合。在 Julia 中,传统循环可以作为大多数算法的有效 drop-in 替代。
附录: 以上可能是我所说的最快的解决方案,前提是使用 Vector{Vector{Float64}}
不是问题。如果是,这是另一个输出 Matrix{Float64}
同时速度也很快的解决方案。
function diffr(X,Y)
i, l, m, n = 0, length(first(X)), length(X), length(Y)
Z = Matrix{Float64}(undef, m*n, l)
for x in X, y in Y
Z[i+=1,:] .= x .- y
end
Z
end
这里是我电脑上所有已发布解决方案的性能比较。
@btime [x.-y for x∈$X for y∈$Y] # 312.245 ns (9 allocations: 656 bytes)
@btime diffr($X, $Y) # 73.868 ns (1 allocation: 208 bytes)
@btime differences($X, $Y) # 439.000 ns (12 allocations: 896 bytes)
@btime diffs_row($X, $Y) # 463.131 ns (11 allocations: 784 bytes)
我正在尝试将以下 Python 代码(来自 SMT GEKPLS)的等价物翻译成 Julia:
def differences(X, Y):
D = X[:, np.newaxis, :] - Y[np.newaxis, :, :]
return D.reshape((-1, X.shape[1]))
所以,给定这样的输入:
X = np.array([[1.0,1.0,1.0], [2.0,2.0,2.0]])
Y = np.array([[1.0,2.0,3.0], [4.0,5.0,6.0], [7.0,8.0,9.0]])
diff = differences(X,Y)
我们得到如下所示的输出(差异):
[[ 0. -1. -2.]
[-3. -4. -5.]
[-6. -7. -8.]
[ 1. 0. -1.]
[-2. -3. -4.]
[-5. -6. -7.]]
使用 Julia 代码执行此操作的有效方法是什么?我希望 X 和 Y 输入矩阵非常大。
经过一番思考,得出了这个函数:
function differences(X, Y)
Rx = repeat(X, inner=(size(Y, 1), 1))
Ry = repeat(Y, size(X, 1))
Rx - Ry
end
希望对您有所帮助。
这是一个避免 repeat
的版本,它会产生不必要的数据重复:
function diffs_row(X, Y)
N = size(X, 2)
return reshape(reshape(X', 1, N, :) .- Y', N, :)'
end
所有伴随词 '
的原因是在 Julia 中操作 row-wise 并不是很自然。 Julia 数组是 column-major,因此 reshape
将检索数据 column-wise。如果您决定改为更改数据的方向,您可以写
function diffs_col(X, Y)
N = size(X, 1)
return reshape(reshape(X, N, 1, :) .- Y, N, :)
end
相反。
人们在将 numpy 代码翻译成 Julia 时经常看到这一点。 Numpy 是原生的 row-major,所以翻译起来有点别扭。在许多情况下,您应该考虑将数据布局更改为主要列。
这可能比其他替代方案更快,同时仍然易于理解。
[x .- y for x ∈ X for y ∈ Y]
6-element Vector{Vector{Float64}}:
[0.0, -1.0, -2.0]
[-3.0, -4.0, -5.0]
[-6.0, -7.0, -8.0]
[1.0, 0.0, -1.0]
[-2.0, -3.0, -4.0]
[-5.0, -6.0, -7.0]
我不喜欢 numpy
的一件事是,必须准确记住每个函数以及输入参数的组合。在 Julia 中,传统循环可以作为大多数算法的有效 drop-in 替代。
附录: 以上可能是我所说的最快的解决方案,前提是使用 Vector{Vector{Float64}}
不是问题。如果是,这是另一个输出 Matrix{Float64}
同时速度也很快的解决方案。
function diffr(X,Y)
i, l, m, n = 0, length(first(X)), length(X), length(Y)
Z = Matrix{Float64}(undef, m*n, l)
for x in X, y in Y
Z[i+=1,:] .= x .- y
end
Z
end
这里是我电脑上所有已发布解决方案的性能比较。
@btime [x.-y for x∈$X for y∈$Y] # 312.245 ns (9 allocations: 656 bytes)
@btime diffr($X, $Y) # 73.868 ns (1 allocation: 208 bytes)
@btime differences($X, $Y) # 439.000 ns (12 allocations: 896 bytes)
@btime diffs_row($X, $Y) # 463.131 ns (11 allocations: 784 bytes)