# DataFrames: \`@combine\` only if a condition is met

**URL:** <https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232>\
**Category:** General Usage\
**Tags:** question, dataframes, dataframesmeta\
**Created:** [March 21, 2025, 4:09pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232 "2025-03-21T16:09:42Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [March 21, 2025, 4:09pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/1 "2025-03-21T16:09:42Z")

</div>

How can I compute a variable with `@combine` only if some condition is met?

MWE:

```julia
using DataFrames, DataFramesMeta
dfTmp = DataFrame(y = 1:3, x = 10:12)
@combine dfTmp begin
    # Always compute `a`
    :a = :y * 2;
    # Only compute `b` if `x` is present
    :b = (:x in names(dfTmp)) ? (:x .+ 1) : zeros(nrow(dfTmp));
end
# Now remove `b` if `x` was not present

```

This is slightly clumsy and it fails if `x` is not in `names(dfTmp)`.

The alternative is to implement a 2nd `combine` statement just for `b` and to join the resulting DataFrames. But that seems clumsy and inefficient.

Are there better options?

---

<div class="post-metadata">

**Author:** ![eteppo](https://avatars.discourse-cdn.com/v4/letter/e/90db22/32.png) [@eteppo](https://discourse.julialang.org/u/eteppo)\
**Post date:** [March 21, 2025, 7:31pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/2 "2025-03-21T19:31:01Z")

</div>

If-else too simple?

```julia
using TidierData
dftmp = DataFrame(y = 1:3, x = 10:12)
if "x" in names(dftmp)                                                                  
    @transmute(dftmp, a = y * 2, b = x + 1)
else
    @transmute(dftmp, a = y * 2)
end

```

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [March 21, 2025, 8:36pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/3 "2025-03-21T20:36:03Z")

</div>

I am hoping to avoid duplicating all the code that computes variables in all cases (the `a = y * 2` in this case).  
This is especially important if there are multiple variables that may be missing from the DataFrame.  
But thanks for the suggestion.

---

<div class="post-metadata">

**Author:** ![kdpsingh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdpsingh/32/215018_2.png) [@kdpsingh](https://discourse.julialang.org/u/kdpsingh)\
**Post date:** [March 22, 2025, 3:43am UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/4 "2025-03-22T03:43:24Z")

</div>

Here’s a more concise way:

```julia
using TidierData
df = DataFrame(y = 1:3, x = 10:12)
@chain df begin
  @mutate(a = y * 2)
  if "x" in names(_) @mutate(_, b = x + 1) else _ end
  # more conditions here...
end

```

```julia
3×4 DataFrame
 Row │ y x a b     
     │ Int64 Int64 Int64 Int64 
─────┼────────────────────────────
   1 │ 1 10 2 11
   2 │ 2 11 4 12
   3 │ 3 12 6 13

```

Just in case it’s not clear, the `_` is a placeholder within `@chain`. If the condition is not met, having the `else _` ensures that you return the data frame without modifications so you can continue the chain. `@mutate` uses `DataFrames.transform()` under the hood.

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [March 22, 2025, 12:08pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/5 "2025-03-22T12:08:53Z")

</div>

That works (even if `x` is not present, while `DataFramesMeta` does not work in that case).  
I will mark it as the solution, even though I would prefer a solution that does not require me to write that one section of the code in the Tidier syntax, while I’m using DataFramesMeta everywhere else.  
Thank you for the suggestion.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [March 22, 2025, 12:55pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/6 "2025-03-22T12:55:17Z")

</div>

You can also use `AsTable`:

```julia
julia> using DataFrames, DataFramesMeta

julia> dfTmp = DataFrame(y = 1:3, x = 10:12)
3×2 DataFrame
 Row │ y x
     │ Int64 Int64
─────┼──────────────
   1 │ 1 10
   2 │ 2 11
   3 │ 3 12

julia> @combine dfTmp $AsTable = begin
           a = :y * 2
           if "x" in names(dfTmp)
               b = :x .+ 1
               (; a, b)
           else
               (; a)
           end
       end
3×2 DataFrame
 Row │ a b
     │ Int64 Int64
─────┼──────────────
   1 │ 2 11
   2 │ 4 12
   3 │ 6 13

```

Edit: no this fails if x doesn’t exist because the created function is given to DataFrames with args :y and :x

---

<div class="post-metadata">

**Author:** ![kdpsingh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdpsingh/32/215018_2.png) [@kdpsingh](https://discourse.julialang.org/u/kdpsingh)\
**Post date:** [March 22, 2025, 1:03pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/7 "2025-03-22T13:03:38Z")

</div>

Happy to provide a DataFramesMeta solution. Should be similar. Will take a look.

Does this work? (not at a computer)

```julia
using DataFramesMeta, Chain
df = DataFrame(y = 1:3, x = 10:12)
@chain df begin
  @rtransform(:a = :y * 2)
  if "x" in names(_) @rtransform(_, :b = :x + 1) else _ end
  # more conditions here...
end

```

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [March 22, 2025, 3:02pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/8 "2025-03-22T15:02:06Z")

</div>

That works, even if the conditioning variable does not exist - thanks.

---

<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:** [March 22, 2025, 5:28pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/9 "2025-03-22T17:28:18Z")

</div>

or by exploiting one of Julia’s peculiarities

```julia
df = DataFrame(y = 1:3, x = 10:12)
f(dfxy::@NamedTuple{y::Int64, x::Int64})=(;a=dfxy.y*2,b=dfxy.x+1)
f(dfy::@NamedTuple{y::Int64})=(;a=dfy.y*2)

transform(df, AsTable(:) => ByRow(f)=>AsTable )

dfnx=df[:,Not(:x)] 
transform(dfnx, AsTable(:) => ByRow(f)=>AsTable )

```

---

<div class="post-metadata">

**Author:** ![kdpsingh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kdpsingh/32/215018_2.png) [@kdpsingh](https://discourse.julialang.org/u/kdpsingh)\
**Post date:** [March 22, 2025, 9:53pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/10 "2025-03-22T21:53:45Z")

</div>

![image](https://global.discourse-cdn.com/julialang/original/3X/6/4/64b87684636c3eb6b01e6b64eadcd9a1dc47fd20.jpeg)

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [March 23, 2025, 12:44pm UTC](https://discourse.julialang.org/t/dataframes-combine-only-if-a-condition-is-met/127232/11 "2025-03-23T12:44:20Z")

</div>

That’s an interesting option. Instead of writing different combinations of `f`, one could just put `if else` logic into `f` (otherwise, writing out several versions of `f` could be tedious). I would have to check performance, though. Thanks.
