簡體   English   中英

在 Julia 中從 R 重現 `expand.grid` 函數

[英]Reproduce the `expand.grid` function from R in Julia

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 中重現此功能?

感謝@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))

這是我的完全(?)通用解決方案,使用遞歸、可變參數和 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

這給出了一個數組數組,但如果這是你想要的,你可以簡單地將它組合成一個矩陣。

我知道這是一個相當老的問題,但我也確實在找到這篇文章前幾天幾乎一行一行地將 expand.grid 函數從 R 轉換為 Julia ......它對某人來說仍然很有趣,因為它返回一個DataFrame ,它可以更方便。 這是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 新手嘗試:

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 函數中得到我所期望的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM