Cómo construir un np.array con fromiter

Estoy tratando de construir un np.array muestreando desde un generador de python, que produce una fila de la matriz por invocación de la next . Aquí hay un código de ejemplo:

 import numpy as np data = np.eye(9) labels = np.array([0,0,0,1,1,1,2,2,2]) def extract_one_class(X,labels,y): """ Take an array of data X, a column vector array of labels, and one particular label y. Return an array of all instances in X that have label y """ return X[np.nonzero(labels[:] == y)[0],:] def generate_points(data, labels, size): """ Generate and return 'size' pairs of points drawn from different classes """ label_alphabet = np.unique(labels) assert(label_alphabet.size > 1) for useless in xrange(size): shuffle(label_alphabet) first_class = extract_one_class(data,labels,label_alphabet[0]) second_class = extract_one_class(data,labels,label_alphabet[1]) pair = np.hstack((first_class[randint(0,first_class.shape[0]),:],second_class[randint(0,second_class.shape[0]),:])) yield pair points = np.fromiter(generate_points(data,labels,5),dtype = np.dtype('f8',(2*data.shape[1],1))) 

La función extract_one_class devuelve un subconjunto de datos: todos los puntos de datos que pertenecen a una etiqueta de clase. Me gustaría que los puntos fueran un np.array con shape = (size,data.shape[1]) . Actualmente el fragmento de código anterior devuelve un error:

 ValueError: setting an array element with a sequence. 

La documentación de fromiter afirmaciones de fromiter de devolver una matriz unidimensional. Sin embargo, otros han usado fromiter para construir arreglos de discos en números antes (por ejemplo, http://iam.al/post/21116450281/numpy-is-my-homeboy ).

¿Estoy fuera de lugar al suponer que puedo generar una matriz de esta manera? ¿O es que mi número no está del todo bien?

Puede modificar los puntos de generate_points para generar flotantes individuales en lugar de np.arrays, usar np.fromiter para formar una matriz 1D y luego usar .reshape(size, -1) para convertirla en una matriz 2D.

 points = np.fromiter( generate_points(data,labels,5)).reshape(size, -1) 

Como ha notado, la documentación de np.fromiter explica que la función crea una matriz 1D. No podrá crear una matriz 2D de esa manera, y el método @unutbu de devolver una matriz 1D que luego reforme es seguro.

Sin embargo, puede crear matrices estructuradas utilizando fromiter , como se ilustra en:

 >>> import itertools >>> a = itertools.izip((1,2,3),(10,20,30)) >>> r = np.fromiter(a,dtype=[('',int),('',int)]) array([(1, 10), (2, 20), (3, 30)], dtype=[('f0', ' 

pero mira, r.shape=(3,) , es decir, r es más que una matriz de registros 1D, cada registro está compuesto de dos enteros. Como todos los campos tienen el mismo tipo de dtype , podemos ver r como una matriz 2D

 >>> r.view((int,2)) array([[ 1, 10], [ 2, 20], [ 3, 30]]) 

Entonces, sí, podrías intentar usar np.fromiter con un dtype como [('',int)]*data.shape[1] : obtendrás una matriz 1D de size de longitud, que luego podrás ver esta matriz como ((int, data.shape[1])) . Puede usar flotantes en lugar de ints, la parte importante es que todos los campos tienen el mismo tipo de dty.

Si realmente lo quieres, puedes usar un dtype bastante complejo. Consideremos por ejemplo

 r = np.fromiter(((_,) for _ in a),dtype=[('',(int,2))]) 

Aquí, obtiene una matriz 1D estructurada con 1 campo, el campo que consiste en una matriz de 2 enteros. Tenga en cuenta el uso de (_,) para asegurarse de que cada registro se pase como una tupla (de lo contrario np.fromiter chokes). ¿Pero necesitas esa complejidad?

Tenga en cuenta también que, como sabe de antemano la longitud de la matriz (su size ), debe usar el argumento opcional del counter de np.fromiter para obtener más eficiencia.

Siguiendo algunas sugerencias aquí, se me ocurrió un reemplazo bastante general para numpy.fromiter() que cumple con los requisitos del OP:

 import numpy as np def fromiter(iterator, dtype, *shape): """Generalises `numpy.fromiter()` to multi-dimesional arrays. Instead of the number of elements, the parameter `shape` has to be given, which contains the shape of the output array. The first dimension may be `-1`, in which case it is inferred from the iterator. """ res_shape = shape[1:] if not res_shape: # Fallback to the "normal" fromiter in the 1-D case return np.fromiter(iterator, dtype, shape[0]) # This wrapping of the iterator is necessary because when used with the # field trick, np.fromiter does not enforce consistency of the shapes # returned with the '_' field and silently cuts additional elements. def shape_checker(iterator, res_shape): for value in iterator: if value.shape != res_shape: raise ValueError("shape of returned object %s does not match" " given shape %s" % (value.shape, res_shape)) yield value, return np.fromiter(shape_checker(iterator, res_shape), [("_", dtype, res_shape)], shape[0])["_"]