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

时间:2018-09-02 06:47:51

标签: arrays dataframe scope julia

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

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

返回f.([1,2],[1,2])是两个1x3数据帧的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。有什么我想念的吗?我的问题是,如何获得所需的n m元素而不是n m数组...  我尝试遵循此Julia blog postthis 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])时,这里是正确的呼叫。 我在这里所说的不一致之处是(从不了解内部功能代码的用户的角度来看),以获得其中zx的长度和y.f2一起使用,但不与f1一起使用。我能看到的唯一解决方法是在z = .x * y中定义f2(或对每个索引循环使用a)。在这种情况下,f1f2都可以不带点被调用。那是一个合适的解决方案吗?明确地说,我的目标是无论f1f2是单个还是多个元素数组,用户都将xy相同地调用。我的喜好是,如果xy是单个元素,则用户调用两个函数时都不要带点,如果每个变量具有多个元素,则使用.。这似乎不可能。因此,我必须学习生活的一部分是必须在我的函数中编写许多.[i](如果我想要“一致性”)。是吗?

或者,我可以添加文档来明确声明,当参数的长度大于1时,返回一个变量的函数需要使用.调用,而返回数据帧的函数则不需要使用{{1出于任何原因。 [原谅任何对技术语言的滥用;我的背景是生态学]

2 个答案:

答案 0 :(得分: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 :(得分: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

现在让我们对其进行测试。请注意,函数行为如何取决于参数的类型(Float64Int)。每个参数可以是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 │