2012-03-26 10 views
7

Mam wektor/tablicę n elementów. Chcę wybrać m elementów.Wybierz m równomiernie rozmieszczone elementy z sekwencji o długości n

Wybory muszą być sprawiedliwe/deterministyczny - równie wiele z każdej podsekcji.

m = 10, N = 20 jest proste: ma co drugi element. Ale jak to zrobić w ogólnym przypadku? Czy muszę obliczyć LCD?

+12

co jest złego w wyborze pierwszego ' elementy m? wydaje się, że istnieje pewne ograniczenie, które sugerujesz, ale nie opisałeś go. –

+2

Czy chcesz przyjąć pozycje 'm' równomiernie rozłożone na' n'? – hamstergene

+0

Dzięki. Musi być sprawiedliwe - potrzebuję jednakowo dużo z każdej podsekcji - tj. Z każdej części oryginalnej tablicy. To musi być rozłożone. – j13r

Odpowiedz

9

Oto krótki przykład:

from math import ceil 

def takespread(sequence, num): 
    length = float(len(sequence)) 
    for i in range(num): 
     yield sequence[int(ceil(i * length/num))] 

math.ceil jest używana, ponieważ bez niego, wybrane indeksy będą ważone zbytnio ku początku każdego niejawnego podrozdziale, w wyniku czego lista jako całość.

+0

Dlaczego potrzebujemy tutaj sufitu? Czy obcięcie int nie wykona zadania, tj. Po prostu wyda sekwencję [i * length/num] – j13r

+0

@ j13r Obiekty będą ważone na początku listy zbyt wiele, jeśli użyjesz niejawnej 'podłogi '. – agf

+0

nie zaokrągliłaby, żeby mieć więcej sensu niż wtedy? – j13r

17

Prawdopodobnie trzeba Bresenham's line algorithm. Wybór m elementy równomiernie od n jest równoważna rysując linię m x n dyskretnej siatce pikseli. Przyjmij współrzędne x w 0 .. n-1 i y we współrzędnych 0 .. m-1 i postępuj tak, jakby rysować linię między (0,0) i (n-1, m-1). Ilekroć koordynacja y zmienia się, wybierz element z indeksu x.

UPD: Ale wydaje się, że ta prosta czynność wystarczy Ci:

>>> f = lambda m, n: [i*n//m + n//(2*m) for i in range(m)] 
>>> f(1,20) 
[10] 
>>> f(2,20) 
[5, 15] 
>>> f(3,20) 
[3, 9, 16] 
>>> f(5,20) 
[2, 6, 10, 14, 18] 
+0

Ponieważ '//' działa również na Pythonie 2, lepiej jest być jawnym i używać go, gdy chodzi o dzielenie obcięte. – agf

+0

@agf Rzeczywiście. Zaktualizowano. – hamstergene

1

Użyj pętli (int i = 0; i < m; i ++)

Następnie, aby uzyskać indeksy chcesz , Ceil (i * m/n).

0

pracuję w praktyce klinicznej i znaleźć wszystkie odpowiedzi powyżej mieć różne stopnie nastawienia. Oto inne rozwiązanie, które działa dobrze nawet w kręgu. Oznacza to, że nawet jeśli ostatnia liczba owija się tak jak podczas pracy z stopniami 0 ° = 360 °.

import numpy as np 
m = 51 
# Generate intervals 
epts = np.linspace(0,360,m+1,endpoint=True) 
# Create the halfsteps between intervals (One would have sufficed) 
halfsteps = (epts[1:] - epts[:-1])/2 
# Find the midpoints 
midpoints = epts[:-1] + halfsteps 
# Make an unbiased rounding 
results = np.around(midpoints, decimals=0) 
+0

można po prostu obliczyć punkty środkowe z 'midpoints = (epts [1:] + epts [: - 1])/2', powinny mieć taki sam lub lepszy wynik, jeśli uważasz, że' halfsteps' może być zbyt mały, gdy m jest zbyt duży – AngelLeliel

0

to zawsze wybiera pierwsze i ostatnie elementy:

which_idxs = lambda m, n: np.rint(np.linspace(1, n, min(m,n)) - 1).astype(int) 

evenly_spaced = np.array(your_list)[which_idxs(m,n)] 

ten wybiera tylko maksymalnie n elementów, w przypadku gdy m jest większe niż n. Jeśli naprawdę chcesz go równo rozłożone w całej tablicy, nawet na końcach, to byłoby to zamiast:

which_idxs = lambda m, n: [idx for idx in np.rint(np.linspace(1-n/(2*min(m,n)), n+n/(2*min(m,n)), min(m,n)+2) - 1).astype(int) if idx in range(n)] 

evenly_spaced = np.array(your_list)[which_idxs(m,n)] 

co daje mniej więcej tak:

>>> np.array([1, 2, 3, 'a', 'b', 'c'])[which_idxs(m,n)] 
Out: array(['2', 'b']) 
Powiązane problemy