4

np.arrayの呼び出しごとに配列の 1 つの行を生成する、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関数は、データのサブセットを返します。つまり、1 つのクラス ラベルに属するすべてのデータ ポイントです。ポイントnp.arraywithにしたいと思いshape = (size,data.shape[1])ます。現在、上記のコード スニペットはエラーを返します。

ValueError: setting an array element with a sequence.

fromiter1 次元配列を返すと主張するドキュメント。さらに、以前に fromiter を使用して numpy でレコード配列を構築した人もいます (例: http://iam.al/post/21116450281/numpy-is-my-homeboy )。

この方法で配列を生成できると仮定して、私は的外れですか? または、私のnumpyはまったく正しくありませんか?

4

3 に答える 3

9

お気づきのとおり、 のドキュメントでnp.fromiterは、関数が 1D 配列を作成すると説明しています。そのように2D配列を作成することはできません。後で再形成する1D配列を返す@unutbuメソッドは確実です。

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実際にはレコードの 1D 配列に過ぎず、各レコードは 2 つの整数で構成されています。すべてのフィールドの が同じであるため、 を 2D 配列としてdtype表示できます。r

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

したがって、はい、likeで使用np.fromiterすることもできます: length の 1D 配列を取得し、この配列を として表示できます。int の代わりに float を使用できます。重要な部分は、すべてのフィールドが同じ dtype を持つことです。dtype[('',int)]*data.shape[1]size((int, data.shape[1]))

本当に必要な場合は、かなり複雑なdtype. たとえば、

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

ここでは、1 つのフィールドを持つ 1D 構造化配列を取得します。フィールドは 2 つの整数の配列で構成されます。(_,)各レコードがタプルとして渡されることを確認するために を使用することに注意してください(それ以外の場合はnp.fromiterチョークします)。しかし、その複雑さが必要ですか?

また、配列の長さは事前にわかっているので (それは です)、効率を高めるためにオプションの引数 をsize使用する必要があることにも注意してください。counternp.fromiter

于 2012-09-18T08:50:27.113 に答える
4

You could modify generate_points to yield single floats instead of np.arrays, use np.fromiter to form a 1D array, and then use .reshape(size, -1) to make it a 2D array.

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 に答える