2012-06-22 14 views
5

Umożliwia powiedzieć, że posiada listę:Pythonie Uniquefying listę z domieszką

L = [15,16,57,59,14] 

lista zawiera mesurements, które nie są bardzo dokładne, to znaczy wartość rzeczywista elementu jest ± 2 z zarejestrowana wartość. Zatem 14,15 i 16 mogą mieć tę samą wartość. Co chcę zrobić, to ujednolicić tę listę, biorąc pod uwagę błędy pomiarowe. Wyjście powinno być do nich:

l_out = [15,57] 

lub

l_out = [(14,15,16),(57,59)] 

mam problemu wytwarzania albo powstają z pętli. Jestem jednak ciekaw, czy może być bardziej eleganckie rozwiązanie. Pomysły bardzo przydatne.

+5

Jakich rezultatów oczekujesz dla 'L = [1,2,3,4,5,6,7,8,10]'? – sloth

+0

A jaki byłby wynik [15,16,57,59,14,13]? – kosii

+0

Zdaję sobie sprawę z tego problemu, ale dane, które mam na myśli, są omijane w taki sposób, że odległość między grupami wynosi> 2 – root

Odpowiedz

5

Jak lazyr zauważył w komentarzach podobny problem został opublikowany here. Korzystanie z modułu klastra rozwiązanie mojego problemu byłoby:

>>> from cluster import * 
>>> L = [15,16,57,59,14] 
>>> cl = HierarchicalClustering(L, lambda x,y: abs(x-y)) 
>>> cl.getlevel(2) 
[[14, 15, 16], [57, 59]] 

lub (aby uzyskać unikalne listy z wartościami średnimi z każdej grupy):

>>> [mean(cluster) for cluster in cl.getlevel(2)] 
[15, 58] 
-1

Dla pętli to najprostszy sposób, ale jeśli naprawdę chcesz kod single-line:
l_out = list(set(tuple([tuple(filter(lambda i: abs(item - i) < 3, L)) for item in L])))
Bardzo niejasne chociaż wolałbym w wersji :)

+2

To nie zadziałałoby dla przykładu "[15,16,57,59,14,13]' –

+0

powiedział "Jestem świadomy problemu, ale dane które ja Mając na uwadze, jest po omacku ​​tak, że odległość między grupami jest> 2 " – lolopop

+1

ten warunek jest spełniony tutaj. twój program nie podzieli prawidłowo listy. –

2

Jeśli chcesz standardowych lib Python, itertool „s groupby jest twoim przyjacielem:

from itertools import groupby 

L = [15,16,57,59,14] 

# Stash state outside key function. (a little hacky). 
# Better way would be to create stateful class with a __call__ key fn. 
state = {'group': 0, 'prev': None} 
thresh = 2 

def _group(cur): 
    """Group if within threshold.""" 
    if state["prev"] is not None and abs(state["prev"] - cur) > thresh: 
     state["group"] += 1 # Advance group 
    state["prev"] = cur 
    return state["group"] 

# Group, then drop the group key and inflate the final tuples. 
l_out = [tuple(g) for _, g in groupby(sorted(L), key=_group)] 

print l_out 
# -> [(14, 15, 16), (57, 59)] 
+0

@ +1 Ryan nie jest zły :) – root

+0

Myślę, że można uniknąć stanu globalnego, grupując wartości w pary najpierw za pomocą 'l = posortowane (L); zip (l, l [1:]) ' –

+0

@NiklasB. -- tak! Innym sposobem byłby bardziej klasyczny wzór dekoracyjno-sortowo-niezdobny ... Albo chyba sortuj-dekoruj-grupuj-nieurodzaj;) –

2

Oto jak zrobiłbym to w czystej-Python podejścia:

s = sorted(L) 
b = [i + 1 for i, (x, y) in enumerate(zip(s, s[1:])) if y > x + 2] 
result = [s[i:j] for i, j in zip([None] + b, b + [None])] 

Tutaj b to lista "przerw", indeksów, w których kończy się klaster.

+0

@NiklasB. dzięki, błąd off-by-one; naprawiony. – ecatmur

Powiązane problemy