Reputation: 343
Given a dataframe like the following one:
farm_1 farm_2 farm_3
NA chicken NA
cow lamb NA
NA NA deer
lamb pig pig
NA donkey NA
I would like to reshape it so all the NAs each single column contains go to the lower positions, leaving the upper ones to the actual values. Hence, the dataframe in the example should become something like this:
farm_1 farm_2 farm_3
cow chicken deer
lamb lamb pig
NA pig NA
NA donkey NA
NA NA NA
Upvotes: 1
Views: 40
Reputation: 125208
For what it's good for. A tidyverse approach to achieve your desired result may look like so:
d <- read.table(text = "farm_1 farm_2 farm_3
NA chicken NA
cow lamb NA
NA NA deer
lamb pig pig
NA donkey NA", header = TRUE)
library(dplyr)
mutate(d, across(everything(), sort, na.last = TRUE))
#> farm_1 farm_2 farm_3
#> 1 cow chicken deer
#> 2 lamb donkey pig
#> 3 <NA> lamb <NA>
#> 4 <NA> pig <NA>
#> 5 <NA> <NA> <NA>
If you want to preserve the order of the non-NA values (thanks to @Lucas for pointing that out) you could do:
mutate(d, across(everything(), ~ sort(forcats::fct_inorder(.x), na.last = TRUE)))
#> farm_1 farm_2 farm_3
#> 1 cow chicken deer
#> 2 lamb lamb pig
#> 3 <NA> pig <NA>
#> 4 <NA> donkey <NA>
#> 5 <NA> <NA> <NA>
Upvotes: 3
Reputation: 389155
You can use na.omit
to drop NA
values, subset the values so that the last values are appended by NA
.
df[] <- lapply(df, function(x) na.omit(x)[1:length(x)])
# farm_1 farm_2 farm_3
#1 cow chicken deer
#2 lamb lamb pig
#3 <NA> pig <NA>
#4 <NA> donkey <NA>
#5 <NA> <NA> <NA>
Or if you prefer dplyr
-
library(dplyr)
df %>% mutate(across(.fns = ~na.omit(.)[1:length(.)]))
Upvotes: 2