2012-05-15 12 views
12

Estoy trabajando en un conjunto de datos que incluye datos de la comunidad, y muchas de las columnas (especies) tienen muchos ceros. Me gustaría poder soltar estas columnas para algunos de los análisis que estoy haciendo, basados ​​en la suma de toda la columna. Estoy tentado de hacer esto con un bucle for, pero he oído que la aplicación y las funciones son mejores cuando se usa R. Mi objetivo es eliminar todas las columnas con una suma de menos de 15. Tengo which() utilizado para eliminar filas de factores, por ejemplo,Excluyendo columnas de un marco de datos basado en sumas de columna

September<-which(data$Time_point=="September") 

data<-data[-September,] 

y las dos maneras que he probado columnas quitar es mediante el uso de apply():

data<-data[,apply(data,2,function(x)sum(x<=15))] 

y mediante el uso de un desordenado para lazo/combo si otra cosa :

for (i in 6:length(data)){ 
    if (sum(data[,i])<=15) 
    data[,i]<-NULL 
    else 
    data[,i]<-data[,i] 
    } 

Ninguno de estos métodos ha funcionado. Sin duda, hay una forma elegante de deshacerse de las columnas en función de criterios lógicos.

str(head(data,10)) 
'data.frame': 10 obs. of 23 variables: 
$ Core_num : Factor w/ 159 levels "152","153","154",..: 133 72 70 75 89 85 86 90 95 99 
$ Cage_num : num 0 1 2 3 4 5 6 7 8 9 
$ Treatment : Factor w/ 4 levels "","C","CC","NC": 1 2 2 2 2 2 2 2 2 2 
$ Site  : Factor w/ 10 levels "","B","B07","B08",..: 1 8 8 8 7 7 7 7 9 9 
$ Time_point : Factor w/ 3 levels "","May","September": 1 2 2 2 2 2 2 2 2 2 
$ Spionidae : num 108 0 0 0 0 0 0 0 0 0 
$ Syllidae : num 185 0 0 0 3 8 0 1 4 1 
$ Opheliidae : num 424 0 1 0 0 0 1 1 0 0 
$ Cossuridae : num 164 0 7 3 0 0 0 0 0 0 
$ Sternaspidae: num 214 0 0 6 1 0 11 9 0 0 
$ Sabellidae : num 1154 0 2 2 0 ... 
$ Capitellidae: num 256 1 10 17 0 3 0 0 0 0 
$ Dorvillidae : num 21 1 0 0 0 0 0 0 0 0 
$ Cirratulidae: num 17 0 0 0 0 0 0 0 0 0 
$ Oligochaeta : num 3747 12 41 27 32 ... 
$ Nematoda : num 410 5 4 13 0 0 0 2 2 0 
$ Sipuncula : num 33 0 0 0 0 0 0 0 0 0 
$ Ostracoda : num 335 0 1 0 0 0 0 0 0 0 
$ Decapoda : num 62 0 4 0 1 0 0 0 0 0 
$ Amphipoda : num 2789 75 17 34 89 ... 
$ Copepoda : num 75 0 0 0 0 0 0 0 0 0 
$ Tanaidacea : num 84 0 0 0 1 0 0 0 0 0 
$ Mollusca : int 55 0 4 0 0 0 0 0 0 0 
+1

Sería mucho más fácil ayudar si proporcionó algunos datos reproducibles. Por ejemplo, la salida de 'str (head (data, 10))' probablemente sea suficiente. (Las versiones impresas de sus datos generalmente son inútiles, ya que son difíciles de copiar y pegar en ejemplos, y no proporcionan información sobre cómo se almacenan los datos, lo que puede ser crucial). – joran

+0

Gracias @joran. He editado la pregunta original para contener esa salida. ¡Lo siento por los inconvenientes ocasionados! – Margaret

Respuesta

13

¿Qué tal un subconjunto simple? En primer lugar, creamos una simple de datos Framel

R> dd = data.frame(x = runif(5), y = 20*runif(5), z=20*runif(5)) 

A continuación, seleccione las columnas donde la suma es mayor que 15

R> dd1 = dd[,colSums(dd) > 15] 
R> ncol(dd1) 
[1] 2 

En el conjunto de datos, sólo desea subconjunto columnas 6 en adelante, así que algo como :

##Drop the first five columns 
dd[,colSums(dd[,6:ncol(dd)]) > 15] 

o

#Keep the first six columns 
cols_to_drop = c(rep(TRUE, 5), dd[,6:ncol(dd)]>15) 
dd[,cols_to_drop] 

debería funcionar.


La parte clave a tener en cuenta es que en los corchetes, queremos un vector de Logicals, es decir, un vector de VERDADERO y FALSO. Entonces, si quisieras subconjunto usando algo un poco más complicado, entonces crea una función que devuelva VERDADERO o FALSO y un subconjunto como de costumbre.

3

Debería poder indexar directamente su data.frame con un valor booleano y colSums().Por ejemplo:

set.seed(123) 
dat <- data.frame(var1 = runif(10), var2 = rnorm(10), var3 = rlnorm(10)) 
colSums(dat) 
#----- 
    var1  var2  var3 
5.782475 1.317914 12.91987 
#Let's set the threshold at 5, so we should get var1 and var3 
> dat[, colSums(dat) > 5] 
#----- 
     var1  var3 
1 0.2875775 5.9709924 
2 0.7883051 1.6451811 
3 0.4089769 0.1399294 
... 

EDITAR - para hacer frente a las columnas no numéricos

set.seed(123) 
dat <- data.frame(var1 = runif(10), var2 = rnorm(10), var3 = rlnorm(10), var4 = "notNumeric") 

require(plyr) 
dat[, -which(numcolwise(sum)(dat) < 5)] 

Consolec:/Documents and Settings/Charles/escritorio/

> dat[, -which(numcolwise(sum)(dat) < 5)] 
     var1  var3  var4 
1 0.2875775 5.9709924 notNumeric 
2 0.7883051 1.6451811 notNumeric 
3 0.4089769 0.1399294 notNumeric 
..... 
+2

Indique al OP que no funcionó en su conjunto de datos en 3 ... 2 ... 1 ... (observe las primeras 6 columnas de su marco de datos). – joran

+0

'data [, c (1: 5, colSums (data [, 6: length (data)]> 15])]'. La versión de aplicación sería similar pero creo que 'colSums' es más rápido. – Justin

+0

@joran - bah , buen punto. Sin pensar demasiado, esto debería funcionar 'require (plyr); dat [, -which (numcolwise (sum (dat) Chase

1

Esto devolverá las columnas que no contiene todos los ceros, incluidos los factores y las columnas de caracteres (solo leo en el primer rowchunky de sus datos):

Leer en algunos de sus datos:

dat <- read.table(text=" Core_num Cage_num Treatment Site Time_point Spionidae Nereididae Syllidae Opheliidae 
6  24  1   C M2  May   0   0  0   0 
4  22  2   C M2  May   0   0  0   1 
9  27  3   C M2  May   0   0  0   0 
23  41  4   C M  May   0   0  3   0 
19  37  5   C M  May   0   0  8   0 
20  38  6   C M  May   0   0  0   1", header=T) 

El código:

summer <- function(x){ 
    if(is.numeric(x)){ 
     sum(x) > 15 
    } else { 
     TRUE 
    } 
} 

dat[, sapply(dat, summer)] 
Cuestiones relacionadas