在Julia中从R中复制`expand.grid`函数

bttbmeg0  于 2023-07-31  发布在  其他
关注(0)|答案(5)|浏览(141)

expand.gridR中一个非常方便的函数,用于计算多个列表的所有可能组合。它的工作原理如下:

> x = c(1,2,3)
> y = c("a","b")
> z = c(10,12)
> d = expand.grid(x,y,z)
> d
   Var1 Var2 Var3
1     1    a   10
2     2    a   10
3     3    a   10
4     1    b   10
5     2    b   10
6     3    b   10
7     1    a   12
8     2    a   12
9     3    a   12
10    1    b   12
11    2    b   12
12    3    b   12

字符串
如何在Julia中重现此函数?

mrzz3bfm

mrzz3bfm1#

感谢@Henrik的评论:

x = [1,2,3]
y = ["a","b"]
z = [10,12]
d = collect(Iterators.product(x,y,z))

字符串
下面是使用列表理解的另一个解决方案

reshape([ [x,y,z]  for x=x, y=y, z=z ],length(x)*length(y)*length(z))

a64a0gku

a64a0gku2#

这里是我的完全(?)一般解决方案,使用递归、varargs和splatting:

function expandgrid(args...)
    if length(args) == 0
        return Any[]
    elseif length(args) == 1
        return args[1]
    else
        rest = expandgrid(args[2:end]...)
        ret  = Any[]
        for i in args[1]
            for r in rest
                push!(ret, vcat(i,r))
            end
        end
        return ret
    end
end

eg = expandgrid([1,2,3], ["a","b"], [10,12])
@assert length(eg) == 3*2*2
@show eg

字符串
这给出了一个数组的数组,但是如果你想的话,你可以把它简单地组合成一个矩阵。

oymdgrw7

oymdgrw73#

我知道这是一个相当老的问题,但我也确实将expand.grid函数从R转换为Julia,几乎是在找到这篇文章的前几天一行一行地转换。对于某些人来说,它仍然很有趣,因为它返回一个DataFrame,这可能更方便。下面是link to the Gist,下面是以防万一的代码:

using DataFrames

"""
Create a Data Frame from All Combinations of Factor Variables (see R's base::expand.grid)
# Arguments
... Array, Dict, or Tuple containing at least one value
# Return
A DataFrame containing one row for each combination of the supplied argument. The first factors vary fastest.
# Examples
```julia
expand_grid([1,2],["owl","cat"])
expand_grid((1,2),("owl","cat"))
expand_grid((1,2)) # -> Returns a DataFrame with 2 rows of 1 and 2.

"""
function expand_grid(args...)
nargs= length(args)

if nargs == 0
  error("expand_grid need at least one argument")
end

iArgs= 1:nargs
nmc= "Var" .* string.(iArgs)
nm= nmc
d= map(length, args)
orep= prod(d)
rep_fac= [1]
# cargs = []

if orep == 0
    error("One or more argument(s) have a length of 0")
end

cargs= Array{Any}(undef,orep,nargs)

for i in iArgs
    x= args[i]
    nx= length(x)
    orep= Int(orep/nx)
    mapped_nx= vcat(map((x,y) -> repeat([x],y), collect(1:nx), repeat(rep_fac,nx))...)
    cargs[:,i] .= x[repeat(mapped_nx,orep)]
    rep_fac= rep_fac * nx
end

convert(DataFrame,cargs)

end

字符串
fiei3ece

fiei3ece4#

我知道这是一个老问题,但如果有人仍然在寻找一个像R expand.grid函数一样工作的解决方案(即传递一个任意类型的命名变量列表,并返回一个 Dataframe ,其中变量名作为列名,每列都是原始变量的类型,以及不同变量的所有可能组合),这是我的Julia新手尝试:

using DataFrames

function expand_grid(; iters...)
    var_names = collect(keys(iters))
    var_itr = [1:length(x) for x in iters.data]
    var_ix = vcat([collect(x)' for x in Iterators.product(var_itr...)]...)
    out = DataFrame()
    for i = 1:length(var_names)
        out[:,var_names[i]] = collect(iters[i])[var_ix[:,i]]
    end
    return out
end

expand_grid(a=1:2, b=1.0:5.0, c=["one", "two", "three", "four"])

字符串
很可能有一种更有效或更干净的方法来做到这一点,但这是我能想到的最好的方法,它能给予我从R函数中所期望的。

x4shl7ld

x4shl7ld5#

using DataFrames

function expand_grid(; kw...)
  values = [v for (_, v) in kw]
  names = keys(kw) |> collect
  DataFrame(collect(Iterators.product(values...))[:], names)
end

julia> dims = (x = 1:2, y = [3, 4], z = ["a", "b", "c"]);

julia> expand_grid(;dims...)
12×3 DataFrame
 Row │ x      y      z      
     │ Int64  Int64  String 
─────┼──────────────────────
   1 │     1      3  a
   2 │     2      3  a
   3 │     1      4  a
   4 │     2      4  a
   5 │     1      3  b
   6 │     2      3  b
   7 │     1      4  b
   8 │     2      4  b
   9 │     1      3  c
  10 │     2      3  c
  11 │     1      4  c
  12 │     2      4  c

字符串

相关问题