Map over combinations of parameters, and grouping results as DataFrame

I’ve noticed that reduce has an optional source argument specifically to keep track of each block. With this, I now have the following wrapper:


function expand_grid(; kws...)
    names, vals = keys(kws), values(kws)
    return DataFrame(NamedTuple{names}(t) for t in Iterators.product(vals...))
end

function mymodel(;x = range(0, 10, length = 100), a = 1, b = 1, c = 2, fun = sin, kws...)
    DataFrame(x = x, y = a .* sin.(b .* x) .+ c, z = a .* fun.(b .* x) .+ c)
end

function pmap_df(p, f, kws...; join=true)
   tmp = map(f, eachrow(p), kws...)
   all = reduce(vcat, tmp, source="id")
   if !join
    return all
   end
   p[!, :id] = 1:nrow(p)
   return DataFrames.leftjoin(p, all, on=:id)
end

params = expand_grid(a=[0.1,0.2,0.3], b = [1,2,3], c = [0,0.5]);

pmap_df(params, p -> mymodel(;p..., fun=tanh))

That’s pretty close to what I was after; I’d still like to merge the map+reduce steps with mapreduce, but I’m not sure how to pass extra arguments to reduce. Any idea?