variable valores valor una reemplazar por perdidos modificar columna cambiar buscar r replace sequence

valores - buscar y reemplazar secuencia numérica en r



modificar una columna en r (3)

Aquí hay una solución sin lazo que usa rle() y inverse.rle() .

data <- c(1,1,1,0,0,1,1,2,2,2,0,0,0,2,1,1,0,1,0,2) local({ r <- rle(data) x <- r$values x0 <- which(x==0) # index positions of zeroes xt <- x[x0-1]==x[x0+1] # zeroes surrounded by same value r$values[x0[xt]] <- x[x0[xt]-1] # substitute with surrounding value inverse.rle(r) }) [1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2

PD. Utilizo local() como un mecanismo simple para no saturar el espacio de trabajo con montones de nuevos objetos temporales. Podrías crear una function lugar de usar local , solo encuentro que actualmente uso mucho local para este tipo de tarea.

PPS. Deberá modificar este código para excluir ceros iniciales o finales en sus datos originales.

Tengo un marco de datos con una secuencia de números similar a la siguiente:

data <- c(1,1,1,0,0,1,1,2,2,2,0,0,0,2,1,1,0,1,0,2)

Lo que necesito es algo para ubicar todas las instancias de 1, 2 o 3 repeticiones de 0 donde los números de procedimiento y siguientes son idénticos, es decir, ambos 1 o ambos 2 (por ejemplo 1,0,1 o 2,0,0,2 pero NO 2,0,1).

Entonces necesito completar los ceros solo con el valor circundante.

Logré localizar y contar ceros consecutivos

consec <- (!data) * unlist(lapply(rle(data)$lengths, seq_len))

entonces he encontrado la fila donde comienzan estos ceros consecutivos:

consec <- as.matrix(consec) first_na <- which(consec==1,arr.ind=TRUE)

Pero estoy perplejo con el proceso de reemplazo

¡Realmente apreciaría tu ayuda con esto!

Carl


Dado que parece haber mucho interés en la respuesta a esta pregunta, pensé que escribiría un método alternativo de expresiones regulares para la posteridad.

Usando la función ''gregexpr'', puede buscar patrones y usar las correspondencias de ubicación resultantes y las longitudes de coincidencia para indicar qué valores cambiar en el vector original. La ventaja de utilizar expresiones regulares es que podemos ser explícitos sobre exactamente qué patrones queremos que coincidan, y como resultado, no tendremos ningún caso de exclusión de qué preocuparse.

Nota: El siguiente ejemplo funciona como está escrito, porque asumimos valores de un solo dígito. Podríamos adaptarlo fácilmente para otros patrones, pero podemos tomar un pequeño atajo con caracteres únicos. Si quisiéramos hacer esto con posibles valores de varios dígitos, nos gustaría agregar un carácter de separación como parte de la primera función de concatenación (''pegar'').

El código

str.values <- paste(data, collapse="") # String representation of vector str.matches <- gregexpr("1[0]{1,3}1", str.values) # Pattern 101/1001/10001 data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1 # Replace zeros with ones str.matches <- gregexpr("2[0]{1,3}2", str.values) # Pattern 202/2002/20002 data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2 # Replace zeros with twos

Paso 1 : crea una sola cadena de todos los valores de datos.

str.values <- paste(data, collapse="") # "11100112220002110102"

Esto colapsará los datos en una cadena larga, por lo que podemos usar una expresión regular en ella.

Paso 2 : aplique una expresión regular para encontrar las ubicaciones y longitudes de cualquier coincidencia dentro de la cadena.

str.matches <- gregexpr("1[0]{1,3}1", str.values) # [[1]] # [1] 3 16 # attr(,"match.length") # [1] 4 3 # attr(,"useBytes") # [1] TRUE

En este caso, estamos usando una expresión regular para buscar el primer patrón, de uno a tres ceros ( [0]{2,} ) con unos a cada lado ( 1[0]{1,3}1 ). Tendremos que coincidir con el patrón completo, para evitar tener que verificar si hay coincidencias o dos en los extremos. Restaremos esos extremos en el siguiente paso.

Paso 3 : Escribe unos en todas las ubicaciones coincidentes en el vector original.

data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1 # 1 1 1 1 1 1 1 2 2 2 0 0 0 2 1 1 1 1 0 2

Estamos haciendo unos pocos pasos aquí todos a la vez. Primero, estamos creando una lista de secuencias de números a partir de los números que coinciden en la expresión regular. En este caso, hay dos coincidencias, que comienzan en los índices 3 y 16 y tienen 4 y 3 elementos de longitud, respectivamente. Esto significa que nuestros ceros están ubicados en los índices (3 + 1) :( 3-2 + 4), o 4: 5 y en (16 + 1) :( 16-2 + 3), o 17:17. Concatenamos (''pegan'') estas secuencias usando nuevamente la opción ''colapsar'', en caso de que haya múltiples coincidencias. Luego, usamos una segunda concatenación para poner las secuencias dentro de una función de combinación ( c() ). Usando las funciones ''eval'' y ''analizar'', convertimos este texto en código y lo pasamos como valores de índice a la matriz [data]. Escribimos todos en esos lugares.

Paso x : repite para cada patrón. En este caso, debemos hacer una segunda búsqueda y encontrar de uno a tres ceros con dos en cada lado y luego ejecutar la misma declaración que en el Paso 3, pero asignando dos, en lugar de unos.

str.matches <- gregexpr("2[0]{1,3}2", str.values) # [[1]] # [1] 10 # attr(,"match.length") # [1] 5 # attr(,"useBytes") # [1] TRUE data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2 # 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2

Actualización : me di cuenta de que el problema original decía que coincidía con uno a tres ceros en una fila, en lugar de los "dos o más" que escribí en el código original. He actualizado las expresiones regulares y la explicación, aunque el código sigue siendo el mismo.


Puede haber una solución sin un bucle for , pero puede intentar esto:

tmp <- rle(data) val <- tmp$values for (i in 2:(length(val)-1)) { if (val[i]==0 & val[i-1]==val[i+1]) val[i] <- val[i-1] } tmp$values <- val inverse.rle(tmp)

Lo que da :

[1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2