Using Weights from statsbase in Julia, and using an array

Hi I am new to Julia, and I am trying to play with it a bit.

Consider this function:

function drawValues(fromDistribution, byCount)

fromDistribution : 
    A 2D array
    Each element is an array with two elements
    The first one is a value, and the second one is the probability of that value
    We will draw a value out of this distribution from a random number generator
byCount :
    An integer
    We draw that many values from the source distribution


values = []
wts    = []

for i = 1:length(fromDistribution)
    push!(values, fromDistribution[i][1])
    push!(wts   , fromDistribution[i][2])

w = Weights(wts)

res = []

for i = 1:byCount
    r = sample(values, w)
    push!(res, r)

plot(values, wts)


This throws the error :

ERROR: MethodError: no method matching Weights(::Array{Any,1}, ::Float64) Closest candidates are: Weights(::var"#18#V", ::var"#16#S") where {var"#16#S"<:Real, var"#17#T"<:Real, var"#18#V"<:AbstractArray{var"#17#T",1}} at /home/hedgehog/.julia/packages/StatsBase/EA8Mh/src/weights.jl:13
Weights(::Any) at /home/hedgehog/.julia/packages/StatsBase/EA8Mh/src/weights.jl:16 Stacktrace: [1] Weights(::Array{Any,1}) at /home/hedgehog/.julia/packages/StatsBase/EA8Mh/src/weights.jl:16 [2] drawValues(::Array{Array{Float64,1},1}, ::Int64) at /home/hedgehog/LASER.jl:51 [3] top-level scope at REPL[13]:1 [4] run_repl(::REPL.AbstractREPL, ::Any) at /build/julia/src/julia-1.5.3/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

It seems, that the second definition ( Weights(::Array{Any,1}) ) whould fit. But somehow Julia sees two input arguments?

Please help.

Versioninfo :

Julia Version 1.5.3
Commit 788b2c77c1* (2020-11-09 13:37 UTC)
Platform Info:
OS: Linux (x86_64-pc-linux-gnu)
CPU: AMD Ryzen 7 3700X 8-Core Processor
LIBM: libopenlibm
LLVM: libLLVM-10.0.1 (ORCJIT, znver2)

Welcome to the community! When posting it is generally helpful to make your example self contained, so that other people can reproduce the error you’re seeing. In this case, I assume this would have meant including the packages you are using (StatsBase?) as well as an example of how you construct fromDistribution.

I assume this is a learning exercise, as sampling n values from a collection with weights w is already implemented in StatsBase:

julia> using StatsBase

julia> sample(1:10, Weights(rand(10)), 5)
5-element Vector{Int64}:

Without being able to run your code though I think your problem is (maybe somewhat confusingly) that you are using an untyped array Any to construct your weights. Consider:

julia> Weights([1,2,3])
3-element Weights{Int64, Int64, Vector{Int64}}:

julia> Weights(Any[1, 2, 3])
ERROR: MethodError: no method matching Weights(::Vector{Any}, ::Int64)
Closest candidates are:
  Weights(::var"#6#V", ::var"#4#S") where {var"#4#S"<:Real, var"#5#T"<:Real, var"#6#V"<:AbstractVector{var"#5#T"}} at /home/nils/.julia/packages/StatsBase/EA8Mh/src/weights.jl:13
  Weights(::Any) at /home/nils/.julia/packages/StatsBase/EA8Mh/src/weights.jl:16
 [1] Weights(vs::Vector{Any})
   @ StatsBase ~/.julia/packages/StatsBase/EA8Mh/src/weights.jl:16
 [2] top-level scope
   @ none:1

In the first example, I use a vector of Int64 (Julia infers the type automatically when constructing the array, as all elements are Int64), while in the second example I force the array to be of type Any. This is what you are implicitly doing when you instantiate your wts vector with []:

julia> []

push!ing to this afterwards won’t change the type of the container, so you end up passing a Vector{Any} to the weights constructor, which fails as you see above.

I’m not all that familiar with the internals of StatsBase, but it seems the confusion comes from Weights(::Array{Any, 1}) being allowed, but then calling Weights(<:AbstractVector{T}, <:Real) in the next step, so the method error is one step removed from the call that the user makes. You can see this in the source when you do @edit Weights(wts), but again it’s a bit opaque as the constructor itself is created from a macro.

Actually there’s no Weights(::Array{Any,1}). What you see in the stacktrace is the fact that you passed an Array{Any} to the Weigths(::Any) method. But I agree this would be clearer if the single-argument method throwed the error. See:

1 Like