web-dev-qa-db-fra.com

Remplacement rapide des valeurs dans la structure de données dans R

J'ai une base de données de 150 000 lignes avec 2 000 colonnes contenant des valeurs, dont certaines sont négatives. Je remplace ces valeurs négatives par 0, mais le processus est extrêmement lent (environ 60 minutes ou plus). 

df[df < 0] = 0

df[,1441:1453] ressemble à (toutes les colonnes/valeurs numériques):

  V1441 V1442 V1443 V1444 V1445 V1446 V1447 V1448 V1449 V1450 V1451 V1452 V1453
1     3     1     0     4     4    -2     0     3    12     5    17    34    27
2     0     1     0     7     0     0     0     1     0     0     0     0     0
3     0     2     0     1     2     3     6     1     2     1    -6     3     1
4     1     2     3     6     1     2     1    -6     3     1    -4     1     0
5     1     2     1    -6     3     1    -4     1     0     0     1     0     0
6     1     0     0     1     0     0     0     0     0     0     1     2     2

Y a-t-il un moyen d'accélérer un tel processus, par exemple, la façon dont je le fais est très lente, et l'approche est plus rapide pour cela? Merci.

19
Benoit B.

Essayez de transformer votre DF en une matrice.

df <- data.frame(a=rnorm(1000),b=rnorm(1000))
m <- as.matrix(df)
m[m<0] <- 0
df <- as.data.frame(m)
30
Roland

L’approche initiale et la réponse actuelle créent un objet de la même taille que m (ou df) lors de la création de m<0 (l’approche matricielle est plus rapide car il y a moins de copies internes avec [<- par rapport à [<-.data.frame

Vous pouvez utiliser lapply et replace, alors vous ne regardez qu'un vecteur ou length (nrow(df)) à chaque fois .__ et ne copiez pas autant.

df <- as.data.frame(lapply(df, function(x){replace(x, x <0,0)})

Le code ci-dessus devrait être assez efficace.

Si vous utilisez data.table, la majeure partie de l'inefficacité mémoire (et) temporelle de l'approche data.frame est alors supprimée. Ce serait idéal pour une situation de données aussi volumineuse que la vôtre.

library(data.table)
# this really shouldn't be 
DT <- lapply(df, function(x){replace(x, x <0,0)})
# change to data.table
setattr(DT, 'class', c('data.table','data.frame'))
# or 
# DT <- as.data.table(df, function(x){replace(x, x <0,0)})

Vous pouvez définir des clés sur toutes les colonnes, puis les remplacer par des références inférieures à 0.

22
mnel

Une autre réponse de data.table, pourrait être plus rapide et devrait certainement consommer moins de mémoire. 

library(data.table)
set.seed(108)
d = data.table(a=rnorm(1000),b=rnorm(1000))
set.colwise = function(x, i, j, value) {
  replace_dot_j = function(e, j) {
    if (is.symbol(e) && identical(e, as.symbol(".j"))) return(j)
    if (is.call(e)) {
      if (e[[1L]] == ".j") e[[1L]] = j
      for (i in seq_along(e)[-1L]) if (!is.null(e[[i]])) e[[i]] = replace_dot_j(e[[i]], j)
    }
    e
  }
  for (jj in j) eval(substitute(
    set(x, .i, .j, value),
    list(
      .i=replace_dot_j(substitute(i), jj),
      .j=jj
    )
  ))
  invisible(x)
}
d
set.colwise(d, i = which(d[[.j]] < 0), j = c("a","b"), value = 0)
d

Le symbole .j utilisé dans l'argument i est itéré et remplacé par les colonnes de l'argument j.

0
jangorecki