# Make a Copy of a DataFrame Row

**URL:** <https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953>\
**Category:** General Usage\
**Tags:** dataframes\
**Created:** [February 2, 2023, 10:24pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953 "2023-02-02T22:24:42Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![quietlight](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quietlight/32/35187_2.png) [@quietlight](https://discourse.julialang.org/u/quietlight)\
**Post date:** [February 2, 2023, 10:24pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/1 "2023-02-02T22:24:42Z")

</div>

I am stuck on this for loop. I need a copy of a dataframe row so I can modify it and then push the modified row onto to the dataframe.

My K-MF label means a male and female kiwi are both calling at the same time, I want to change this so I have 2 labels (or rows), one for the female call, one for the male call.

This is all happening in a function that builds my training dataset which is quite large and growing.

```julia
for row in eachrow(data_frame)
            # correct to Male, Female, Close to match newer annotations
            if row.species == "K-M"
                row.species = "Male"

            elseif row.species == "K-F"
                row.species = "Female"

            # correct K-MF label to Male, plus another identical row with label Female
            elseif row.species == "K-MF"
               row.species = "Male"
            # I need to break off a copy of row into a new dataframe with no 
            # connection to the original row
               new_row = row[:] # I thought it was a copy     
               new_row.species = "Female"
               push!(data_frame, new_row) 
            # I end up with 2 rows with species=Female, instead of 1 male, 
            # 1 female as 'new_row.species = "Female"' modifies both the new 
            # row and the original
            end
        end

```

Kindness  
David

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [February 2, 2023, 10:30pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/2 "2023-02-02T22:30:13Z")

</div>

Not at a computer to test, but can you try `copy(row)`?

---

<div class="post-metadata">

**Author:** ![quietlight](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quietlight/32/35187_2.png) [@quietlight](https://discourse.julialang.org/u/quietlight)\
**Post date:** [February 2, 2023, 10:41pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/3 "2023-02-02T22:41:56Z")

</div>

Thanks, yes I had tried already but did again anyway.

Here is the error: “ERROR: setfield!: immutable struct of type NamedTuple cannot be changed”

copy() does not return a dataframe.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [February 2, 2023, 10:45pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/4 "2023-02-02T22:45:29Z")

</div>

Somewhat confusingly, `copy(row)` returns a `NamedTuple`, not a new `DataFrameRow`. This is unfortunately what’s causing your problem.

You can `push!` a dictionary to a data frame, so you might want to do

```julia
julia> Dict(k => v for (k, v) in enumerate(dfr))
Dict{Int64, Int64} with 2 entries:
  2 => 3
  1 => 1

```

instead of `copy`.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 2, 2023, 11:07pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/5 "2023-02-02T23:07:31Z")

</div>

try this

```julia
for row in eachrow(df)
    # correct to Male, Female, Close to match newer annotations
    if row.species == "K-M"
        row.species = "Male"

    elseif row.species == "K-F"
        row.species = "Female"

    # correct K-MF label to Male, plus another identical row with label Female
    elseif row.species == "K-MF"
       row.species = "Male"
       push!(df, merge(row, (species="Female",))) 
    end
end

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 2, 2023, 11:14pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/6 "2023-02-02T23:14:36Z")

</div>

an alternative way

```julia
tdf=transform(df, :species=>ByRow(x->x=="K-M" ? "M" : (x=="K-F" ? "F" : ["M","F"]))=>:g)

flatten(tdf,:g)

```

---

<div class="post-metadata">

**Author:** ![quietlight](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quietlight/32/35187_2.png) [@quietlight](https://discourse.julialang.org/u/quietlight)\
**Post date:** [February 2, 2023, 11:27pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/8 "2023-02-02T23:27:18Z")

</div>

The idea works, but since the keys of the dicts are the number of the column id is hard to merge back into the base dataframe. There are a lot of columns oor i would just bodge it manually. This works fine:

```julia
new_row = Dict(names(row) .=> values(row))       
new_row["species"] = "Female"

```

Thanks  
David

---

<div class="post-metadata">

**Author:** ![quietlight](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quietlight/32/35187_2.png) [@quietlight](https://discourse.julialang.org/u/quietlight)\
**Post date:** [February 2, 2023, 11:28pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/9 "2023-02-02T23:28:56Z")

</div>

Thanks

I like this solution.

Regards  
David

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [February 2, 2023, 11:33pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/10 "2023-02-02T23:33:19Z")

</div>

Oh sorry. Yeah, your version is correct.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [February 2, 2023, 11:34pm UTC](https://discourse.julialang.org/t/make-a-copy-of-a-dataframe-row/93953/11 "2023-02-02T23:34:03Z")

</div>

Looks like you got a solution, but here is a different approach:

```julia
function replace_species(df)
    # create a copy of the K-MF rows, set them all to femail
    k_mf_rows = filter(AsTable(:) => r -> r.species == "K-MF", df)
    k_mf_rows.species .= "Female"

    # replace species in place (setting original K-MFs to Male)
    species_map = Dict(
        "K-M" => "Male",
        "K-F" => "Female",
        "K-MF" => "Male"
    )
    replace!(v -> species_map[v], df.species)
    
    # Stack on the copies
    new_df = vcat(df, k_mf_rows)
    return new_df
end

```

Edit: FWIW, depending on the size of the DataFrame and the number of K-MF values, this solution might be faster because calling `push!` over and over is slow since it has to allocate each time.
