باستخدام numpy لبناء مجموعة من مجموعات من اثنين صفائف

StackOverflow https://stackoverflow.com/questions/1208118

سؤال

أحاول تشغيل أكثر من المعلمات مساحة 6 المعلمة وظيفة الدراسة العددية السلوك قبل أن تحاول أن تفعل أي شيء معقد مع ذلك أنا في البحث عن طريقة فعالة للقيام بذلك.

بلدي وظيفة يأخذ تطفو القيم المعطاة 6-خافت numpy مجموعة الإدخال.ما حاولت القيام به في البداية هو هذا:

أولا أنا خلقت وظيفة أن يأخذ المصفوفات 2 وتوليد مجموعة مع جميع مجموعات من القيم من اثنين صفائف

from numpy import *
def comb(a,b):
    c = []
    for i in a:
        for j in b:
            c.append(r_[i,j])
    return c

ثم اعتدت reduce() إلى تطبيق ذلك على م نسخ من نفس مجموعة:

def combs(a,m):
    return reduce(comb,[a]*m)

ثم تقيم تعمل مثل هذا:

values = combs(np.arange(0,1,0.1),6)
for val in values:
    print F(val)

يعمل هذا ولكن هذا waaaay بطيئة جدا.أنا أعرف الفضاء من المعلمات ضخمة ، ولكن هذا لا يجب أن تكون بطيئة جدا.لدي عينات فقط 106 (مليون) نقطة في هذا المثال واستغرق أكثر من 15 ثانية فقط لإنشاء مجموعة values.

هل تعرف أي طريقة أكثر كفاءة للقيام بذلك مع numpy?

لا يمكن تعديل طريقة وظيفة F يأخذ الحجج إذا لزم الأمر.

هل كانت مفيدة؟

المحلول

في أحدث إصدار numpy (>1.8.x) ، numpy.meshgrid() يوفر أسرع بكثير التنفيذ:

@pv الحل

In [113]:

%timeit cartesian(([1, 2, 3], [4, 5], [6, 7]))
10000 loops, best of 3: 135 µs per loop
In [114]:

cartesian(([1, 2, 3], [4, 5], [6, 7]))

Out[114]:
array([[1, 4, 6],
       [1, 4, 7],
       [1, 5, 6],
       [1, 5, 7],
       [2, 4, 6],
       [2, 4, 7],
       [2, 5, 6],
       [2, 5, 7],
       [3, 4, 6],
       [3, 4, 7],
       [3, 5, 6],
       [3, 5, 7]])

numpy.meshgrid() استخدام 2D فقط, الآن أنها قادرة على ND.في هذه الحالة, 3D:

In [115]:

%timeit np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)
10000 loops, best of 3: 74.1 µs per loop
In [116]:

np.array(np.meshgrid([1, 2, 3], [4, 5], [6, 7])).T.reshape(-1,3)

Out[116]:
array([[1, 4, 6],
       [1, 5, 6],
       [2, 4, 6],
       [2, 5, 6],
       [3, 4, 6],
       [3, 5, 6],
       [1, 4, 7],
       [1, 5, 7],
       [2, 4, 7],
       [2, 5, 7],
       [3, 4, 7],
       [3, 5, 7]])

علما بأن النظام النهائي الناتج هو مختلفة قليلا.

نصائح أخرى

إليك تطبيق نقية نمباي. انها كاليفورنيا. 5 × أسرع من استخدام itertools.


import numpy as np

def cartesian(arrays, out=None):
    """
    Generate a cartesian product of input arrays.

    Parameters
    ----------
    arrays : list of array-like
        1-D arrays to form the cartesian product of.
    out : ndarray
        Array to place the cartesian product in.

    Returns
    -------
    out : ndarray
        2-D array of shape (M, len(arrays)) containing cartesian products
        formed of input arrays.

    Examples
    --------
    >>> cartesian(([1, 2, 3], [4, 5], [6, 7]))
    array([[1, 4, 6],
           [1, 4, 7],
           [1, 5, 6],
           [1, 5, 7],
           [2, 4, 6],
           [2, 4, 7],
           [2, 5, 6],
           [2, 5, 7],
           [3, 4, 6],
           [3, 4, 7],
           [3, 5, 6],
           [3, 5, 7]])

    """

    arrays = [np.asarray(x) for x in arrays]
    dtype = arrays[0].dtype

    n = np.prod([x.size for x in arrays])
    if out is None:
        out = np.zeros([n, len(arrays)], dtype=dtype)

    m = n / arrays[0].size
    out[:,0] = np.repeat(arrays[0], m)
    if arrays[1:]:
        cartesian(arrays[1:], out=out[0:m,1:])
        for j in xrange(1, arrays[0].size):
            out[j*m:(j+1)*m,1:] = out[0:m,1:]
    return out

itertools.combinations في عام أسرع طريقة للحصول على مزيج من حاوية بيثون (إذا كنت تفعل في الواقع تريد تركيبات، أي ترتيبات دون التكرار ومستقلة عن النظام؛ هذا ليس ما يبدو التعليمات البرمجية الخاصة بك أن تفعل، ولكن لا استطيع ان اقول ما اذا كان ذلك لأن التعليمات البرمجية هو عربات التي تجرها الدواب أو لأنك " إعادة استخدام مصطلحات خاطئة).

إذا كنت تريد شيئا مختلفا من مجموعات ربما المكررات أخرى في itertools، product أو permutations، قد خدمتك بشكل أفضل. على سبيل المثال، يبدو أن التعليمات البرمجية هو تقريبا نفس:

for val in itertools.product(np.arange(0, 1, 0.1), repeat=6):
    print F(val)

وكل هذه المكررات تسفر عن الصفوف، وليس قوائم أو صفائف نمباي، حتى إذا F الخاص بك هو من الصعب إرضاءه حول الحصول على وجه التحديد مجموعة نمباي سيكون لديك لقبول الحمل الزائد من بناء أو إزالة وإعادة ملء واحدة في كل خطوة.

يجب أن يكون تنفيذ نمباي التالية تقريبا. 2X سرعة الجواب:

def cartesian2(arrays):
    arrays = [np.asarray(a) for a in arrays]
    shape = (len(x) for x in arrays)

    ix = np.indices(shape, dtype=int)
    ix = ix.reshape(len(arrays), -1).T

    for n, arr in enumerate(arrays):
        ix[:, n] = arrays[n][ix[:, n]]

    return ix

ويبدو أنك تريد الشبكة لتقييم وظيفة الخاص بك، في هذه الحالة يمكنك استخدام numpy.ogrid (فتح) أو numpy.mgrid (بلورتها):

import numpy
my_grid = numpy.mgrid[[slice(0,1,0.1)]*6]

ويمكنك أن تفعل شيئا من هذا القبيل

import numpy as np

def cartesian_coord(*arrays):
    grid = np.meshgrid(*arrays)        
    coord_list = [entry.ravel() for entry in grid]
    points = np.vstack(coord_list).T
    return points

a = np.arange(4)  # fake data
print(cartesian_coord(*6*[a])

والذي يعطي

array([[0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 1],
   [0, 0, 0, 0, 0, 2],
   ..., 
   [3, 3, 3, 3, 3, 1],
   [3, 3, 3, 3, 3, 2],
   [3, 3, 3, 3, 3, 3]])

ويمكنك استخدام np.array(itertools.product(a, b))

إليك طريقة أخرى، وذلك باستخدام النقي نمباي، لا العودية، لا توجد قائمة على الفهم، وليس صريحا للحلقات. انها أبطأ حوالي 20٪ من الإجابة الأصلية، وأنها تقوم على np.meshgrid.

def cartesian(*arrays):
    mesh = np.meshgrid(*arrays)  # standard numpy meshgrid
    dim = len(mesh)  # number of dimensions
    elements = mesh[0].size  # number of elements, any index will do
    flat = np.concatenate(mesh).ravel()  # flatten the whole meshgrid
    reshape = np.reshape(flat, (dim, elements)).T  # reshape and transpose
    return reshape

وعلى سبيل المثال،

x = np.arange(3)
a = cartesian(x, x, x, x, x)
print(a)

وتعطي

[[0 0 0 0 0]
 [0 0 0 0 1]
 [0 0 0 0 2]
 ..., 
 [2 2 2 2 0]
 [2 2 2 2 1]
 [2 2 2 2 2]]

لتطبيق نمباي نقية من المنتج الديكارتي من المصفوفات 1D (أو قوائم الثعبان شقة)، ومجرد استخدام meshgrid()، ولفة محاور مع transpose()، وإعادة تشكيل لouput المطلوب:

 def cartprod(*arrays):
     N = len(arrays)
     return transpose(meshgrid(*arrays, indexing='ij'), 
                      roll(arange(N + 1), -1)).reshape(-1, N)

ملاحظة هذا الأمر انعقاد محور الماضي تغيير أسرع ( "النمط C" أو "صف كبير").

In [88]: cartprod([1,2,3], [4,8], [100, 200, 300, 400], [-5, -4])
Out[88]: 
array([[  1,   4, 100,  -5],
       [  1,   4, 100,  -4],
       [  1,   4, 200,  -5],
       [  1,   4, 200,  -4],
       [  1,   4, 300,  -5],
       [  1,   4, 300,  -4],
       [  1,   4, 400,  -5],
       [  1,   4, 400,  -4],
       [  1,   8, 100,  -5],
       [  1,   8, 100,  -4],
       [  1,   8, 200,  -5],
       [  1,   8, 200,  -4],
       [  1,   8, 300,  -5],
       [  1,   8, 300,  -4],
       [  1,   8, 400,  -5],
       [  1,   8, 400,  -4],
       [  2,   4, 100,  -5],
       [  2,   4, 100,  -4],
       [  2,   4, 200,  -5],
       [  2,   4, 200,  -4],
       [  2,   4, 300,  -5],
       [  2,   4, 300,  -4],
       [  2,   4, 400,  -5],
       [  2,   4, 400,  -4],
       [  2,   8, 100,  -5],
       [  2,   8, 100,  -4],
       [  2,   8, 200,  -5],
       [  2,   8, 200,  -4],
       [  2,   8, 300,  -5],
       [  2,   8, 300,  -4],
       [  2,   8, 400,  -5],
       [  2,   8, 400,  -4],
       [  3,   4, 100,  -5],
       [  3,   4, 100,  -4],
       [  3,   4, 200,  -5],
       [  3,   4, 200,  -4],
       [  3,   4, 300,  -5],
       [  3,   4, 300,  -4],
       [  3,   4, 400,  -5],
       [  3,   4, 400,  -4],
       [  3,   8, 100,  -5],
       [  3,   8, 100,  -4],
       [  3,   8, 200,  -5],
       [  3,   8, 200,  -4],
       [  3,   8, 300,  -5],
       [  3,   8, 300,  -4],
       [  3,   8, 400,  -5],
       [  3,   8, 400,  -4]])

إذا كنت تريد تغيير أولا محور أسرع ( "أسلوب FORTRAN" أو "عمود رئيسي")، مجرد تغيير المعلمة order من reshape() مثل هذا: reshape((-1, N), order='F')

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top