trucos rapido rapida prueba para niños multiplicar multiplicaciones multiplicacion metodos hace formas ejemplos diferentes cruz como r dataframe

rapido - ¿Cuál es la forma correcta de multiplicar el cuadro de datos por el vector?



prueba de la multiplicacion en cruz ejemplos (6)

Creo que la forma más rápida (sin probar data.table) es data.frame(t(t(df)*v)) .

Mis pruebas

testit <- function(nrow, ncol) { df <- as.data.frame(matrix(rnorm(nrow*ncol),nrow=nrow,ncol=ncol)) v <- runif(ncol) r1 <- data.frame(t(t(df)*v)) r2 <- data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)) r3 <- df * rep(v, each=nrow(df)) stopifnot(identical(r1, r2) && identical(r1, r3)) microbenchmark(data.frame(t(t(df)*v)), data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)), df * rep(v, each=nrow(df))) }

Resultado

> set.seed(1) > > testit(100,100) Unit: milliseconds expr min lq median uq max neval data.frame(t(t(df) * v)) 2.297075 2.359541 2.455778 3.804836 33.05806 100 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE)) 9.977436 10.401576 10.658964 11.762009 15.09721 100 df * rep(v, each = nrow(df)) 14.309822 14.956705 16.092469 16.516609 45.13450 100 > testit(1000,10) Unit: microseconds expr min lq median uq max neval data.frame(t(t(df) * v)) 754.844 805.062 844.431 1850.363 27955.79 100 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE)) 1457.895 1497.088 1567.604 2550.090 4732.03 100 df * rep(v, each = nrow(df)) 5383.288 5527.817 5875.143 6628.586 32392.81 100 > testit(10,1000) Unit: milliseconds expr min lq median uq max neval data.frame(t(t(df) * v)) 17.07548 18.29418 19.91498 20.67944 57.62913 100 data.frame(mapply(`*`, df, v, SIMPLIFY = FALSE)) 99.90103 104.36028 108.28147 114.82012 150.05907 100 df * rep(v, each = nrow(df)) 112.21719 118.74359 122.51308 128.82863 164.57431 100

Estoy tratando de multiplicar una trama de datos df por un vector v , de modo que el producto sea una trama de datos, donde la i -ésima fila está dada por df[i,]*v . Puedo hacer esto, por ejemplo, por

df <- data.frame(A=1:5, B=2:6); v <- c(0,2) as.data.frame(t(t(df) * v)) A B 1 0 4 2 0 6 3 0 8 4 0 10 5 0 12

Estoy seguro de que tiene que haber un enfoque más de estilo R (¡y uno muy simple!), Pero no se me ocurre nada. Incluso intenté algo como

apply(df, MARGIN=1, function(x) x*v)

pero aún así, se requieren construcciones no legibles como as.data.frame(t(.)) .
¿Cómo puedo encontrar una solución eficiente y elegante aquí?


Esto funciona también:

data.frame(mapply(`*`,df,v))

En esa solución, está aprovechando el hecho de que data.frame es un tipo de list , por lo que puede iterar sobre los elementos de df y v al mismo tiempo con mapply .

Desafortunadamente, está limitado en lo que puede generar de mapply : como una simple list o una matrix . Si sus datos son enormes, esto probablemente sería más eficiente:

data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE))

Porque lo convertiría en una list , que es más eficiente convertirlo en un data.frame .


Qué hay de malo en

t(apply(df, 1, function(x)x*v))

?


Si está buscando velocidad y eficiencia de memoria - data.table . data.table para el rescate:

library(data.table) dt = data.table(df) for (i in seq_along(dt)) dt[, (i) := dt[[i]] * v[i]] eddi = function(dt) { for (i in seq_along(dt)) dt[, (i) := dt[[i]] * v[i]] } arun = function(df) { df * matrix(v, ncol=ncol(df), nrow=nrow(df), byrow=TRUE) } nograpes = function(df) { data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)) } N = 1e6 dt = data.table(A = rnorm(N), B = rnorm(N)) v = c(0,2) microbenchmark(eddi(copy(dt)), arun(copy(dt)), nograpes(copy(dt)), times = 10) #Unit: milliseconds # expr min lq mean median uq max neval # eddi(copy(dt)) 23.01106 24.31192 26.47132 24.50675 28.87794 34.28403 10 # arun(copy(dt)) 337.79885 363.72081 450.93933 433.21176 516.56839 644.70103 10 # nograpes(copy(dt)) 19.44873 24.30791 36.53445 26.00760 38.09078 95.41124 10

Como señala Arun en los comentarios, también se puede usar la función set del paquete data.table para realizar esta modificación in data.frame en data.frame ''s también:

for (i in seq_along(df)) set(df, j = i, value = df[[i]] * v[i])

Por supuesto, esto también funciona para las data.table de data.table y podría ser significativamente más rápido si el número de columnas es grande.


Un lenguaje que le permite combinar vectores con matrices tiene que tomar una decisión en algún punto, ya sea que las matrices estén ordenadas por filas mayores o por columnas. La razón:

> df * v A B 1 0 4 2 4 0 3 0 8 4 8 0 5 0 12

es porque R opera primero por las columnas. Hacer el truco de doble transposición subvierte esto. Lo siento si esto es solo una explicación de lo que sabes, pero no conozco otra forma de hacerlo, excepto expandir explícitamente v en una matriz del mismo tamaño.

O escribe una buena función que envuelva el código no muy del estilo R en algo que tenga el estilo R.


library(purrr) map2_dfc(df, v, `*`)

Punto de referencia

N = 1e6 dt = data.table(A = rnorm(N), B = rnorm(N)) v = c(0,2) eddi = function(dt) { for (i in seq_along(dt)) dt[, (i) := dt[[i]] * v[i]]; dt } arun = function(df) { df * matrix(v, ncol=ncol(df), nrow=nrow(df), byrow=TRUE) } nograpes = function(df) { data.frame(mapply(`*`,df,v,SIMPLIFY=FALSE)) } ryan = function(df) {map2_dfc(df, v, `*`) } library(microbenchmark) microbenchmark( eddi(copy(dt)) , arun(copy(dt)) , nograpes(copy(dt)) , ryan(copy(dt)) , times = 100) # Unit: milliseconds # expr min lq mean median uq max neval # eddi(copy(dt)) 8.367513 11.06719 24.26205 12.29132 19.35958 171.6212 100 # arun(copy(dt)) 94.031272 123.79999 186.42155 148.87042 251.56241 364.2193 100 # nograpes(copy(dt)) 7.910739 10.92815 27.68485 13.06058 21.39931 172.0798 100 # ryan(copy(dt)) 8.154395 11.02683 29.40024 13.73845 21.77236 181.0375 100