2015-06-16 19 views
6

Hãy nói rằng tôi có vectơ sau:Nhóm số tương tự của một vector

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

và tôi muốn "nhóm" phần tử của nó theo giá trị của họ: con số mà khác nhau < = 3 nên được coi là thuộc về cùng một nhóm. Trong trường hợp này tôi muốn, đối với mỗi số xuất hiện trong vectơ, để có được tất cả các con số gần với nó. Ví dụ,

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

vv

Có thể, nó có thể hữu ích để có được cũng chỉ mục của họ ... Có cách nào thông minh để đạt được điều này?

Trả lời

9

Bạn có thể sử dụng chức năng này chút:

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

sẽ không làm tổn thương để sửa đổi: 'return (danh sách (sim = vec [close.index], index = close.index))' –

2

Có lẽ không phải là phiên bản thanh lịch nhất, nhưng điều này không làm những gì bạn muốn có?

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 

nó thực sự là một chút thanh lịch hơn để sử dụng 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

Cảm ơn vi sự giup đơ của hai bạn! – Ruggero

0

Nó có thể hữu ích để tạo ra danh sách với những con số như "chìa khóa":

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 

Sau đó, để truy cập vào nhóm và chỉ số cho '12', nói:

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

đây là một giải pháp ngắn đem lại cho bạn tất cả các nhóm như một danh sách:

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 

Đối với các chỉ số, khái niệm tương tự có thể được áp dụng một cách dễ dàng:

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

giải pháp tốt nhất cho đến nay. 'bên ngoài 'là một số thứ mạnh mẽ. +1 –

Các vấn đề liên quan