Eliminar filas que contengan valores mayores que las filas anteriores

publicado por: Anonymous

Tengo un masivo fichero csv que responde a la siguiente estructura minimizada:

Datos

Aquí la tabla de datos insertada:

Ronda   Tratamiento
5        A
6        A
7        A
6        A
7        A
3        B
4        B
5        B
6        B
7        B
6        C
7        C
6        C
7        C
5        C
6        C
7        C
6        B
7        B

La columna ronda contiene valores ordenados desde un valor arbitrario hasta 7.
Me gustaría eliminar de la columna ronda todas las filas que contengan un valor numérico para ronda mayor que el valor numérico de la fila anterior. O en otras palabras, conservar solamente las filas que contengan el primer valor en que la serie creciente hasta 7 se inicia.

Por ejemplo, en el ejemplo aportado, obtener algo así:

Ronda   Tratamiento
5        A
6        A
3        B
6        C
6        C
5        C
6        B

Estaba intentando crear una columna adicional con la idea de después borrar filas. Pero no estoy familiarizado con estas operaciones en R. Seguro que existe un método mucho más efectivo y directo. Copio, en cualquier caso los esfuerzos:

v <- c()
data$Round <- as.numeric(data$Round)
for (i in seq(1:(nrow(t)))) {
  v <-c(v, ifelse(t[i+1,5]> t[i,5], 1,0))
}
t$keep <- v
t<- t[!(t$keep==0),]

Gracias por la ayuda,

solución

Si pensamos el problema de otra forma podríamos decir que lo que buscas es obtener las filas dónde cada Tratamiento tenga el valor mínimo de Ronda para ese Tratamiento.

Partiremos de estos datos:

df <- data.frame(Ronda=c(5,6,7,5,6,7,3,4,5,6,7,7,7,6,7,6,6),
                 Tratamiento=c('A','A','A','A','A','A','B','B','B','B','B',
                               'C','C','C','C','C','C'))

Esto, usando R base puede resolverse de la siguiente forma:

  1. Obtenemos los valores mínimos de Ronda por cada Tratamiento usando aggregate() y la función min():

    minimos <- aggregate(Ronda ~ Tratamiento, df, min)
    
    minimos
      Tratamiento Ronda
    1           A     5
    2           B     3
    3           C     6
    
  2. Teniendo los valores mínimos de cada grupo vamos ahora a filtrar las filas del data.frame principal, hay varias formas, la que se me ocurre bien sencilla es usar merge() para hacer algo que en SQL se conoce como INNER JOIN es decir la intersección de los dos conjuntos de datos:

    merge(df,minimos,by = c("Ronda","Tratamiento"))
      Ronda Tratamiento
    1     3           B
    2     5           A
    3     5           A
    4     6           C
    5     6           C
    6     6           C
    

Puedes, y es muy recomendable, usar dplyr dónde las operaciones anteriores son mucho más legibles:

library(dplyr)

df %>% 
    group_by(Tratamiento) %>%    # Agrupamos por Tratamiento
    filter(Ronda == min(Ronda))  # Solo filas dónde Ronda sea el mínimo del grupo

Edición:

Según lo último que mencionas, necesitas la primer fila del primer valor de la serie ascendente, en este caso creo que con R base es más simple por que es un poco de aritmética de vectores:

df[c(max(df[,1]),df[1:nrow(df)-1,1]) - df[,1] > 0,]

   Ronda Tratamiento
1      5           A
4      6           A
6      3           B
11     6           C
13     6           C
15     5           C
18     6           B

Detalle:

  • Con c(max(df[,1]),df[1:nrow(df)-1,1]) generamos un vector con las Ronda pero desfazado un elemento y con el valor máximo como primero:

    [1] 7 5 6 7 6 7 3 4 5 6 7 6 7 6 7 5 6 7 6
    
  • Si lo restamos al vector original df[,1], es decir:

    [1] 5 6 7 6 7 3 4 5 6 7 6 7 6 7 5 6 7 6 7
    

    Obtendremos algo así:

    [1]  2 -1 -1  1 -1  4 -1 -1 -1 -1  1 -1  1 -1  2
    [16] -1 -1  1 -1
    

    Si prestamos atención, los valores positivos son justamente los primeros de cada serie ascendente, por lo que utilizaremos esto para “filtrar” las filas finales convirtiendo este vector en uno lógico: c(max(df[,1]),df[1:nrow(df)-1,1]) - df[,1] > 0 que usaremos para filtrar las filas que nos interesan.

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *