6 votes

Remplacer les NAs par des valeurs manquantes dans la séquence (R)

J'ai un DF comme

enter image description here

Maintenant je veux remplacer la Col B = NA par 15 puisque c'est la valeur manquante. Col C premièrement NA avec 14 et deuxièmement NA avec 15. Col D : premier NA avec 13, deuxième NA avec 14 et troisième NA avec 15. Les chiffres suivent donc une séquence de haut en bas ou de bas en haut.

Données d'échantillons reproductibles

structure(list(`Col A` = c(11, 12, 13, 14, 15), `Col B` = c(NA, 
11, 12, 13, 14), `Col C` = c(NA, NA, 11, 12, 13), `Col D` = c(NA, 
NA, NA, 11, 12)), row.names = c(NA, -5L), class = c("tbl_df", 
"tbl", "data.frame"))

6voto

Anoushiravan R Points 4928

Je pense que vous pouvez utiliser la solution suivante dans tidyverse :

library(dplyr)
library(purrr)

df[1] %>%
  bind_cols(map_dfc(2:length(df), function(x) {
    df[[x]][which(is.na(df[[x]]))] <- setdiff(df[[1]], df[[x]][!is.na(df[[x]])])
    df[x]
  }))

# A tibble: 5 x 4
  `Col A` `Col B` `Col C` `Col D`
    <dbl>   <dbl>   <dbl>   <dbl>
1      11      15      14      13
2      12      11      15      14
3      13      12      11      15
4      14      13      12      11
5      15      14      13      12

Ou dans base R que nous pourrions faire :

do.call(cbind, Reduce(function(x, y) {
  i <- which(is.na(df[[y]]))
  df[[y]][i] <- sort(setdiff(x, df[[y]]))
  df[[y]]
}, init = df[[1]], 2:length(df), accumulate = TRUE)) |>
  as.data.frame() |>
  setNames(paste0("Col", LETTERS[1:length(df)]))

  ColA ColB ColC ColD
1   11   15   14   13
2   12   11   15   14
3   13   12   11   15
4   14   13   12   11
5   15   14   13   12

3voto

Jay Points 1879

Vous pouvez essayer :

df[is.na(df)] <- head({tm <- toeplitz(rev(df$ColA))}[upper.tri(tm, diag = TRUE)], sum(is.na(df)))

Ce qui donne :

  ColA ColB ColC ColD
1   11   15   14   13
2   12   11   15   14
3   13   12   11   15
4   14   13   12   11
5   15   14   13   12

1voto

ThomasIsCoding Points 54213

Essayez le code ci-dessous

df[-1] <- lapply(
  df[-1],
  function(x) {
    replace(x, is.na(x), df[[1]][is.na(match(df[[1]], x))])
  }
)

et vous obtiendrez

> df
# A tibble: 5 x 4
  `Col A` `Col B` `Col C` `Col D`
    <dbl>   <dbl>   <dbl>   <dbl>
1      11      15      14      13
2      12      11      15      14
3      13      12      11      15
4      14      13      12      11
5      15      14      13      12

1voto

tmfmnk Points 8978

Si la séquence est constante (dans ce cas, de 11 à 15), on peut utiliser la méthode suivante dplyr pourrait être :

df %>%
 mutate(across(everything(), ~ if_else(is.na(.), max(., na.rm = TRUE) + cumsum(is.na(.)), .)))

  `Col A` `Col B` `Col C` `Col D`
    <dbl>   <dbl>   <dbl>   <dbl>
1      11      15      14      13
2      12      11      15      14
3      13      12      11      15
4      14      13      12      11
5      15      14      13      12

Si la séquence peut varier, alors une option pourrait être :

df %>%
 mutate(across(-1, 
               ~ if_else(is.na(.),
                         cumsum(is.na(.)) - 1 + last(pull(select(cur_data(), which(names(cur_data()) == cur_column()) - 1))),
                         .)))

Ou :

df %>%
 mutate(across(-1, 
               ~ if_else(is.na(.),
                         cumsum(is.na(.)) - 1 + last(get(paste0("Col ", LETTERS[which(names(cur_data()) == cur_column()) - 1]))),
                         .)))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X