2012-06-12 13 views
10

Dada una lista a que contienen vectores de longitud desigual y un vector b que contiene algunos elementos de los vectores en a, quiero obtener un vector de longitud igual a b que contiene el índice de a donde el elemento de b partidos (esto es una mala explicación que conozco) ...Una manera rápida de conseguir el índice de coincidencia en la lista

el siguiente código hace el trabajo:

a <- list(1:3, 4:5, 6:9) 
b <- c(2, 3, 5, 8) 

sapply(b, function(x, list) which(unlist(lapply(list, function(y, z) z %in% y, z=x))), list=a) 
[1] 1 1 2 3 

Sustitución de la sapply con un bucle for logra el mismo de cours e

El problema es que este código se usará con listas y vectores con una longitud superior a 1000. En un conjunto de la vida real, la función tarda unos 15 segundos (tanto para el ciclo como sapply).

¿Alguien tiene una idea de cómo acelerar esto, seguro para un enfoque paralelo? No he podido ver un enfoque vectorizado (y no puedo programar en C, aunque probablemente sea el más rápido).

Editar:

limitaremos a destacar elegante solución utilizando partido de Aaron(), que dio un aumento de la velocidad del orden de 1667 veces (de 15 a 0.009)

amplié un poco en él para permitir que varios partidos (el retorno es entonces una lista)

a <- list(1:3, 3:5, 3:7) 
b <- c(3, 5) 
g <- rep(seq_along(a), sapply(a, length)) 
sapply(b, function(x) g[which(unlist(a) %in% x)]) 
[[1]] 
[1] 1 2 3 

[[2]] 
[1] 2 3 

el tiempo de ejecución para este era 0.169 que es posiblemente bastante más lento, pero por otro lado más flexible

+2

¿Qué quiere que haga el algoritmo si un elemento de 'b' aparece en más de un elemento de' a'? ¿Es eso posible en tu problema real? –

+0

Debería haber especificado que ... No es una posibilidad – ThomasP85

Respuesta

12

Aquí hay una posibilidad de usar match:

> a <- list(1:3, 4:5, 6:9) 
> b <- c(2, 3, 5, 8) 
> g <- rep(seq_along(a), sapply(a, length)) 
> g[match(b, unlist(a))] 
[1] 1 1 2 3 

findInterval es otra opción:

> findInterval(match(b, unlist(a)), cumsum(c(0,sapply(a, length)))+1) 
[1] 1 1 2 3 

Para devolver una lista, intente esto:

a <- list(1:3, 4:5, 5:9) 
b <- c(2,3,5,8,5) 
g <- rep(seq_along(a), sapply(a, length)) 
aa <- unlist(a) 
au <- unique(aa) 
af <- factor(aa, levels=au) 
gg <- split(g, af) 
gg[match(b, au)] 
+0

De 15 segundos a 0.009 - eso es una mejora impresionante. Descubrí que realmente me gustaría devolver una lista en lugar de un vector, para que pueda manejar múltiples coincidencias. He sustituido la última línea en su primera sugerencia con sapply (b, function (x) g [which (unlist (a)% in% x)]) para lograr esto. El tiempo de ejecución fue 0.169, que es bastante más lento que tu pero sigue siendo una mejora importante. – ThomasP85

0

Como comentario a tu post sugiere , depende de lo que quieras hacer si/cuando aparece el mismo elemento en varios vectores en a. Suponiendo que quiere el índice más bajo que puede hacer:

apply(sapply(a, function(vec) {b %in% vec}), 1, which.max) 
Cuestiones relacionadas