create new variable defined only for a subset of the data using `dplyr`
<p>Consider this example data:</p>

<pre><code>set.seed(1234567)
mydf &lt;- data.frame(var1 = runif(10), var2 = c(runif(5), rep(NA, 5)))
</code></pre>

<p>And this EXAMPLE vectorized function that, unfortunately, triggers an error whenever one of the arguments is <code>NA</code></p>

<pre><code>myfn &lt;- function(x, y){
    sum(x:y)
}
myfn &lt;- Vectorize(myfn)
</code></pre>

<p>Now, in the middle of a <code>dplyr</code> chain I need to create a new variable using <code>myfn</code>. This new var (<code>var3</code>) is only defined when <code>var1</code> and <code>var2</code> are not <code>NA</code>.</p>

<p>So the most common solution for similar situations is to use <code>ifelse</code>. Something like this.</p>

<pre><code>mydf %&gt;%
    mutate(var3 = ifelse(
        test = is.na(var2), 
        yes = NA, 
        no = myfn(var1, var2)))
</code></pre>

<p>But this does not work in my case because <code>ifelse</code> anyway actually passes the whole vector <code>var1</code> and <code>var2</code> to <code>myfn</code> and not just the sub-vector when <code>test</code> is <code>FALSE</code>. And it all breaks because <code>myfn</code> breaks whenever receives a <code>NA</code>.</p>

<p>So, what is the clever <code>dplyr</code> solution for this? (I can think of many solutions for this without using <code>dplyr</code>, but I am just interested in a <code>dplyr</code>-friendly solution)</p>

<p>It occurred to me that <code>filter</code> could help and indeed works with a very readable and <code>dplyr</code>y code</p>

<pre><code>mydf %&gt;%
    filter(!is.na(var2)) %&gt;%
    mutate(var3 = myfn(var1, var2))

        var1       var2       var3
1 0.56226084 0.62588794 0.56226084
2 0.72649850 0.24145251 0.72649850
3 0.91524985 0.03768974 0.91524985
4 0.02969437 0.51659297 0.02969437
5 0.76750970 0.81845788 0.76750970
</code></pre>

<p>But then I would have to save this in a temporary object, then create <code>var3</code> in the original data all with <code>NA</code> and put all back together in the same data ('cause as far as I know the <code>unfilter</code> that some have <a href="https://stackoverflow.com/questions/23642811/replace-parts-of-a-variable-using-numeric-indices-in-dplyr-do-i-need-to-create">suggested</a> does not exist, ..., yet). </p>

<p>So just to illustrate the output I want, this code produces it (no using <code>dplyr</code> at all):</p>

<pre><code>mydf$var3 &lt;- NA
index &lt;- !is.na(mydf$var2)
mydf$var3[index] &lt;- myfn(mydf$var1[index], mydf$var2[index])
mydf

&gt; mydf
         var1       var2       var3
1  0.56226084 0.62588794 0.56226084
2  0.72649850 0.24145251 0.72649850
3  0.91524985 0.03768974 0.91524985
4  0.02969437 0.51659297 0.02969437
5  0.76750970 0.81845788 0.76750970
6  0.48005398         NA         NA
7  0.08837960         NA         NA
8  0.86294587         NA         NA
9  0.49660306         NA         NA
10 0.85350403         NA         NA
</code></pre>

<p><strong>EDIT:</strong></p>

<p>I accepted @krlmlr's solution because it is what I was looking for: clear, easily readable and concise code that effortlessly integrate in a <code>dplyr</code> chain. For my example, this solution looks like this.</p>

<pre><code>mydf %&gt;%
        rowwise %&gt;%
        mutate(var3 = if(is.na(var2)) NA else myfn(var1, var2))
</code></pre>

<p>However, as @krlmlr pointed out in his answer, to operate row by row has a cost in terms of performance. It may not be significant for small data sets or single time operations, but for larger data sets or repeating the operation millions of times, it could be considerable. To illustrate, here's a comparison using <code>microbenchmark</code> and three solutions (base, dyplr and data.table) applied over a somewhat larger data set (not massive or anything, just 1000 rows instead of 10 in my original example).</p>

<pre><code>library(data.table)
library(dplyr)

set.seed(1234567)
mydf &lt;- data.frame(var1 = runif(1000), var2 = c(runif(500), rep(NA, 500)))

myfn &lt;- function(x, y){
    sum(x:y)
}
myfn &lt;- Vectorize(myfn)

using_base &lt;- function(){
    mydf$var3 &lt;- NA
    index &lt;- !is.na(mydf$var2)
    mydf$var3[index] &lt;- myfn(mydf$var1[index], mydf$var2[index])
}

using_dplyr &lt;- function(){
    mydf &lt;- mydf %&gt;%
        rowwise %&gt;%
        mutate(var3 = if(is.na(var2)) NA else myfn(var1, var2))
}

using_datatable &lt;- function(){
    setDT(mydf)[!is.na(var2), var3 := myfn(var1, var2)]
}

library(microbenchmark)
mbm &lt;- microbenchmark(
    using_base(), using_dplyr(), using_datatable(), 
    times = 1000)

library(ggplot2)
autoplot(mbm)
</code></pre>

<p><a href="https://i.stack.imgur.com/F63gQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/F63gQ.png" alt="enter image description here"></a></p>

<p>And as you can see, the <code>dplyr</code> solution using <code>rowwise</code> is considerably slower than its <code>base</code> and <code>data.table</code> rivals.</p>