4

我正在尝试np.array通过从 python 生成器中采样来构造一个,每次调用next. 这是一些示例代码:

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

extract_one_class函数返回一个数据子集:属于一个类标签的所有数据点。我想得到积分np.array。_ shape = (size,data.shape[1])目前上面的代码片段返回一个错误:

ValueError: setting an array element with a sequence.

fromiter声明返回一维数组的文档。还有一些人以前使用 fromiter 在 numpy 中构造记录数组(例如http://iam.al/post/21116450281/numpy-is-my-homeboy)。

假设我可以以这种方式生成一个数组,我是否偏离了标准?还是我的 numpy 不太对劲?

4

3 回答 3

9

正如您所注意到的,文档np.fromiter解释了该函数创建一维数组。您将无法以这种方式创建 2D 数组,而 @unutbu 返回您之后重塑的 1D 数组的方法是肯定的。

但是,您确实可以使用 创建结构化数组fromiter,如下所示:

>>> 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', '<i8'), ('f1', '<i8')])

但是,看,r.shape=(3,)实际上r只是一维记录数组,每条记录由两个整数组成。因为所有字段都相同dtype,所以我们可以将其r视为 2D 数组

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

所以,是的,您可以尝试使用np.fromiterlike dtype[('',int)]*data.shape[1]您将获得一个长度为 1D 的数组size,然后您可以将该数组视为((int, data.shape[1])). 您可以使用浮点数而不是整数,重要的是所有字段都具有相同的数据类型。

如果你真的想要它,你可以使用一些相当复杂dtype的 . 考虑例如

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

在这里,您得到一个具有 1 个字段的一维结构化数组,该字段由 2 个整数组成的数组组成。请注意使用(_,)确保每个记录作为元组传递(否则np.fromiter阻塞)。但是你需要那种复杂性吗?

另请注意,由于您事先知道数组的长度(它是size),因此您应该使用counter可选参数 ofnp.fromiter以提高效率。

于 2012-09-18T08:50:27.113 回答
4

您可以修改generate_points以产生单个浮点数而不是 np.arrays,用于np.fromiter形成一维数组,然后用于.reshape(size, -1)使其成为二维数组。

points = np.fromiter(
    generate_points(data,labels,5)).reshape(size, -1)
于 2012-09-17T22:24:21.267 回答
1

根据此处的一些建议,我想出了一个相当通用的替代品numpy.fromiter(),可以满足 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])["_"]
于 2015-06-04T14:29:34.043 回答