vectores recodificar programacion manejar estadistico eliminar ejemplos datos con como comandos ciencia analisis r data.table r6

programacion - recodificar variables en r



Subasignar por referencia en el vector en R (2)

¿Puedo usar la subasignación por referencia en vectores atómicos de alguna manera?
Por supuesto, sin envolverlo en 1 columna data.table para usar := .

library(data.table) N <- 5e7 x <- sample(letters, N, TRUE) X <- data.table(x = x) upd_i <- sample(N, 1L, FALSE) system.time(x[upd_i] <- NA_character_) # user system elapsed # 0.11 0.06 0.17 system.time(X[upd_i, x := NA_character_]) # user system elapsed # 0.00 0.00 0.03

Si R6 puede ayudar en eso, estoy abierto a la solución R6, ya que es una de mis funciones.
Ya he comprobado que <- dentro del objeto R6 todavía hace copia: gist .


En la versión más reciente de R (3.1-3.1.2 o más), la asignación a un vector no se copia. Sin embargo, no verá eso ejecutando el código de OP, y la razón es la siguiente. Debido a que reutiliza x y lo asigna a algún otro objeto, R no recibe notificación de que x se copia en ese momento y debe asumir que no lo será (en el caso particular anterior, creo que será bueno cambiar) se encuentra en data.table::data.table y notifica a R que se ha realizado una copia, pero ese es un problema por separado ( data.frame mismo problema), y debido a eso copia x en el primer uso. Si cambia un poco el orden de los comandos, no verá ninguna diferencia:

N <- 5e7 x <- sample(letters, N, TRUE) upd_i <- sample(N, 1L, FALSE) # no copy here: system.time(x[upd_i] <- NA_character_) # user system elapsed # 0 0 0 X <- data.table(x = x) system.time(X[upd_i, x := NA_character_]) # user system elapsed # 0 0 0 # but now R will copy: system.time(x[upd_i] <- NA_character_) # user system elapsed # 0.28 0.08 0.36

(respuesta antigua, mayormente dejada por curiosidad)

Realmente puede usar el operador data.table := para modificar su vector en su lugar (creo que necesita la versión R 3.1+ para evitar la copia en la list ):

modify.vector = function (v, idx, value) setDT(list(v))[idx, V1 := value] v = 1:5 address(v) #[1] "000000002CC7AC48" modify.vector(v, 4, 10) v #[1] 1 2 3 10 5 address(v) #[1] "000000002CC7AC48"


Según lo sugerido por @Frank, es posible hacer esto usando Rcpp . Aquí hay una versión que incluye una macro inspirada en el dispatch.h de Rcpp que maneja todos los tipos de vectores atómicos:

mod_vector.cpp

#include <Rcpp.h> using namespace Rcpp; template <int RTYPE> Vector<RTYPE> mod_vector_impl(Vector<RTYPE> x, IntegerVector i, Vector<RTYPE> value) { if (i.size() != value.size()) { stop("i and value must have same length."); } for (int a = 0; a < i.size(); a++) { x[i[a] - 1] = value[a]; } return x; } #define __MV_HANDLE_CASE__(__RTYPE__) case __RTYPE__ : return mod_vector_impl(Vector<__RTYPE__>(x), i, Vector<__RTYPE__>(value)); // [[Rcpp::export]] SEXP mod_vector(SEXP x, IntegerVector i, SEXP value) { switch(TYPEOF(x)) { __MV_HANDLE_CASE__(INTSXP) __MV_HANDLE_CASE__(REALSXP) __MV_HANDLE_CASE__(RAWSXP) __MV_HANDLE_CASE__(LGLSXP) __MV_HANDLE_CASE__(CPLXSXP) __MV_HANDLE_CASE__(STRSXP) __MV_HANDLE_CASE__(VECSXP) __MV_HANDLE_CASE__(EXPRSXP) } stop("Not supported."); return x; }

Ejemplo:

x <- 1:20 address(x) #[1] "0x564e7e8" mod_vector(x, 4:5, 12:13) # [1] 1 2 3 12 13 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 address(x) #[1] "0x564e7e8"

Comparación con los métodos base y data.table. Se puede ver que es mucho más rápido:

x <- 1:2e7 microbenchmark::microbenchmark(mod_vector(x, 4:5, 12:13), x[4:5] <- 12:13, modify.vector(x, 4:5, 12:13)) #Unit: microseconds # expr min lq mean median uq # mod_vector(x, 4:5, 12:13) 5.967 7.3480 15.05259 9.718 21.0135 # x[4:5] <- 12:13 2.953 5.3610 45722.61334 48122.996 52623.1505 # modify.vector(x, 4:5, 12:13) 954.577 988.7785 1177.17925 1021.380 1361.1210 # max neval # 58.463 100 # 126978.146 100 # 1559.985 100