2015-06-16 10 views
6

Diciamo aver il vettore seguente:Gruppo numero simile di un vettore

c(4, 5, 5, 8, 12, 12, 12, 13, 15, 15, 18, 19, 20, 23, 37, 37, 37, 37, 37, 41)

e desidero "gruppo" gli elementi in base al loro valore: numeri che differiscono < = 3 deve essere considerato appartenente allo stesso gruppo. In questo caso, per ogni numero visualizzato nel vettore, vorrei ottenere tutti i numeri che gli sono vicini. Per esempio,

4 --> c(4,5,5,8) 
5 --> c(4,5,5,8) 
8 --> c(5,8) 
12 --> c(12,12,12,13,15,15) 

ecc

Forse, potrebbe essere utile per avere anche loro indice ... Esiste un modo intelligente per raggiungere questo obiettivo?

risposta

9

È possibile utilizzare questa funzione poco:

similar <- function(vec, val, bound = 3, index = F) { 
    close.index <- which(abs(vec - val) <= bound) 
    if (index) return(close.index) 
    return(vec[close.index]) 
} 

x <- c(4, 5, 5, 8, 12, 12, 12, 13, 15, 15, 18, 19, 20, 23, 37, 37, 37, 37, 37, 41) 
similar(x, 5) 
# [1] 4 5 5 8 
similar(x, 5, index = T) 
# [1] 1 2 3 4 
similar(x, 5, bound = 7) 
# [1] 4 5 5 8 12 12 12 
+1

non sarebbe male per modificare: 'ritorno (lista (SIM = vec [close.index], index = close.index))' –

2
non

Forse la versione più elegante, ma lo fa fare quello che si voleva avere?

x <- c(4, 5, 5, 8, 12, 12, 12, 13, 15, 15, 18, 19, 20, 23, 37, 37, 37, 37, 37, 41) 
vals <- unique(x) 
# print indices 
for (i in 1:length(vals)) print(which((x >= vals[i] - 3) & (x <= vals[i] + 3))) 
# print values 
for (i in 1:length(vals)) print(x[which((x >= vals[i] - 3) & (x <= vals[i] + 3))]) 

[1] 1 2 3 
[1] 1 2 3 4 
[1] 2 3 4 
[1] 5 6 7 8 9 10 
[1] 5 6 7 8 9 10 
[1] 5 6 7 8 9 10 11 
[1] 9 10 11 12 13 
[1] 11 12 13 
[1] 11 12 13 14 
[1] 13 14 
[1] 15 16 17 18 19 
[1] 20 

[1] 4 5 5 
[1] 4 5 5 8 
[1] 5 5 8 
[1] 12 12 12 13 15 15 
[1] 12 12 12 13 15 15 
[1] 12 12 12 13 15 15 18 
[1] 15 15 18 19 20 
[1] 18 19 20 
[1] 18 19 20 23 
[1] 20 23 
[1] 37 37 37 37 37 
[1] 41 

è davvero un po 'più elegante da utilizzare abs.

for (i in 1:length(vals)) print(which(abs(x-vals[i]) <= 3)) 
for (i in 1:length(vals)) print(x[which(abs(x-vals[i]) <= 3)]) 
+0

Grazie ad entrambi per il vostro aiuto! – Ruggero

0

Potrebbe essere utile per creare liste con i numeri come "chiavi":

data <- c(4, 5, 5, 8, 12, 12, 12, 13, 15, 15, 18, 19, 20, 23, 37, 37, 37, 37, 37, 41) 
uniques <- unique(data) 

myGroups <- lapply(
    uniques, 
    function(n) Filter(
    function(x) abs(x - n) <= 3, 
    data 
) 
) 
names(myGroups) <- uniques 


myIndices <- lapply(
    uniques, 
    function(n) which(abs(data - n) <= 3) 
) 
names(myIndices) <- uniques 

Poi, per accedere al gruppo e indici per '12', dicono:

> myGroups[['12']] 
[1] 12 12 12 13 15 15 
> myIndices[['12']] 
[1] 5 6 7 8 9 10 
2

Ecco una breve soluzione che offre tutto il gruppo come elenco:

x = c(4, 5, 5, 8, 12, 12, 12, 13, 15, 15, 18, 19, 20, 23, 37, 37, 37, 37, 37, 41) 

m = unique(x) 
setNames(apply(abs(outer(m,m,'-')), 2, function(u) m[u<=3]),m) 

#$`4` 
#[1] 4 5 

#$`5` 
#[1] 4 5 8 

#$`8` 
#[1] 5 8 

#$`12` 
#[1] 12 13 15 

#$`13` 
#[1] 12 13 15 

#$`15` 
#[1] 12 13 15 18 

#$`18` 
#[1] 15 18 19 20 

#$`19` 
#[1] 18 19 20 

#$`20` 
#[1] 18 19 20 23 

#$`23` 
#[1] 20 23 

#$`37` 
#[1] 37 

#$`41` 
#[1] 41 

Per l'indice, lo stesso concetto può essere applicato facilmente:

setNames(apply(abs(outer(m,m,'-')), 2, function(u) which(x %in% m[u<=3])),m) 
+0

soluzione migliore finora. 'outer' è un po 'di roba potente. +1 –

Problemi correlati