Repository: JuliaAI/MLJBase.jl
Pull request #655 (2021-10-01 04:33:22)

Improve sampler object display
#273


Patch:
diff --git a/src/hyperparam/one_dimensional_range_methods.jl b/src/hyperparam/one_dimensional_range_methods.jl
index 25edeae0..06027efc 100644
--- a/src/hyperparam/one_dimensional_range_methods.jl
+++ b/src/hyperparam/one_dimensional_range_methods.jl
@@ -269,12 +269,20 @@ end
 
 ### Numeric case
 
-struct NumericSampler{T,D<:Distributions.Sampleable,S} <: MLJType
+struct NumericSampler{T,D<:Distributions.Sampleable,S}
     distribution::D
     scale::S
     NumericSampler(::Type{T}, d::D, s::S) where {T,D,S} = new{T,D,S}(d,s)
 end
 
+function Base.show(stream::IO,
+                   s::NumericSampler{T,D}) where {T,D}
+    repr = "NumericSampler{$T,$D}}"
+    s.scale isa Symbol || (repr = "transformed "*repr)
+    print(stream, repr)
+    return nothing
+end
+
 # constructor for distribution *instances*:
 """
     sampler(r::NominalRange, probs::AbstractVector{<:Real})
@@ -389,6 +397,15 @@ struct NominalSampler{T,N,D<:Distributions.Sampleable} <: MLJType
         new{T,N,D}(d, values)
 end
 
+function Base.show(stream::IO,
+                   s::NominalSampler{T,N,D}) where {T,N,D}
+    samples = round3.(s.values)
+    seqstr = sequence_string(s.values)
+    repr = "NominalSampler($seqstr)"
+    print(stream, repr)
+    return nothing
+end
+
 # constructor for probability vectors:
 function Distributions.sampler(r::NominalRange{T},
                  probs::AbstractVector{<:Real}) where T
diff --git a/src/hyperparam/one_dimensional_ranges.jl b/src/hyperparam/one_dimensional_ranges.jl
index 3abf7525..16961b34 100644
--- a/src/hyperparam/one_dimensional_ranges.jl
+++ b/src/hyperparam/one_dimensional_ranges.jl
@@ -36,7 +36,7 @@ function Base.show(stream::IO,
     if r.scale isa Symbol
         r.scale !== :linear && (repr *= " on $(r.scale) scale")
     else
-        repr *= " on non-linear scale"
+        repr = "transformed "*repr
     end
     print(stream, repr)
     return nothing
@@ -46,10 +46,8 @@ function Base.show(stream::IO,
 #                   ::MIME"text/plain",
                    r::NominalRange{T}) where T
     fstr = string(r.field)
-    values_str = join(string.(r.values), ", ")
-    suffix = length(r.values) > 3 ? ", ..." : ""
-    values_str *= suffix
-    repr = "NominalRange($fstr = $values_str)"
+    seqstr = sequence_string(collect(r.values))
+    repr = "NominalRange($fstr = $seqstr)"
     print(stream, repr)
     return nothing
 end
diff --git a/src/utilities.jl b/src/utilities.jl
index 4810beb3..98afc535 100644
--- a/src/utilities.jl
+++ b/src/utilities.jl
@@ -220,6 +220,44 @@ function short_string(v::Vector)
     return "[$middle]"
 end
 
+"""
+    sequence_string(itr, n=3)
+
+Return a "sequence" string from the first `n` elements generated
+by `itr`.
+
+    sequence_string(1:10, 3)
+
+**Private method.**
+
+"""
+function sequence_string(itr::Itr, n=3) where Itr
+    n > 1 || throw(ArgumentError("Cutoff must be at least 2. "))
+    I = Base.IteratorSize(Itr)
+    I isa Base.HasLength ||
+        I isa Base.HasShape ||
+        I isa IsInfinite ||
+        throw(Argumenterror("Unsupported iterator. "))
+    vals = typeof(first(itr))[]
+    i = 0
+    earlystop = false
+    for x in itr
+        i += 1
+        if i === n + 1
+            earlystop = true
+            break
+        else
+            push!(vals, x)
+        end
+    end
+    ret = join(vals, ", ")
+    earlystop && (ret *= ", ...")
+    return ret
+end
+
+
+## UNWINDING ITERATORS
+
 """
     unwind(iterators...)
 


Test patch:
diff --git a/test/resampling.jl b/test/resampling.jl
index 8f085b93..35738ffb 100644
--- a/test/resampling.jl
+++ b/test/resampling.jl
@@ -4,7 +4,7 @@ using Distributed
 import ComputationalResources: CPU1, CPUProcesses, CPUThreads
 using .TestUtilities
 using ProgressMeter
-using Tables: table
+import Tables
 
 @everywhere begin
     using .Models
@@ -486,7 +486,7 @@ end
 
 @testset_accelerated "class weights in evaluation" accel begin
     x = [1,2,3,4,5,6,7]
-    X, y = table([x x x x x x]), coerce([1,2,1,3,1,2,2], Multiclass)
+    X, y = Tables.table([x x x x x x]), coerce([1,2,1,3,1,2,2], Multiclass)
     model = Models.DeterministicConstantClassifier()
     mach = machine(model, X, y)
     cv=CV(nfolds = 2)
@@ -709,7 +709,7 @@ end
     end
 
     x = [1,2,3,4,5,6,7]
-    X, y = table([x x x x x x]), coerce([1,2,1,3,1,2,2], Multiclass)
+    X, y = Tables.table([x x x x x x]), coerce([1,2,1,3,1,2,2], Multiclass)
     model = Models.DeterministicConstantClassifier()
     class_w = Dict(zip(levels(y), rand(length(levels(y)))))
 
diff --git a/test/utilities.jl b/test/utilities.jl
index 190cf052..77c87fff 100644
--- a/test/utilities.jl
+++ b/test/utilities.jl
@@ -66,7 +66,7 @@ end
 
     x = 1:5 |> collect
     y = 1:5 |> collect
-    
+
     # In the following tests it is crucial to recreate a new `RNG` each time.
     perm = Random.randperm(StableRNG(11900), 5)
     @test MLJBase.shuffle_rows(x, y; rng=StableRNG(11900)) == (x[perm], y[perm])
@@ -129,5 +129,12 @@ end
     @test MLJBase.available_name(Utilities, :orange) == :orange3
 end
 
+@testset "sequence_string" begin
+    @test MLJBase.sequence_string(1:10, 2) == "1, 2, ..."
+    @test MLJBase.sequence_string(1:10) == "1, 2, 3, ..."
+    @test MLJBase.sequence_string(1:3) == "1, 2, 3"
+    @test MLJBase.sequence_string(1:2) == "1, 2"
+end
+
 end # module
 true