So I was following a tutorial, but I got confused when they showed the following code:
vec(string.([“x”,“y”],[1 2 3 4]))
First, how am I supposed to infer the broadcasting of string given a vector and a matrix will return a matrix pairing each possible combinations?
Second, why with [1 2 3 4] the broadcasting works but it does not work with [1,2,3,4]? Aren’t the dimensions compatible?
Thanks.
Spaces create a 1-row matrix, commas or semicolons create a vector (~ 1-column matrix).
When a column and a row are broadcasted, the output shape is the same as the way a matrix multiplication works, then the vec
flattens it into a vector.
2 Likes
So in general brosdcasting will form that resultant matrix from two separate arguments?
The broadcasting semantics (Single- and multi-dimensional Arrays · The Julia Language) are that vectors/matrices are treated as if they were arrays with singleton dimensions, then these dimensions are expanded to match. (There are some edge cases)
So, since the second argument is a 1x4 matrix (enter it in the REPL and see), the vector ["x", "y"]
gets treated as a 2x1 matrix. Then the vector gets (virtually) expanded to a 2x4 matrix by repeating its columns and the matrix gets expanded to a 2x4 matrix by repeating the rows.
This produces the equivalent of the call
vec(string.(["x" "x" "x" "x"; "y" "y" "y" "y"], [1 2 3 4; 1 2 3 4]))
Here string
is applied element-wise, so it’s equivalent to
vec(["x1" "x2" "x3" "x4"; "y1" "y2" "y3" "y4"])
which produces a vector of these elements.
As @BioTurboNick notes, this is equivalent to the semantics of multiplying a column-vector by a row-vector.
Also, please note that this only applies to arrays (and vectors/matrices), not general iterators. Iterators generally don’t have a shape, only a length, and so broadcasting across them just produces a flat array.
HTH
Yes. Here are some more examples of this in action:
julia> ["x", "y"] .^ [1, 2, 3, 4]' # I'm using transpose to get a row vector in this example
2×4 Matrix{String}:
"x" "xx" "xxx" "xxxx"
"y" "yy" "yyy" "yyyy"
julia> [10, 100] .+ [1 2; 3 4] # notice the second argument is a matrix already
2×2 Matrix{Int64}:
11 12
103 104
julia> [10, 100]' .+ [1 2; 3 4] # And it matters if the first is a column or row! notice the transpose this time
2×2 Matrix{Int64}:
11 102
13 104
julia> tuple.(0:0.5:1, (0:0.5:1)') # transpose of a range??? Yes.
3×3 Matrix{Tuple{Float64, Float64}}:
(0.0, 0.0) (0.0, 0.5) (0.0, 1.0)
(0.5, 0.0) (0.5, 0.5) (0.5, 1.0)
(1.0, 0.0) (1.0, 0.5) (1.0, 1.0)
julia> LinearIndices((3,2,2)) .+ [0 100] # yes, even in higher dimensions!
3×2×2 Array{Int64, 3}:
[:, :, 1] =
1 104
2 105
3 106
[:, :, 2] =
7 110
8 111
9 112
Broadcasting is super powerful, but it does take some getting used to.
I don’t know where that tutorial you were following was, but it does seem like a pretty tricky example (was it somewhere in the official docs?)
Thank you. It was in the introduction to DataFrames video tutorial.