Elija m elementos espaciados uniformemente de una secuencia de longitud n

Tengo un vector / matriz de n elementos. Quiero elegir m elementos.

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? ¿Tengo que calcular el LCD?

Aquí hay 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))] 

Se usa math.ceil porque sin él, los índices elegidos se ponderarán demasiado hacia el inicio de cada subsección implícita y, como resultado, la lista en su conjunto.

Probablemente necesitas el algoritmo de línea de Bresenham . Elegir m elementos uniformemente de n es equivalente a dibujar una línea en m x n cuadrícula de píxeles discretos. Suponga la coordenada x en 0 .. n-1 y coordenada y 0 .. m-1 , y proceda como si estuviera dibujando una línea entre (0,0) y (n-1, m-1). Siempre que cambie la coordenada y , elija un elemento del índice x .

UPD: Pero parece que esta simple función te bastará:

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

Esto siempre seleccionará los primeros y últimos 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 solo seleccionará un máximo de n elementos, en caso de que m sea mayor que n.

Si realmente quieres que se distribuya por igual en toda la matriz, incluso en los extremos, entonces sería esto:

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

Lo que te da algo como esto:

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

Use un bucle (int i = 0; i

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

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