Ответ 1
Попробуйте преобразовать ваш df в матрицу.
df <- data.frame(a=rnorm(1000),b=rnorm(1000))
m <- as.matrix(df)
m[m<0] <- 0
df <- as.data.frame(m)
У меня есть dataframe из 150 000 строк с 2000 столбцами, содержащими значения, некоторые из которых являются отрицательными. Я заменяю эти отрицательные значения на 0, но делать это очень медленно (~ 60 мин или более).
df[df < 0] = 0
где df[,1441:1453]
выглядит как (все столбцы/значения числовые):
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
Есть ли способ ускорить такой процесс, например, как я это делаю, это очень медленно, и для этого существует более быстрый подход? Спасибо.
Попробуйте преобразовать ваш df в матрицу.
df <- data.frame(a=rnorm(1000),b=rnorm(1000))
m <- as.matrix(df)
m[m<0] <- 0
df <- as.data.frame(m)
Как ваш оригинальный подход, так и текущий ответ создают объект с тем же размером, что и m
(или df
) при создании m<0
(матричный подход быстрее, потому что меньше внутреннего копирования с [<-
по сравнению с [<-.data.frame
Вы можете использовать lapply
и replace
, тогда вы смотрите только на вектор или length (nrow(df))
каждый раз
и не копировать так много
df <- as.data.frame(lapply(df, function(x){replace(x, x <0,0)})
Вышеприведенный код должен быть достаточно эффективным.
Если вы используете data.table
, тогда большая часть неэффективности использования памяти (и) подхода data.frame
удаляется. Это было бы идеально для такой большой ситуации с данными, как ваша.
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)})
Вы можете устанавливать ключи во всех столбцах, а затем заменять ссылкой на значения ключей менее 0
Другой ответ на data.table может быть быстрее и определенно должен занимать меньше памяти.
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
Символ .j
используемый в аргументе i
повторяется и заменяется столбцами из аргумента j
.