Imagine una matriz de números llamada A. En cada nivel de A, desea encontrar el elemento más reciente con un valor coincidente. Puede hacer esto fácilmente con un bucle for de la siguiente manera:

A = c(1, 1, 2, 2, 1, 2, 2)

for(i in 1:length(A)){   
  if(i > 1 & sum(A[1:i-1] == A[i]) > 0){ 
    answer[i] = max(which(A[1:i-1] == A[i]))
  }else{
    answer[i] = NA
  }
}

Pero quiero vectorizar esto para el bucle (porque aplicaré este principio en un conjunto de datos muy grande). Intenté usar sapply:

answer = sapply(A, FUN = function(x){max(which(A == x))})

Como puede ver, necesito alguna forma de reducir la matriz a solo valores anteriores a x. ¿Algún consejo?

1
Nick 10 sep. 2018 a las 06:24

4 respuestas

La mejor respuesta

Podemos usar seq_along para recorrer el índice de cada elemento y luego subconjunto y obtener el índice max donde ocurrió el último valor.

c(NA, sapply(seq_along(A)[-1], function(x) max(which(A[1:(x-1)] == A[x]))))
#[1]   NA    1 -Inf    3    2    4    6

Podemos cambiar -Inf a NA si es necesario en ese formato

inds <- c(NA, sapply(seq_along(A)[-1], function(x) max(which(A[1:(x-1)] == A[x]))))
inds[is.infinite(inds)] <- NA
inds
#[1] NA  1 NA  3  2  4  6

El método anterior da una advertencia, para eliminar la advertencia podemos realizar una comprobación adicional de length

c(NA, sapply(seq_along(A)[-1], function(x) {
  inds <- which(A[1:(x-1)] == A[x])
 if (length(inds) > 0)
   max(inds)
 else
   NA
}))

#[1] NA  1 NA  3  2  4  6
2
Ronak Shah 10 sep. 2018 a las 06:58

Aquí hay un enfoque con dplyr que es más detallado, pero más fácil de asimilar. Comenzamos registrando el número de fila, hacemos un grupo para cada número que encontramos y luego registramos la fila coincidente anterior.

library(dplyr)
A2 <- A %>% 
  as_tibble() %>%
  mutate(row = row_number()) %>%
  group_by(value) %>%
  mutate(last_match = lag(row)) %>%
  ungroup()
1
Jon Spring 10 sep. 2018 a las 04:33

Aquí hay una función que hice (basada en la respuesta de Ronak):

lastMatch = function(A){
  uniqueItems = unique(A)
  firstInstances = sapply(uniqueItems, function(x){min(which(A == x))}) #for NA
  notFirstInstances = setdiff(seq(A),firstInstances)
  lastMatch_notFirstInstances = sapply(notFirstInstances, function(x) max(which(A[1:(x-1)] == A[x])))
  X = array(0, dim = c(0, length(A)))
  X[firstInstances] = NA
  X[notFirstInstances] = lastMatch_notFirstInstances
  return(X)
}
0
Nick 10 sep. 2018 a las 05:36

Usted puede hacer:

sapply(seq_along(A)-1, function(x)ifelse(any(a<-A[x+1]==A[sequence(x)]),max(which(a)),NA))
[1] NA  1 NA  3  2  4  6
1
Onyambu 10 sep. 2018 a las 07:45