朱莉娅:大型数组的有限打印

13

我使用Julia的脚本文件生成了许多大型数组。打印整个数组很麻烦,但我想检查前几行是否合理。

我知道在REPL中有一个打印功能,它受屏幕大小限制,例如:

julia> zeros(1000,10)
1000×10 Array{Float64,2}:
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
⋮                        ⋮                      
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

但我在基本的Julia中找不到任何打印/显示函数来模仿这个过程,比如仅仅打印出数组的前10行或类似R的head(我原本期望showcompact能做到这一点)。

是否有类似于R的head的函数在Julia中或者我必须自己写一个。


你应该使用IOContext来完成这个任务。 - Fengyang Wang
1
Julia >=1.6: first(x, 1) 是你的 head 等价物,而 last(x, 1) 则是你的 tail 等价物。请参阅:https://docs.julialang.org/en/v1/base/collections/#Base.first - PatrickT
4个回答

22

如我在评论中提到的那样,在v0.5中实现此操作的方法是使用IOContext

限制数据的一个非常简单的方法是将:limit => true参数传递给IOContext

julia> show(IOContext(stdout, :limit => true), v)
[0.147959 0.4140180.595528 0.852563; 0.32679 0.8249530.432143 0.036279; … ; 0.877398 0.6618540.197207 0.15596; 0.0522946 0.5080750.835359 0.705987]

但是这样输出的结果并不像REPL一样;因为show函数使用两个参数时会以单行显示。若要使用多行显示,请将show函数的第二个参数设为text/plain (一种MIME类型):

julia> show(IOContext(stdout, :limit => true), "text/plain", v)
100×100 Array{Float64,2}:
 0.147959   0.414018   0.0282934  …  0.816132   0.595528   0.852563 
 0.32679    0.824953   0.0582351     0.822526   0.432143   0.036279 
 0.754989   0.724317   0.533966      0.987273   0.931932   0.973622 
 0.547866   0.282694   0.0295411     0.75929    0.886218   0.0813057
 0.0626663  0.111795   0.625083      0.439983   0.562143   0.669046 
 0.712093   0.469622   0.377298   …  0.298224   0.31853    0.376066 
 0.774625   0.754328   0.756725      0.61113    0.76566    0.999292 
 0.917846   0.308363   0.489246      0.715311   0.175302   0.124059 
 0.310922   0.140575   0.20635       0.0280192  0.683004   0.168129 
 0.753361   0.755103   0.831806      0.118009   0.122374   0.281476 
 ⋮                                ⋱                                 
 0.420264   0.7614     0.748408      0.330983   0.0776789  0.309464 
 0.984379   0.851735   0.595121      0.534982   0.255317   0.743713 
 0.814505   0.765941   0.71852       0.730677   0.477631   0.0360992
 0.910384   0.0747604  0.490685      0.0904559  0.0756424  0.313898 
 0.628416   0.0790874  0.401488   …  0.523521   0.397249   0.58112  
 0.578361   0.336352   0.261118      0.838256   0.387374   0.451647 
 0.66724    0.586342   0.378968      0.602694   0.450686   0.901279 
 0.877398   0.661854   0.685156      0.658952   0.197207   0.15596  
 0.0522946  0.508075   0.244423      0.95935    0.835359   0.705987 

您当然可以通过向IOContext传递:displaysize来更改显示的行数:

julia> show(IOContext(stdout, :limit => true, :displaysize => (10, 10)), "text/plain", v)

100×100 Array{Float64,2}:
 0.1479590.852563
 0.32679       0.036279
 0.754989      0.973622
 ⋮          ⋱          
 0.877398      0.15596 
 0.0522946     0.705987

总的来说,IOContext非常灵活。详情请参见其文档


这正是我想要的。谢谢! - Jack
这是我见过的第一个易懂的IOContext示例。+100! - David P. Sanders

4
你可以轻松地自己定义一个 head 函数。对于一维和二维,这相当简单:
torange(n::Integer, m) = 1:min(n, m)
torange(c::Colon, m) = (:)

function head(a::AbstractArray{TypeVar(:T), 1}, n = 10)
    view(a, torange(n,size(a,1)))
end


function head(a::AbstractArray{TypeVar(:T), 2}, n1 = 10, n2 = 10)
        view(a, torange(n1, size(a,1)), torange(n2, size(a,2)))
end

torange方法允许使用:返回相应维度的完整长度。例如:

head(zeros(10, 10), 5, :)
5×10 SubArray{Float64,2,Array{Float64,2},Tuple{UnitRange{Int64},Colon},false}:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

对于两个以上的维度,我选择从第三个参数开始重复最后一个参数:

function head{Na, Nn}(a::AbstractArray{TypeVar(:T), Na}, n1 = 10, n2 = 10, ns::Vararg{TypeVar(:T), Nn} = 2)
        nend = last(ns)
        view(a, torange(n1, size(a,1)), torange(n2, size(a,2)), (torange(ns[i], size(a,i+2)) for i = 1:Nn)..., (torange(nend, size(a, i)) for i in Nn+3:Na)...)
end

例如:

head(rand(10, 10, 5, 5), 3, 3, 2)  # the last two is the default value and can be omitted
3×3×2×2 SubArray{Float64,4,Array{Float64,4},Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}},false}:
[:, :, 1, 1] =
 0.384724  0.7328   0.585211
 0.738284  0.95145  0.362914
 0.43928   0.94307  0.758541

[:, :, 2, 1] =
 0.78603   0.588877  0.677201
 0.559547  0.800559  0.488433
 0.993593  0.691884  0.236595

[:, :, 1, 2] =
 0.25732   0.90491   0.323905
 0.300924  0.703919  0.813316
 0.040522  0.776142  0.624097

[:, :, 2, 2] =
 0.746677   0.153574   0.155539 
 0.991624   0.90167    0.0880094
 0.0423263  0.0153597  0.0608328

请注意,n维版本不是类型稳定的,但这对打印输出并不重要。

啊,这是一个不错的做法。你知道在Julia中是否有一个基本方法可以进行有限的打印吗? - Jack
我不知道。如果在脚本或会话开始时可以为每个维度设置默认的头部和尾部最大打印长度,那就太好了。 - tim
Julia 1.6+ 中,您可以使用 first(x, 10)last(x, 10) - PatrickT

4
我们可以使用display()来获得与REPL相同的输出(这是您要查找的内容吗...?)此外,可以通过使用数组部分来打印“head”和“tail”部分,例如,
disp( x ) = ( display(x) ; println() ; println() )

A = diagm( [ i for i=1:100 ] )

disp( A )
disp( A[ 1:5, : ] )         # head
disp( A[ end-4:end, : ] )   # tail

B = [ i for i=1:100 ]

disp( B )
disp( B[ 1:5 ] )         # head
disp( B[ end-4:end ] )   # tail

$ julia test.jl

100x100 Array{Int64,2}:
 1  0  0  0  0  0  0  0  0   0  0  0  …  0   0   0   0   0   0   0   0    0
 0  2  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  3  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  4  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  5  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  6  0  0  0   0  0  0  …  0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  7  0  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  8  0   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  9   0  0  0      0   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0  10  0  0      0   0   0   0   0   0   0   0    0
 ⋮              ⋮               ⋮     ⋱                   ⋮                 
 0  0  0  0  0  0  0  0  0   0  0  0     92   0   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0  93   0   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0  94   0   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0  95   0   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0  …  0   0   0   0  96   0   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0  97   0   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0  98   0    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0  99    0
 0  0  0  0  0  0  0  0  0   0  0  0      0   0   0   0   0   0   0   0  100

5x100 Array{Int64,2}:
 1  0  0  0  0  0  0  0  0  0  0  0  0  … 0  0  0  0  0  0  0  0  0  0  0  0
 0  2  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  3  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  4  0  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0
 0  0  0  0  5  0  0  0  0  0  0  0  0     0  0  0  0  0  0  0  0  0  0  0  0

5x100 Array{Int64,2}:
 0  0  0  0  0  0  0  0  0  0  0  0  0  … 0  0  0  0  0  96   0   0   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0  97   0   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0  98   0    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0   0  99    0
 0  0  0  0  0  0  0  0  0  0  0  0  0     0  0  0  0  0   0   0   0   0  100

100-element Array{Int64,1}:
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
   ⋮
  92
  93
  94
  95
  96
  97
  98
  99
 100

5-element Array{Int64,1}:
 1
 2
 3
 4
 5

5-element Array{Int64,1}:
  96
  97
  98
  99
 100

谢谢,我想这是最好的选择,不过像Tim说的那样,设置默认的最大打印长度会很好。 - Jack
是的,我同意,并且我还编写了一个自定义的漂亮打印程序,具有更多的控制。但对于简单的情况,display() 对我来说就足够了。 - roygvib
虽然我似乎无法像你一样使用“...”符号获得“自动限制”。我正在使用Julia 0.5。所以我只能尝试定义自己的函数。 - Jack
哦,对了,如果我使用v0.5版本,我不会得到那种“…”的东西,而是会得到完整的数字列表……(上面的测试中我使用的是v0.4.7版本)。嗯… - roygvib
啊,是啊,也许这是v0.5的问题!最好在GitHub上提出这个问题... - Jack

2

我认为这个主题已经过时了。在我的julia v1.4.1中,display函数不会打印有限的数组。

a = zeros(1000,6)
show(IOContext(STDOUT, limit=true), "text/plain", a)

产生错误。相反,我发现这个有效。
a = zeros(1000,6)
show(IOContext(stdout, :limit => true), "text/plain", a)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接