2014-09-29 35 views
5

Cython'da, rasgele boyut çok boyutlu bir matrisinin birkaç ekseni boyunca karışabilen NaN güvenli bir karıştırma yordamı uygulamak için çalışıyorum. Çok boyutlu büyük işlemek için bu algoritma uzatmakÇok boyutlu dizilerin yerinde karıştırılması

def shuffle1D(np.ndarray[double, ndim=1] x): 
    cdef np.ndarray[long, ndim=1] idx = np.where(~np.isnan(x))[0] 
    cdef unsigned int i,j,n,m 

    randint = np.random.randint 
    for i in xrange(len(idx)-1, 0, -1): 
     j = randint(i+1) 
     n,m = idx[i], idx[j] 
     x[n], x[m] = x[m], x[n] 

ben gibi olacaktır: 1B matrisin basit durumda

, bir sadece Fisher-Yates algoritması kullanılarak değerlerinin olmayan NaN tüm indisleri üzerinde karitirabilirsiniz yeniden şekillendirilmemiş diziler (burada dikkate alınmayan daha karmaşık durumlar için bir kopyasını tetikler). Bu amaçla, sabit girdi boyutundan kurtulmam gerekecek, ki bu da numt dizileriyle veya Cython'daki bellek görüntüleriyle mümkün görünmüyor. Bir çözüm var mı?

Şimdiden çok teşekkürler!

+0

Sorun sadece rasgele bir sayıya sahip mi? – Veedrac

+0

Girişin boyutu bilinmediğinde kaç tane döngü kullanacaksınız? –

+0

@moarningsun bir genel durum için herhangi bir eksen boyunca hafızayı taramak için dizi adımlarını kullanmak mümkündür ... –

cevap

4

teşekkürler.

  • bir işaretçi dizisi axis
  • Kişisel algoritma
  • O C sipariş diziler için bir kopyasını oluşturmaz sıralanmakta olan onları engelleyen bir modifikasyon that checks for nan values kullanılır boyunca değerlerin bellek adresini saklar. Fortran sıralı dizilerde ravel() komutu bir kopya döndürecektir. Bu ... muhtemelen bazı önbellek cezası, x değerlerini taşımak için çift işaretçiler başka dizi oluşturarak geliştirilebilir

Bu kod daha hızlı dilimleri dayalı diğerinden daha büyüklük en az bir sırasıdır.

from libc.stdlib cimport malloc, free 

cimport numpy as np 
import numpy as np 
from numpy.random import randint 

cdef extern from "numpy/npy_math.h": 
    bint npy_isnan(double x) 

def shuffleND(x, int axis=-1): 
    cdef np.ndarray[double, ndim=1] v # view of x 
    cdef np.ndarray[int, ndim=1] strides 
    cdef int i, j 
    cdef int num_axis, pos, stride 
    cdef double tmp 
    cdef double **v_axis 

    if axis==-1: 
     axis = x.ndim-1 

    shape = list(x.shape) 
    num_axis = shape.pop(axis) 

    v_axis = <double **>malloc(num_axis*sizeof(double *)) 
    for i in range(num_axis): 
     v_axis[i] = <double *>malloc(1*sizeof(double)) 

    try: 
     tmp_strides = [s//x.itemsize for s in x.strides] 
     stride = tmp_strides.pop(axis) 
     strides = np.array(tmp_strides, dtype=np.int32) 
     v = x.ravel() 
     for indices in np.ndindex(*shape): 
      pos = (strides*indices).sum() 
      for i in range(num_axis): 
       v_axis[i] = &v[pos + i*stride] 
      for i in range(num_axis-1, 0, -1): 
       j = randint(i+1) 
       if npy_isnan(v_axis[i][0]) or npy_isnan(v_axis[j][0]): 
        continue 
       tmp = v_axis[i][0] 
       v_axis[i][0] = v_axis[j][0] 
       v_axis[j][0] = tmp 
    finally: 
     free(v_axis) 

    return x 
+1

'nihayet' bir 'son' bloğu koyarak, ama bu temiz görünüyor. Algoritmayı hiç anlamıyorum, bu yüzden doğru olduğuna güveniyorum. – Veedrac

+0

1: 'ravel' * 'nin * kopyalayabildiğini ve 2: sanırım' (adım * indisleri) .sum() ', tüm durumlar için yeterli olmayabilir. V [:: 2] .strides 'düşünün. – Veedrac

+0

@ Veedrac Denedim (strides * indices).sum() 'ile bir çift zor girdiler ve işe yaramış gibi görünüyor ve ben rab (falcon) dizisi Fortran hizalanmışsa kopyalayacağımıza dair bir not ekledim: –

2

Aşağıdaki algoritma, kopyaların yapılmadığı dilimlere dayanmaktadır ve hiçbir np.ndarray için çalışmalıdır. Ana adımlar şunlardır:

  • np.ndindex() uygulandığı zaten 1-D durumu için sizin tarafınızdan geliştirilen
  • karıştır karıştır istediğiniz eksene ait bir hariç, farklı boyutlu endeksleri düşünce çalıştırmak için kullanılır .

Kodu: Bu yanıt Cython yetenekleri daha kullanır @Veedrac yorumlarına

def shuffleND(np.ndarray x, axis=-1): 
    cdef np.ndarray[long long, ndim=1] idx 
    cdef unsigned int i, j, n, m 
    if axis==-1: 
     axis = x.ndim-1 
    all_shape = list(np.shape(x)) 
    shape = all_shape[:] 
    shape.pop(axis) 
    for slices in np.ndindex(*shape): 
     slices = list(slices) 
     axis_slice = slices[:] 
     axis_slice.insert(axis, slice(None)) 
     idx = np.where(~np.isnan(x[tuple(axis_slice)]))[0] 
     for i in range(idx.shape[0]-1, 0, -1): 
      j = randint(i+1) 
      n, m = idx[i], idx[j] 
      slice1 = slices[:] 
      slice1.insert(axis, n) 
      slice2 = slices[:] 
      slice2.insert(axis, m) 
      slice1 = tuple(slice1) 
      slice2 = tuple(slice2) 
      x[slice1], x[slice2] = x[slice2], x[slice1] 
    return x 
+0

Bu yöntem Cython'u kullanmanın yararlarından hiçbirini geçersiz kılmıştır. Belki de kullanıcı için yeterlidir45893, ama bilmem. – Veedrac

+0

@Veedrac yorum için teşekkür ederim ... dizi adımlarını kullanarak başka bir alternatif aradım ve başka bir cevapla geldim ... hangi dilime göre çözümden en az 10X daha hızlı olması gerektiğini ... –