Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fill missings with first non-missing value by group?

Tags:

r

tidyverse

I have the following data structure:

  library(dplyr)

  test_data <- data.frame(some_dimension = c(rep("first",6),rep("second",6)),
                          first_col = c(rep(NA,3),rep(1,3),rep(NA,3),rep(0,3)),
                          second_col = c(rep(NA,3),rep(0,3),rep(NA,3),rep(1,3)),
                          third_col = c(rep(NA,3),rep(1,3),rep(NA,3),rep(1,3)))

      some_dimension first_col second_col third_col
1           first        NA         NA        NA
2           first        NA         NA        NA
3           first        NA         NA        NA
4           first         1          0         1
5           first         1          0         1
6           first         1          0         1
7          second        NA         NA        NA
8          second        NA         NA        NA
9          second        NA         NA        NA
10         second         0          1         1
11         second         0          1         1
12         second         0          1         1

I would like to get the following data structure:

  expexted_data <- data.frame(some_dimension = c(rep("first",6),rep("second",6)),
                          first_col = c(rep(0,3),rep(1,3),rep(1,3),rep(0,3)),
                          second_col = c(rep(1,3),rep(0,3),rep(0,3),rep(1,3)),
                          third_col = c(rep(0,3),rep(1,3),rep(0,3),rep(1,3)))


     some_dimension first_col second_col third_col
1           first         0          1         0
2           first         0          1         0
3           first         0          1         0
4           first         1          0         1
5           first         1          0         1
6           first         1          0         1
7          second         1          0         0
8          second         1          0         0
9          second         1          0         0
10         second         0          1         1
11         second         0          1         1
12         second         0          1         1

That is I would like to fill the missing value with the oposite of the first non-missing value (grouped by some_dimension), where the values ranges in (0,1).

What I have tried last was the following. Its basically finding all non missings and take the smallest index. However I have some difficulties of applying that function properly:

my_fun <- function(x){
   all_non_missings <- which(!is.na(x))
   first_non_missing <- min(all_non_missings)
   if(.data[first_non_missing] == 1){
    is.na(x) <- rep(0, length.out = length(x))
  } else {
    is.na(x) <- rep(1, length.out = length(x))
  }
}

test_data %>% group_by(some_dimension) %>% mutate_if(is.numeric, funs(new = my_fun(.)))

Where I get always some errors like:

Error in mutate_impl(.data, dots): Evaluation error: (list) object cannot be coerced to type 'double'. Traceback: for instance

like image 969
Mamba Avatar asked Dec 20 '25 03:12

Mamba


1 Answers

Try the na.locf function from the "zoo" package:

library(zoo)
test_data %>%
   group_by(some_dimension) %>% 
   mutate_if(is.numeric,funs(ifelse(is.na(.),1-na.locf(.,fromLast=TRUE),.)))
#   some_dimension first_col second_col third_col
#1           first         0          1         0
#2           first         0          1         0
#3           first         0          1         0
#4           first         1          0         1
#5           first         1          0         1
#6           first         1          0         1
#7          second         1          0         0
#8          second         1          0         0
#9          second         1          0         0
#10         second         0          1         1
#11         second         0          1         1
#12         second         0          1         1

Or shorter :

test_data %>% 
  group_by(some_dimension) %>%
  mutate_if(is.numeric,funs(coalesce(.,1-na.locf(.,fromLast=TRUE))))
like image 152
Nicolas2 Avatar answered Dec 22 '25 19:12

Nicolas2



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!