在 Julia 中重现 R 中的“expand.grid”函数
Reproduce the `expand.grid` function from R in Julia
expand.grid
是 R
中一个非常方便的函数,用于计算多个列表的所有可能组合。它是这样工作的:
> 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 中重现此函数?
这是我完全(?)通用的解决方案,使用递归、可变参数和展开:
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
这给出了一个数组数组,但如果您想要的话,您可以简单地将其组合成一个矩阵。
感谢@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))
我知道这是一个相当古老的问题,但在找到这个 post 之前的几天,我也几乎逐行地将 expand.grid 函数从 R 转换为 Julia...
它对某些人来说仍然很有趣,因为它 returns 一个 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
我知道这是一个老问题,但如果有人仍在寻找像 R expand.grid 函数一样工作的解决方案(即传递任何类型的命名变量列表并返回数据框作为列名的变量名,原始变量类型的每一列,以及不同变量的所有可能组合),这是我的 Julia-newbie 尝试:
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 函数的期望。
expand.grid
是 R
中一个非常方便的函数,用于计算多个列表的所有可能组合。它是这样工作的:
> 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 中重现此函数?
这是我完全(?)通用的解决方案,使用递归、可变参数和展开:
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
这给出了一个数组数组,但如果您想要的话,您可以简单地将其组合成一个矩阵。
感谢@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))
我知道这是一个相当古老的问题,但在找到这个 post 之前的几天,我也几乎逐行地将 expand.grid 函数从 R 转换为 Julia...
它对某些人来说仍然很有趣,因为它 returns 一个 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
我知道这是一个老问题,但如果有人仍在寻找像 R expand.grid 函数一样工作的解决方案(即传递任何类型的命名变量列表并返回数据框作为列名的变量名,原始变量类型的每一列,以及不同变量的所有可能组合),这是我的 Julia-newbie 尝试:
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 函数的期望。