广播,多个n * m返回而不是n * m元素[Julia 1.0]

问题描述 投票:0回答:2

假设我想编写一个需要任何长度的数组作为参数输入的函数:例如,

f = function(x,y) 
  z = x * y
  outputs = DataFrame(x = x, y = y, z = z)
  return(outputs)
end

返回,f.([1,2],[1,2])是一个包含两个1x3 DataFrame的2元素数组。但是,在这种情况下,我想要一个2x3 DataFrame。

我可以通过在嵌套for循环之前定义z来实现这一点:

f = function(x,y)
  z=fill(0,length(x))
  for i in 1:length(x)
   z[i] = x[i] * y[i]
  end
  outputs = DataFrame(x = x, y = y, z = z)
  return(outputs)
end

在这里,f([1,2],[1, 2])得到了我想要的东西。但是,问题是我必须两次定义所有函数内变量并添加for循环,同时记住包含迭代变量i。有什么我想念的吗?我的问题是,我如何得到我想要的nm元素而不是nm数组...我试着遵循这个Julia blog post。此外this Julia discussion post专门解决了这个问题,但我认为解决方案已经过时了1.0。

----编辑

使用for循环可以像使用点来表示元素操作一样。我关心的更大问题是一致性。假设我有两个功能。一个函数(f1)返回一维输出,而另一个函数(f2)具有二维输出。

 function f1(x, y)
  z = x .* y
  DataFrame(x = x, y = y, z = z)
 end
 function f2(x, y)
  z = x * y
  return(z)
 end

这里正确的调用当x = [1,2]y = [1,2]将是f1([1,2], [1,2])f2.([1,2], [1,2])。我在这里称之为不一致的是(从一个不知道内部函数代码的用户的角度来看),得到一个输出,其中zxy的长度,.f2一起使用但是不是f1。我能看到的唯一解决方法是在z = .x * y中定义f2(或者为每个索引循环使用a)。在这种情况下,f1f2都可以在没有点的情况下调用。这是一个合适的解决方案?为了清楚起见,我的目标是f1f2被用户称为xy是单个还是多个元素数组。如果xy是单个元素,并且.if每个变量都有多个元素,那么我的偏好是让用户在没有点的情况下调用这两个函数。这似乎不可能。因此,我必须学会忍受的部分是必须在我的函数中写出许多.[i](如果我想要“一致性”)。正确?

或者,我可以添加文档,明确指出当参数长度> 1时,我需要使用.调用返回一个变量的函数,并且无需出于任何原因使用.调用返回数据帧的函数。 [原谅任何滥用技术语言的行为;我的背景是生态学]

arrays dataframe scope julia
2个回答
1
投票

那是你要的吗?

julia> function f(x, y)
           z = x .* y
           DataFrame(x = x, y = y, z = z)
       end
f (generic function with 1 method)

julia> f([1,2], [1,2])
2×3 DataFrame
│ Row │ x │ y │ z │
├─────┼───┼───┼───┤
│ 1   │ 1 │ 1 │ 1 │
│ 2   │ 2 │ 2 │ 4 │

你也可以写简短的f(x, y) = DataFrame(x = x, y = y, z = x .* y)

你写函数定义的方式表明你知道R.在Julia中,与R相反,标量和数组是完全分离的类型(例如.Float64Vector{Float64}),并且必须区别对待;但通常情况下,只需在正确的位置添加足够的广播(并通过在任何函数调用之后或任何运算符之前放置.来进行广播工作)。

为了确保不混淆这些东西,你可以在参数中添加类型:f(x::Vector{Float64}, y::Vector{Float64})或任何适合你的东西。


1
投票

我的偏好是让用户在没有点的情况下调用两个函数,如果x和y是单个元素,并且如果每个变量都有多个元素。

您需要一个专门研究参数类型的函数。执行时最优雅,最快的编译方式是使用@generated宏。

using DataFrames
@generated function f(a,b)
    if a<:Array && b<:Array
        code = quote
            DataFrame(x = a, y = b, z = a .* b)
        end
    else
        code = quote
            DataFrame(x = a, y = b, z = a * b)
        end
    end
    code
end

现在让我们测试一下。请注意函数行为如何取决于参数的类型(Float64 vs Int)。每个参数可以是Array或标量。

julia> f(3,4)                    
1×3 DataFrame                    
│ Row │ x │ y │ z  │             
├─────┼───┼───┼────┤             
│ 1   │ 3 │ 4 │ 12 │             

julia> f(3,4.0)                  
1×3 DataFrame                    
│ Row │ x │ y   │ z    │         
├─────┼───┼─────┼──────┤         
│ 1   │ 3 │ 4.0 │ 12.0 │         

julia> f(3.0,[1,2,3])            
3×3 DataFrame                    
│ Row │ x   │ y │ z   │          
├─────┼─────┼───┼─────┤          
│ 1   │ 3.0 │ 1 │ 3.0 │          
│ 2   │ 3.0 │ 2 │ 6.0 │          
│ 3   │ 3.0 │ 3 │ 9.0 │    

julia> f([1,2,3],4)
3×3 DataFrame
│ Row │ x │ y │ z  │
├─────┼───┼───┼────┤
│ 1   │ 1 │ 4 │ 4  │
│ 2   │ 2 │ 4 │ 8  │
│ 3   │ 3 │ 4 │ 12 │      

julia> f([6,7,8],[1,2,3])        
3×3 DataFrame                    
│ Row │ x │ y │ z  │             
├─────┼───┼───┼────┤             
│ 1   │ 6 │ 1 │ 6  │             
│ 2   │ 7 │ 2 │ 14 │             
│ 3   │ 8 │ 3 │ 24 │             
© www.soinside.com 2019 - 2024. All rights reserved.