2011-04-17 12 views
5

entradaR: eliminar columnas basándose en la similitud de dos de columna visita

row.no column2 column3 column4 
1  bb   ee  up 
2  bb   ee  down 
3  bb   ee  up 
4  bb   yy  down 
5  bb   zz  up 

Tengo una regla para eliminar la fila 1 y 2 y 3, ya que mientras column2 y column3 para la fila 1, 2 y 3 son los mismos, datos contradictorios (upydown) se encuentran en la columna 4.

¿Cómo puedo pedir R para eliminar esas filas con el mismo nombre en column2 y column3 pero columna adjudicador 3 para dar como resultado una matriz como sigue:

row.no column2 column3 column4 
4  bb   yy  down 
5  bb   zz  up 

Respuesta

6

Las funciones en el paquete plyr realmente brillan ante este tipo de problema. Aquí hay una solución que usa dos líneas de código.

Configure los datos (amablemente proporcionados por @GavinSimpson)

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L)) 

de carga del paquete de plyr

library(plyr) 

Uso ddply para dividir, analizar y combinar dat. La siguiente línea de análisis de código divide dat en una combinación única de (columna2 y columna3) por separado. A continuación, agrego una columna llamada unique, que calcula el número de valores únicos de column4 para cada conjunto. Por último, utilizar una sencilla creación de subconjuntos para volver sólo aquellas líneas donde == 1 única, y derrama la columna 5.

df <- ddply(dat, .(column2, column3), transform, 
    row.no=row.no, unique=length(unique(column4))) 
df[df$unique==1, -5] 

y los resultados:

row.no column2 column3 column4 
4  4  bb  yy down 
5  5  bb  zz  up 
+0

+1 para usar plyr –

-1

Puede probar uno de los dos métodos siguientes. Supongamos que la tabla se llama 'tabla1'.

Método 1

repeated_rows = c(); 
for (i in 1:(nrow(table1)-1)){ 
    for (j in (i+1):nrow(table1)){ 
    if (sum((table1[i,2:3] == table1[j,2:3])) == 2){ 
     repeated_rows = c(repeated_rows, i, j) 
    } 
    } 
} 
repeated_rows = unique(repeated_rows) 
table1[-repeated_rows,] 

Método 2

duplicates = duplicated(table1[,2:3]) 
for (i in 1:length(duplicates)){ 
    if (duplicates[i] == TRUE){ 
    for (j in 1:nrow(table1)){ 
     if (sum(table1[i,2:3] == table1[j,2:3]) == 2){ 
     duplicates[j] = TRUE; 
     } 
    } 
    } 
} 
table1[!duplicates,] 
4

Aquí está uno potencial, aunque algo poco elegante, solución

out <- with(dat, split(dat, interaction(column2, column3))) 
out <- lapply(out, function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)}) 
out <- out[!sapply(out, is.null)] 
do.call(rbind, out) 

cual da:

> do.call(rbind, out) 
     row.no column2 column3 column4 
bb.yy  4  bb  yy down 
bb.zz  5  bb  zz  up 

Algunos explicación, línea por línea:

  • Línea 1: divide los datos en una lista, cada componente de las cuales es una trama de datos con filas correspondiente a grupos formados por combinaciones únicas de column2 y column3.
  • Línea 2: iterar sobre el resultado de la línea 1; si hay más de 1 fila en el marco de datos, devuelva NULL, si no devuelve el marco de datos de 1 fila.
  • Línea 3: iterar sobre la salida de la Línea 2; devolver sólo componentes no NULL
  • Línea 4: necesitan unirse, de modo de fila, la salida de la línea 3, que disponemos a través de do.call()

Esto se puede simplificar a dos líneas, la combinación de las líneas 1 -3 en una sola línea:

out <- lapply(with(dat, split(dat, interaction(column2, column3))), 
       function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)}) 
do.call(rbind, out[!sapply(out, is.null)]) 

Lo anterior fue hecho con:

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L)) 
+0

Gracias Gavin, al escribir la primera línea, Encontré el siguiente mensaje de error "Error en sort.list (y): 'x' debe ser atómico para 'sort.list' ¿Has llamado 'ordenar' en una lista?" ¿Podrías enseñarme cómo resolver este problema? – Catherine

+0

@sally leí en el fragmento de datos que mostró, está en un marco de datos llamado 'dat', el código para crear' dat' ahora está incluido en mi respuesta. No dice cómo se almacenan sus datos, así que usé la estructura de datos lógicos (un marco de datos). –

+0

+1 Para usar la base R – Andrie

4

Gavin mantiene elevar º e barra sobre la calidad de las respuestas. Aquí está mi intento.

# This is one way of importing the data into R 
sally <- textConnection("row.no column2 column3 column4 
1  bb   ee  up 
2  bb   ee  down 
3  bb   ee  up 
4  bb   yy  down 
5  bb   zz  up") 
sally <- read.table(sally, header = TRUE) 

# Order the data frame to make rle work its magic 
sally <- sally[order(sally$column3, sally$column4), ] 

# Find which values are repeating 
sally.rle2 <- rle(as.character(sally$column2)) 
sally.rle3 <- rle(as.character(sally$column3)) 
sally.rle4 <- rle(as.character(sally$oclumn4)) 

sally.can.wait2 <- sally.rle2$values[which(sally.rle3$lengths != 1)] 
sally.can.wait3 <- sally.rle3$values[which(sally.rle3$lengths != 1)] 
sally.can.wait4 <- sally.rle4$values[which(sally.rle4$lengths != 1)] 

# Find which lines have values that are repeating 
dup <- c(which(sally$column2 == sally.can.wait2), 
     which(sally$column3 == sally.can.wait3), 
     which(sally$column4 == sally.can.wait4)) 
dup <- dup[duplicated(dup)] 

# Display the lines that have no repeating values 
sally[-dup, ] 
+0

+1 Para usar 'rle' – Andrie

+0

+1 Interesante uso de' rle() '. ¿No podría usar 'lapply()' para organizar las llamadas 'rle()'? ¿Y de hecho para el siguiente código repetido? –

+0

@Gavin, cierto. Cada vez que crea algunos objetos hechos de manera similar, generalmente puede usar la familia de funciones apply. –

Cuestiones relacionadas