J'essaie de réaliser quelque chose de similaire à cette question mais avec plusieurs valeurs qui doivent être remplacées par NA et dans un grand jeu de données.
df <- data.frame(name = rep(letters[1:3], each = 3), foo=rep(1:9),var1 = rep(1:9), var2 = rep(3:5, each = 3))
qui génère cette dataframe:
df
name foo var1 var2
1 a 1 1 3
2 a 2 2 3
3 a 3 3 3
4 b 4 4 4
5 b 5 5 4
6 b 6 6 4
7 c 7 7 5
8 c 8 8 5
9 c 9 9 5
Je voudrais remplacer toutes les occurrences de, par exemple, 3 et 4 par NA, mais uniquement dans les colonnes commençant par "var".
Je sais que je peux utiliser une combinaison d'opérateurs []
pour obtenir le résultat souhaité:
df[,grep("^var[:alnum:]?",colnames(df))][
df[,grep("^var[:alnum:]?",colnames(df))] == 3 |
df[,grep("^var[:alnum:]?",colnames(df))] == 4
] <- NA
df
name foo var1 var2
1 a 1 1 NA
2 a 2 2 NA
3 a 3 NA NA
4 b 4 NA NA
5 b 5 5 NA
6 b 6 6 NA
7 c 7 7 5
8 c 8 8 5
9 c 9 9 5
Maintenant, mes questions sont les suivantes:
|
?Vous pouvez également le faire en utilisant replace
:
sel <- grepl("var",names(df))
df[sel] <- lapply(df[sel], function(x) replace(x,x %in% 3:4, NA) )
df
# name foo var1 var2
#1 a 1 1 NA
#2 a 2 2 NA
#3 a 3 NA NA
#4 b 4 NA NA
#5 b 5 5 NA
#6 b 6 6 NA
#7 c 7 7 5
#8 c 8 8 5
#9 c 9 9 5
Une analyse rapide utilisant un échantillon de millions de lignes de données suggère que cela est plus rapide que les autres réponses.
Vous pouvez aussi faire:
col_idx <- grep("^var", names(df))
values <- c(3, 4)
m1 <- as.matrix(df[,col_idx])
m1[m1 %in% values] <- NA
df[col_idx] <- m1
df
# name foo var1 var2
#1 a 1 1 NA
#2 a 2 2 NA
#3 a 3 NA NA
#4 b 4 NA NA
#5 b 5 5 NA
#6 b 6 6 NA
#7 c 7 7 5
#8 c 8 8 5
#9 c 9 9 5
Je n'ai pas chronométré cette option, mais J'ai écrit une fonction appelée makemeNA
qui fait partie de mon paquet "SOfun" réservé à GitHub .
Avec cette fonction, l’approche ressemblerait à ceci:
library(SOfun)
Cols <- grep("^var", names(df))
df[Cols] <- makemeNA(df[Cols], NAStrings = as.character(c(3, 4)))
df
# name foo var1 var2
# 1 a 1 1 NA
# 2 a 2 2 NA
# 3 a 3 NA NA
# 4 b 4 NA NA
# 5 b 5 5 NA
# 6 b 6 6 NA
# 7 c 7 7 5
# 8 c 8 8 5
# 9 c 9 9 5
La fonction utilise l'argument na.strings
dans type.convert
pour effectuer la conversion en NA
.
Installez le paquet avec:
library(devtools)
install_github("SOfun", "mrdwab")
(ou votre méthode préférée d'installation de paquets à partir de GitHub).
Voici quelques analyses comparatives. J'ai décidé de rendre les choses intéressantes et de remplacer les valeurs numériques et non numériques par NA
pour voir comment les choses se comparent.
Voici les exemples de données:
n <- 1000000
set.seed(1)
df <- data.frame(
name1 = sample(letters[1:3], n, TRUE),
name2 = sample(letters[1:3], n, TRUE),
name3 = sample(letters[1:3], n, TRUE),
var1 = sample(9, n, TRUE),
var2 = sample(5, n, TRUE),
var3 = sample(9, n, TRUE))
Voici les fonctions à tester:
fun1 <- function() {
Cols <- names(df)
df[Cols] <- makemeNA(df[Cols], NAStrings = as.character(c(3, 4, "a")))
df
}
fun2 <- function() {
values <- c(3, 4, "a")
col_idx <- names(df)
m1 <- as.matrix(df)
m1[m1 %in% values] <- NA
df[col_idx] <- m1
df
}
fun3 <- function() {
values <- c(3, 4, "a")
col_idx <- names(df)
val_idx <- sapply(df[col_idx], "%in%", table = values)
is.na(df[col_idx]) <- val_idx
df
}
fun4 <- function() {
sel <- names(df)
df[sel] <- lapply(df[sel], function(x)
replace(x, x %in% c(3, 4, "a"), NA))
df
}
J'éclate fun2
et fun3
. Je ne suis pas fou de fun2
car il convertit tout dans le même type. Je m'attends aussi à ce que fun3
soit plus lent.
system.time(fun2())
# user system elapsed
# 4.45 0.33 4.81
system.time(fun3())
# user system elapsed
# 34.31 0.38 34.74
Alors maintenant, ça revient à moi et Thela ...
library(microbenchmark)
microbenchmark(fun1(), fun4(), times = 50)
# Unit: seconds
# expr min lq median uq max neval
# fun1() 2.934278 2.982292 3.070784 3.091579 3.617902 50
# fun4() 2.839901 2.964274 2.981248 3.128327 3.930542 50
Dang vous Thela!
Voici une approche:
# the values that should be replaced by NA
values <- c(3, 4)
# index of columns
col_idx <- grep("^var", names(df))
# [1] 3 4
# index of values (within these columns)
val_idx <- sapply(df[col_idx], "%in%", table = values)
# var1 var2
# [1,] FALSE TRUE
# [2,] FALSE TRUE
# [3,] TRUE TRUE
# [4,] TRUE TRUE
# [5,] FALSE TRUE
# [6,] FALSE TRUE
# [7,] FALSE FALSE
# [8,] FALSE FALSE
# [9,] FALSE FALSE
# replace with NA
is.na(df[col_idx]) <- val_idx
df
# name foo var1 var2
# 1 a 1 1 NA
# 2 a 2 2 NA
# 3 a 3 NA NA
# 4 b 4 NA NA
# 5 b 5 5 NA
# 6 b 6 6 NA
# 7 c 7 7 5
# 8 c 8 8 5
# 9 c 9 9 5
Voici une solution Dplyr:
# Define replace function
repl.f <- function(x) ifelse(x%in%c(3,4), NA,x)
library(dplyr)
cbind(select(df, -starts_with("var")),
mutate_each(select(df, starts_with("var")), funs(repl.f)))
name foo var1 var2
1 a 1 1 NA
2 a 2 2 NA
3 a 3 NA NA
4 b 4 NA NA
5 b 5 5 NA
6 b 6 6 NA
7 c 7 7 5
8 c 8 8 5
9 c 9 9 5
Je pense que dplyr
convient très bien à cette tâche.
En utilisant replace()
comme suggéré par @thelatemail, vous pourriez faire quelque chose comme ceci:
library("dplyr")
df <- df %>%
mutate_at(vars(starts_with("var")),
funs(replace(., . %in% c(3, 4), NA)))
df
# name foo var1 var2
# 1 a 1 1 NA
# 2 a 2 2 NA
# 3 a 3 NA NA
# 4 b 4 NA NA
# 5 b 5 5 NA
# 6 b 6 6 NA
# 7 c 7 7 5
# 8 c 8 8 5
# 9 c 9 9 5