What is the difference between `:` and `!` indexing in DataFrames with Unitful?

Does not work in the same way as the following would not work for matrices:

julia> x = [1 2; 3 4]
2×2 Matrix{Int64}:
 1  2
 3  4

julia> x[:, 1] = x[:, 1] / 2
ERROR: InexactError: Int64(0.5)

If you are using : on LHS you indicate that you want an in-place operation. This means that target must be able to store the source.

If you use ! on LHS as a selector you indicate that you want to replace the column with new data, overwriting the type of the column:

julia> using DataFrames

julia> df = DataFrame(a=1:2, b=["a", "b"])
2×2 DataFrame
 Row │ a      b
     │ Int64  String
─────┼───────────────
   1 │     1  a
   2 │     2  b

julia> df[:, :a] = df[:, :b] # fails, as it is in place
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64

julia> df[!, :a] = df[:, :b] # works, as it is a replace operation
2-element Vector{String}:
 "a"
 "b"

julia> df
2×2 DataFrame
 Row │ a       b
     │ String  String
─────┼────────────────
   1 │ a       a
   2 │ b       b

Note that writing df[!, :a] is the same as writing df.a.

All this is explained in DataFrames.jl indexing rules | Blog by Bogumił Kamiński.

3 Likes