2011-02-23 7 views
8

Lo que quiero hacer es vergonzoso simple, sin embargo, no lo logro.multiplicar cada celda de un data.frame con su peso

Tengo un data.frame con "caracteres" y "numéricos". Una de las columnas de data.frame representa los pesos.

Quiero multiplicar cada celda del marco de datos con el peso correspondiente (si es numérico).

¿Cómo puedo hacer eso? (Lo mejor sin usar un bucle anidado).

¡Gracias de antemano!

Ejemplo:

c1 c2 w 
l1 abc 2 1 
l2 dxf 3 0.5 
l3 ghi 4 1.5 

debe convertirse en

c1 c2 w 
l1 abc 2 1 
l2 dxf 1.5 0.5 
l3 ghi 6 1.5 

Respuesta

6

Para un ejemplo reproducible, dd es una trama de datos con una mezcla de tipos de variables, con W siendo los pesos.

dd <- data.frame(G=gl(2,2), X=rnorm(4), Y=1L:4L, Z=letters[1:4], W=0.3:3.3) 
num.vars <- names(dd)[sapply(dd, is.numeric)] #select numeric variables 
num.vars <- setdiff(num.vars, "W") # remove the weight variable 
dd[num.vars] <- dd[num.vars] * dd$W # multiply 
+0

¡esto se ve brillante! – speendo

+0

Excelente técnica para extraer columnas numéricas y luego reinsertarlas. ¡Gracias! – drbv

5

Vectorise!

> dat <- data.frame(c1 = c("abc","dxf","ghi"), c2 = 2:4, w = c(1,0.5,1.5)) 

Efectivamente, desea c2 * w, pero necesita decir R mirar dentro la trama de datos:

> with(dat, c2 * w) 
[1] 2.0 1.5 6.0 

Qué podemos insertar de nuevo en dat en una sola línea:

> dat <- within(dat, c3 <- c2 * w) 
> dat 
    c1 c2 w c3 
1 abc 2 1.0 2.0 
2 dxf 3 0.5 1.5 
3 ghi 4 1.5 6.0 

(Reemplace c3 con c2 si desea sobrescribir el 01 existente.)

Si tiene más de una columna numérica que no sea pesas, se requiere una estrategia ligeramente diferente si desea automatizarla (es decir, no decirle a R qué columnas multiplicar por w).

> ## dummy data 
> dat2 <- data.frame(c1 = c("abc","dxf","ghi"), c2 = 2:4, w = c(1,0.5,1.5), 
        c3 = 5:7, c4 = 3:5) 
> ## select the columns we want, all numerics, but not `w` 
> want <- sapply(dat2, is.numeric) & names(dat2) != "w" 
> ## then use want to index into dat2 
> dat2[, want] <- with(dat2, dat2[, want] * w) 
> dat2 
    c1 c2 w c3 c4 
1 abc 2.0 1.0 5.0 3.0 
2 dxf 1.5 0.5 3.0 2.0 
3 ghi 6.0 1.5 10.5 7.5 
+0

gracias! Sé que esto funcionaría, pero tengo unas 200 columnas, por lo tanto, no puedo hacer todas esas multiplicaciones a mano.Pero supongo que habría una manera de hacer esto con apply o un foreach-loop ... – speendo

+1

@Marcel No noté las muchas columnas que forman parte de la Q inicialmente. Agregué un ejemplo de hacer lo mismo para muchas columnas mientras estabas escribiendo tu comentario. –

+0

mi culpa - no lo mencioné en mi pregunta inicial – speendo

2

Sólo por el placer de tratar de hacerlo en una sola línea (pero realmente no la más legible!):

R> dd <- data.frame(G=gl(2,2), X=rnorm(4), Y=1L:4L, Z=letters[1:4], W=0.3:3.3) 
R> dd 
    G   X Y Z W 
1 1 0.2319565 1 a 0.3 
2 1 0.4242205 2 b 1.3 
3 2 0.5218064 3 c 2.3 
4 2 0.7155944 4 d 3.3 

R> data.frame(lapply(subset(dd, select=-W), function(v, w=dd$W) { if (is.numeric(v)) v*w else v }), W=dd$W) 
    G   X Y Z W 
1 1 0.06958695 0.3 a 0.3 
2 1 0.55148670 2.6 b 1.3 
3 2 1.20015475 6.9 c 2.3 
4 2 2.36146163 13.2 d 3.3 
+0

¡Lo intenté de alguna manera como tú, pero fallé! Voy a ver esto con mucho cuidado! :) – speendo

1

Como se ha visto, hay un número de maneras de hacer esto, pero de alguna manera esperarías una manera realmente simple y no sé si eso existe. Hay una función de biblioteca en el paquete plyr llamada colwise que está cerca, pero no puedo encontrar una forma clara de hacer que haga exactamente lo que quiere. Lo mejor que puedo hacer es colwise satisfechas con esto (df asumiendo que su trama de datos se llama):

w2<-df$w df<-colwise(function(x,w){if(is.numeric(x)){x*w} else{x}})(df,df$w) df$w<-w2

Para aquellos que están familiarizados con colwise, no creo que usted puede simplemente utilizar numcolwise porque entonces las columnas no numéricos no se emiten en absoluto. Y no puedo encontrar una forma limpia de no tener la multiplicación aplicada al peso, por lo que simplemente la guardo y la restauro aquí. Creo que si se puede trabajar en una forma más limpia de hacerlo, colwise es una forma sencilla y fácil de entender para hacer esto.

+0

gracias! Realmente pensé que había un comando simple que haría todo, pero no importa, al menos aprendí algo ... – speendo

Cuestiones relacionadas