Setting a value of a Data Frame object

Viewed 178

In my case I load the following csv data (https://ourworldindata.org/coronavirus-source-data) by using the CSV module and importing it like that:

using DataFrames
using CSV

raw = CSV.read("data.csv")

Then I want to set a string column by indexing it like that:

raw[1, :location] = "AA"

and I get the following error:

setindex! not defined for CSV.Column{String,PooledString}

Stacktrace:
 [1] error(::String, ::Type) at ./error.jl:42
 [2] error_if_canonical_setindex(::IndexLinear, ::CSV.Column{String,PooledString}, ::Int64) at ./abstractarray.jl:1006
 [3] setindex!(::CSV.Column{String,PooledString}, ::String, ::Int64) at ./abstractarray.jl:997
 [4] insert_single_entry!(::DataFrame, ::String, ::Int64, ::Symbol) at /home/chris/.julia/packages/DataFrames/S3ZFo/src/dataframe/dataframe.jl:452
 [5] setindex!(::DataFrame, ::String, ::Int64, ::Symbol) at /home/chris/.julia/packages/DataFrames/S3ZFo/src/dataframe/dataframe.jl:491
 [6] top-level scope at In[31]:1

Has this something to do with my types or am I doing something wrong completely? For a simple example it seems to works that way:

df=DataFrames.DataFrame(A=[1,2],B=[3,4])

df[2,:A]=7
1 Answers

This is because what CSV.read returns is by default an immutable dataframe whose underlying storage is based on the CSV.Column type. You can directly read a mutable dataframe using the copycols option:

julia> using CSV

       # Reading from a buffer for the sake of the example
julia> buf = IOBuffer("A B\n1 2\n3 4\n");

       # Note the copycols=true keyword argument
julia> data = CSV.read(buf, copycols=true)
2×2 DataFrames.DataFrame
│ Row │ A     │ B     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 2     │
│ 2   │ 3     │ 4     │

       # The dataframe is now mutable
julia> data[2, :A] = 42;
julia> data
2×2 DataFrames.DataFrame
│ Row │ A     │ B     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 2     │
│ 2   │ 42    │ 4     │

An other possibility would be to convert your data to a "regular" (i.e. Array-based, mutable) DataFrame after loading it from the CSV file.

For example:

julia> using DataFrames

       # Reading from a buffer for the sake of the example
julia> buf = IOBuffer("A B\n1 2\n3 4\n");

       # Pass the output of CSV.read to the DataFrame constructor
julia> data = CSV.read(buf) |> DataFrame
2×2 DataFrame
│ Row │ A     │ B     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 2     │
│ 2   │ 3     │ 4     │

       # The dataframe is now mutable
julia> data[2, :A] = 42;
julia> data
2×2 DataFrame
│ Row │ A     │ B     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 2     │
│ 2   │ 42    │ 4     │
Related