I've recently started trying to do all of my code in the tidyverse. This has sometimes lead me to difficulties. Here is a simple task that I haven't been able to complete in the tidyverse: I need a column in a dataframe that returns the position index of the first non-na value from the left. Does anyone know how to achieve this in dplyr using mutate?
Here is the desired output.
data.frame(
"X1"=c(100,rep(NA,8)),
"X2"=c(NA,10,rep(NA,7)),
"X3"=c(NA,NA,1000,1000,rep(NA,5)),
"X4"=c(rep(NA,4),25,50,10,40,50),
"FirstNonNaPosition"=c(1,2,3,3,4,4,4,4,4)
)
An easier and efficient base R
option would be max.col
after replacing the NA
elements to 0
max.col(replace(df2[1:4], is.na(df2[1:4]), 0), 'first')
Or even
df2$FirstNonNaPosition <- max.col(!is.na(df2[1:4]), "first")
df2$FirstNonNaPosition
#[1] 1 2 3 3 4 4 4 4 4
With tidyverse
, a possible option is pmap
df2 %>%
mutate(FirstNonNaPosition = pmap_int(.[-5], ~
which.max(!is.na(c(...)))))
Or wrap the max.col
df2 %>%
mutate(FirstNonNaPosition = max.col(!is.na(.[-5]), 'first'))
df2 <- structure(list(X1 = c(100, NA, NA, NA, NA, NA, NA, NA, NA), X2 = c(NA,
10, NA, NA, NA, NA, NA, NA, NA), X3 = c(NA, NA, 1000, 1000, NA,
NA, NA, NA, NA), X4 = c(NA, NA, NA, NA, 25, 50, 10, 40, 50),
FirstNonNaPosition = c(1, 2, 3, 3, 4, 4, 4, 4, 4)),
class = "data.frame", row.names = c(NA,
-9L))
Also a base R
possibility:
apply(df, 1, which.max)
[1] 1 2 3 3 4 4 4 4 4
The same with dplyr
:
df %>%
mutate(FirstNonNaPosition = apply(., 1, which.max))
A modification for a scenario mentioned by @Andrew:
apply(df, 1, function(x) which.max(!is.na(x)))
The same with dplyr
:
df %>%
mutate(FirstNonNaPosition = apply(., 1, function(x) which.max(!is.na(x))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With