【问题标题】:Why slice of row vector does not return row vector?为什么行向量的切片不返回行向量?
【发布时间】:2021-03-29 04:37:08
【问题描述】:

我刚开始学习 Julia。请问如何让行向量的切片返回行向量?

我搜索并找不到答案。

在 Matlab 中,获取行向量的切片会按预期返回行向量。但在 Julia 中,它返回一个数组。版本 1.5.3 (2020-11-09)

>julia
julia> x=[1 2 3 4 5 6]
1×6 Array{Int64,2}:
 1  2  3  4  5  6

julia> x[1:4]
4-element Array{Int64,1}:
 1
 2
 3
 4

在 Matlab 中

>> x=[1 2 3 4 5 6 7]
>> x(1:4)

ans =

     1     2     3     4

Julia 中执行此操作的正确方法是什么?即行向量切片返回行向量,列向量切片返回列向量。

【问题讨论】:

  • Matlab 的一般规则的例外实际上是真的令人着迷!

标签: matlab julia


【解决方案1】:

你所拥有的不是行向量,而是形状为 1x6 的矩阵,即二维数组。如果您有兴趣深入了解 Julia 中向量是如何处理的,您可以阅读这个问题:https://github.com/julialang/julia/issues/4774,它被称为“认真对待向量转置”。你可以看到这个设计花了很多心思。

Julia 切片将以可预测的方式丢弃维度:输出的维度数等于输入索引的维度总和。在您的情况下,x[1:4],输入索引切片是 1D,因此输出是 1D。如果希望输出为 2D,则需要 1D+1D=2D 输入索引:

jl> x[1:1, 1:4]
1×4 Matrix{Int64}:
 1  2  3  4

请注意,以下生成一维数组

jl> x[1, 1:4]
4-element Vector{Int64}:
 1
 2
 3
 4

那是因为第一个索引是一个标量,是0维的,所以输出是0D+1D=1D。

这甚至保留用于空数组:

jl> x[1:0, 1:4]
0×4 Matrix{Int64}

仍然是一个矩阵,即使它的大小为 0x4。

您还应该知道,在大多数情况下,您应该更喜欢正确的向量:[1, 2, 3, 4, 5, 6] 而不是 1xN 矩阵,[1 2 3 4 5 6]

【讨论】:

【解决方案2】:

简短而令人怀疑:

y = x[1:4]'

更长且更具教育意义: 如果你密切关注

的输出
x = [1 2 3 4 5 6]

你会看到数组(!)的条件是两个:

1×6 Array{Int64,2}:
 1  2  3  4  5  6

也就是说,因为您没有将元素收集在列中,而是将其强制为一行。要有效地使用 julia,请尝试使用列向量,如

y = [1,2,3,4,5,6]

或者更多的依赖julias的功能和使用

z = collect(1:6)

Julia 使用列优先布局。数组的每一列都是一个连续的内存区域。这使得对列的操作比对行的操作更快。其他语言可能有不同的布局。事实上,FORTRAN 和 MatLab 也使用列优先数组。另一方面,C 编程语言使用行主要布局。

编辑:显然我在写作时迷路了。 我相信julia 中的正确方法是在列向量中完成所有操作。肯定有一些代数是不可能的。但是对于大多数程序来说,向量的方向无关紧要。因此,在 julia 中使用列向量。

【讨论】:

  • collect 范围 1:6 没有特别的原因。在几乎所有情况下,它都表现得像一个普通的向量,但更轻量级和更快。如果你需要改变它,你真的只需要collect
【解决方案3】:

正如@2419 所写,x=[1 2 3 4 5 6] 所得到的实际上是一个单行矩阵,而 Julia 使用列向量的性能更高。

也就是说,矩阵当然有合法用途;-)

长话短说..当您有一个矩阵并将其切片以使结果为行时,它会自动转换为列向量:

julia> x = [1 2 3 4; 10 20 30 40; 100 200 300 400]
3×4 Matrix{Int64}:
   1    2    3    4
  10   20   30   40
 100  200  300  400

julia> a = x[2,:]
4-element Vector{Int64}:
 10
 20
 30
 40

但是,如果将其分割为 2 行或更多行,它仍然是一个矩阵:

julia> b = x[[2,3],:]
2×4 Matrix{Int64}:
  10   20   30   40
 100  200  300  400

我对这个选择感到有些困惑,但就是这样,现在不会改变。 请注意,使用第一种情况检索行向量非常容易:

julia> transpose(a) # or, equivalently, `a'`
1×4 transpose(::Vector{Int64}) with eltype Int64:
 10  20  30  40

重要! transpose 是一种矩阵运算,仅适用于数值矩阵(或向量)。 如果您的矩阵包含非数字元素(如字符串),transpose 会产生错误,您应该改用permutedims

julia> x2 = [1 2 "c" 4; 10 20 "cc" 40; 100 200 300 "ddd"]
3×4 Matrix{Any}:
   1    2     "c"    4
  10   20     "cc"  40
 100  200  300        "ddd"

julia> a2 = x2[2,:]
4-element Vector{Any}:
 10
 20
   "cc"
 40

julia> transpose(a2)
1×4 transpose(::Vector{Any}) with eltype Any:
Error showing value of type LinearAlgebra.Transpose{Any, Vector{Any}}:
ERROR: MethodError: no method matching transpose(::String)
# [...]

julia> permutedims(a2)
1×4 Matrix{Any}:
 10  20  "cc"  40

不过transpose 更快:

julia> using BenchmarkTools
julia> @btime transpose(a)
  21.971 ns (1 allocation: 16 bytes)
1×4 transpose(::Vector{Int64}) with eltype Int64:
 10  20  30  40

julia> @btime permutedims(a)
  66.289 ns (2 allocations: 96 bytes)
1×4 Matrix{Int64}:
 10  20  30  40

所以,如果你确定你的矩阵是数字的,使用transpose,否则使用permutedims

【讨论】:

  • 一些吹毛求疵:首先,决定它是向量还是矩阵的不是输出行数,而是索引表达式的类型。所以x[1, 1:4] 是一个向量,x[1:1, 1:4] 是一个矩阵,即使它只有一行。一致性和类型稳定性是此设计的关键。其次,转置对向量和矩阵都有效,而不仅仅是矩阵。
  • 是的,你是对的。我不想介绍“数组”这个词,我试图区分的是数字数组和非数字数组(已编辑)。
  • 哦,还有一件事。 transpose 实际上是一个惰性操作,基本上需要零时间。您可以看到,如果将变量插入基准表达式:@btime transpose($a)(注意$)。您通常应该在 BenchmarkTools 中使用插值。
猜你喜欢
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 2023-03-29
  • 2018-11-06
相关资源
最近更新 更多