113 votes

Remplacer toutes les valeurs particulières dans un cadre de données

En ayant un data frame, comment puis-je remplacer toutes les valeurs particulières le long de toutes les lignes et colonnes. Par exemple, si je veux remplacer tous les enregistrements vides par des NA (sans taper les positions) :

df <- data.frame(list(A=c("", "xyz", "jkl"), B=c(12, "", 100)))

    A   B
1      12
2  xyz    
3  jkl 100

Résultat attendu :

    A   B
1  NA   12
2  xyz  NA  
3  jkl  100

1voto

jay.sf Points 8160

Il semble qu'une solution manque pour remplacer plusieurs valeurs et pour les facteurs, donc j'en ajouterai une.

Considérez un data frame dat avec différentes classes.

dat
#    character integer       Date factor               POSIX
# 1                  4 2022-07-10      B 2022-07-10 20:08:10
# 2                  1 2022-07-11    FOO 2022-07-10 21:08:10
# 3                 -2 2022-07-12        2022-07-10 22:08:10
# 4                  2 2022-07-13      B 2022-07-10 23:08:10
# 5          a       3 2022-07-14        2022-07-11 00:08:10
# 6          c       1 2022-07-15        2022-07-11 01:08:10
# 7          a      -1 2022-07-16    FOO 2022-07-11 02:08:10
# 8          a      -1 2022-07-17      A 2022-07-11 03:08:10
# 9                  4 2022-07-18    FOO 2022-07-11 04:08:10
# 10         c       0 2022-07-19    FOO 2022-07-11 05:08:10
# 11         b      -2 2022-07-20      B 2022-07-11 06:08:10
# 12         c      -2 2022-07-21      A 2022-07-11 07:08:10

Nous pouvons mettre tout ce que nous voulons convertir en NA dans une liste to_na,

To_NA <- list('', -1, -2, 'c', 'FOO', as.Date('2022-07-17'), as.POSIXct('2022-07-11 00:08:10'))

et l'utiliser dans une petite fonction make_na basée sur replace. Si la variable respective est un factor, nous pouvons vouloir droplevels des valeurs qui viennent d'être supprimées.

make_na <- \(x, z) {x <- replace(x, x %in% z, NA); if (is.factor(x)) droplevels(x) else x}

Nous pouvons l'appliquer sur un vecteur,

make_na(dat$character, To_NA)
# [1] NA  NA  NA  NA  "a" NA  "a" "a" NA  NA  "b" NA 

ou boucler sur les colonnes en utilisant lapply.

dat[] <- lapply(dat, make_na, To_NA)

Donne

dat
#    character integer       Date factor               POSIX
# 1              4 2022-07-10      B 2022-07-10 20:08:10
# 2              1 2022-07-11    2022-07-10 21:08:10
# 3             NA 2022-07-12    2022-07-10 22:08:10
# 4              2 2022-07-13      B 2022-07-10 23:08:10
# 5          a       3 2022-07-14                   
# 6              1 2022-07-15    2022-07-11 01:08:10
# 7          a      NA 2022-07-16    2022-07-11 02:08:10
# 8          a      NA             A 2022-07-11 03:08:10
# 9              4 2022-07-18    2022-07-11 04:08:10
# 10             0 2022-07-19    2022-07-11 05:08:10
# 11         b      NA 2022-07-20      B 2022-07-11 06:08:10
# 12             NA 2022-07-21      A 2022-07-11 07:08:10

Où :

str(dat)
# 'data.frame': 12 obs. of  5 variables:
#  $ character: chr  NA NA NA NA ...
#  $ integer  : int  4 1 NA 2 3 1 NA NA 4 0 ...
#  $ Date     : Date, format: "2022-07-10" "2022-07-11" "2022-07-12" ...
#  $ factor   : Factor w/ 2 levels "A","B": 2 NA NA 2 NA NA NA 1 NA NA ...
#  $ POSIX    : POSIXct, format: "2022-07-10 20:08:10" "2022-07-10 21:08:10" "2022-07-10 22:08:10" ...

Data :

dat <- structure(list(character = c("", "", "", "", "a", "c", "a", "a", 
"", "c", "b", "c"), integer = c(4L, 1L, -2L, 2L, 3L, 1L, -1L, 
-1L, 4L, 0L, -2L, -2L), Date = structure(c(19183, 19184, 19185, 
19186, 19187, 19188, 19189, 19190, 19191, 19192, 19193, 19194
), class = "Date"), factor = structure(c(3L, 4L, 1L, 3L, 1L, 
1L, 4L, 2L, 4L, 4L, 3L, 2L), levels = c("", "A", "B", "FOO"), class = "factor"), 
    POSIX = structure(c(1657476490L, 1657480090L, 1657483690L, 
    1657487290L, 1657490890L, 1657494490L, 1657498090L, 1657501690L, 
    1657505290L, 1657508890L, 1657512490L, 1657516090L), class = c("POSIXct", 
    "POSIXt"), tzone = "")), class = "data.frame", row.names = c(NA, 
-12L))

1voto

Quinten Points 454

Une autre option pourrait être d'utiliser sapply. Voici un exemple reproductible:

df <- data.frame(list(A=c("", "xyz", "jkl"), B=c(12, "", 100)))
df[sapply(df, \(x) x == "")] <- NA
df
#>      A    B
#> 1    12
#> 2  xyz 
#> 3  jkl  100

Créé le 15-01-2023 avec reprex v2.0.2


Veuillez noter: avec R 4.1.0 et ultérieur, vous pourriez utiliser \(x) au lieu de function(x)

0voto

Andy Brown Points 780

Une autre option consiste à utiliser replace_with_na_all() du package naniar, ce qui vous permet de remplacer toutes les valeurs répondant à une condition dans l'ensemble du dataframe.

library(naniar)
library(dplyr)

df %>% 
  replace_with_na_all(condition = ~.x == "")

Résultat

  A     B    

1 NA    12   
2 xyz   NA   
3 jkl   100 

L'avantage de cette méthode est que si vous aviez également des cellules avec des espaces inclus, alors nous pourrions les inclure dans l'argument des conditions. Bien qu'il soit préférable de d'abord supprimer les espaces vides, puis d'utiliser la fonction ci-dessus (c'est-à-dire en ajoutant mutate(across(everything(), ~ trimws(.x))) à la chaîne).

df <- data.frame(list(A=c("", "xyz", "  "), B=c(12, "   ", 100)))

df %>%
  replace_with_na_all(condition = ~.x %in% c("", "  ", "   "))

#  A     B    
#   
#1 NA    12   
#2 xyz   NA   
#3 NA    100

0voto

DanielS Points 545

Il est également possible d'utiliser la fonction gsub en combinaison avec lapply.

df[] <- lapply(df, function(x) (gsub("", NA, x)))

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