2012-03-26 25 views
7

Tengo un vector/matriz de n elementos. Quiero elegir m elementos.Elija m elementos espaciados uniformemente de una secuencia de longitud n

Las opciones deben ser justas/deterministas, igualmente muchas de cada subsección.

Con m = 10, n = 20 es fácil: simplemente tome cada segundo elemento. ¿Pero cómo hacerlo en el caso general? ¿Debo calcular la pantalla LCD?

+12

cuál es incorrecto con la elección de la primera ' m' elementos? parece que hay alguna restricción que está implicando está allí, pero no la ha descrito. –

+2

¿Quiere tomar posiciones 'm' uniformemente repartidas en' n'? – hamstergene

+0

Gracias. Tiene que ser justo, necesito igualmente muchos de cada subsección, es decir, de cada parte de la matriz original. Necesita ser extendido. – j13r

Respuesta

9

Aquí está un ejemplo rápido:

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 se utiliza porque sin ella, los índices elegidos serán ponderados demasiado hacia el comienzo de cada subsección implícita, y como resultado de la lista en su conjunto.

+0

¿Por qué necesitamos ceil aquí? ¿No funcionaría el truncamiento interno, es decir, solo cederá la secuencia [i * length/num] – j13r

+0

@ j13r? Los objetos se ponderarán demasiado hacia el principio de la lista si usa el 'piso' implícito. – agf

+0

no sería redondo tiene más sentido, entonces? – j13r

17

Probablemente necesite Bresenham's line algorithm. Elegir m elementos uniformemente desde n es equivalente a dibujar una línea en m x n cuadrícula de píxeles discretos. Suponga x coordinar en 0 .. n-1 y y coordinar 0 .. m-1, y proceda como si estuviera dibujando una línea entre (0,0) y (n-1, m-1). Siempre que y cambios de coordenadas, elija un elemento del índice x.

UPD: Pero parece que esta función simple será suficiente que:

>>> 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

Dado que '//' también funciona en Python 2, es mejor ser explícito y usarlo cuando se quiere decir truncar la división. – agf

+0

@agf De hecho. Actualizado. – hamstergene

1

utilizar un bucle (int i = 0; i < m; i ++)

Luego de obtener los índices que desea , Ceil (i * m/n).

0

Estoy trabajando en una aplicación clínica y he encontrado que todas las respuestas anteriores tienen diferentes grados de sesgo. Aquí hay otra solución que funciona bien incluso en círculo. Es decir, incluso si el último número se ajusta como en cuando trabaja con grados 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

podría simplemente calcular puntos medios con 'puntos medios = (epts [1:] + epts [: - 1])/2', debería tener el mismo o mejor resultado si considera que' halfsteps' puede ser demasiado pequeño cuando m es demasiado grande – AngelLeliel

0

Esto siempre seleccionará el primer y último elementos:

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)] 

Esto sólo seleccionar un máximo de n elementos, en caso de que m es mayor que n. Si realmente quieres que igualmente se extendió por toda la matriz, incluso en los extremos, entonces sería esto en su lugar:

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)] 

que le da algo como esto:

>>> np.array([1, 2, 3, 'a', 'b', 'c'])[which_idxs(m,n)] 
Out: array(['2', 'b']) 
Cuestiones relacionadas