bir numpy dizisinin tüm kenarlıklarında 0 olup olmadığını kontrol et [kapalı]


13

Çok boyutlu bir numpy dizisinin her tarafında 0 olup olmadığını kontrol etmenin en hızlı yolu ne olurdu.

Yani, basit bir 2D örnek için, ben var:

x = np.random.rand(5, 5)
assert np.sum(x[0:,  0]) == 0
assert np.sum(x[0,  0:]) == 0
assert np.sum(x[0:, -1]) == 0
assert np.sum(x[-1, 0:]) == 0

Bu 2D durumlarda doğru olsa da, daha yüksek boyutlar için yazmak biraz sıkıcı ve burada verimli ve aynı zamanda daha sürdürülebilir hale getirmek için kullanabileceğim bazı akıllı numpy hileleri olup olmadığını merak ediyordum.


8
np.all (x[:, 0] == 0)Toplamdan daha güvenli olmaz mıydı ? Toplam testi yalnızca tüm sayılar pozitifse doğrudur.
Demi-Lune


1
@ Demi-Lume Mantıklı. Benim durumumda, her şey> = 0 olacak ama yorumunuz takdir edilecektir :)
Luca

1
3D durumda, küpün yüzleri (altı tane var) veya kenarları (12 tane var) mı demek istediniz?
Riccardo Bucco

@RiccardoBucco Evet, 6 yüz. ama benim sorunum 3'ten daha yüksek bir boyuta gidebileceğidir
Luca

Yanıtlar:


7

Bunu nasıl yapabileceğiniz aşağıda açıklanmıştır:

assert(all(np.all(np.take(x, index, axis=axis) == 0)
           for axis in range(x.ndim)
           for index in (0, -1)))

np.take "süslü" dizine ekleme ile aynı şeyi yapar.


1
@Luca: Belgeler bunu netleştirmiyor, numpy.takebir kopyasını yapıyor. Bu, bir görünüme bağlı olarak koddan daha kötü performans göstermesine neden olabilir. (Emin olmak için zamanlama gerekir - NumPy görünüm verimliliği bazen
gariptir

1
@RiccardoBucco: len(x.shape)daha basit olarak yazılabilir x.ndim.
user2357112 Monica

1
Monica teşekkürler, düzelttim :)
Riccardo Bucco

5
Ayrıca, bir liste kavrayışının kullanılması allkısa devreyi önler . Bir jeneratör ifadesi kullanmak için köşeli parantezleri kaldırarak alltek bir numpy.allçağrı geri döner dönmez geri dönebilirsiniz False.
user2357112 Monica

1
@ user2357112supportsMonica Doğru !!
Riccardo Bucco

5

İşte dizinin gerçekten ilgilendiğiniz bölümlerini inceleyen ve tüm dizinin boyutunda bir maske oluşturmak için zaman kaybetmeyen bir cevap. Python düzeyinde bir döngü var, ancak kısa, yineleme dizinin boyutu yerine boyut sayısıyla orantılı.

def all_borders_zero(array):
    if not array.ndim:
        raise ValueError("0-dimensional arrays not supported")
    for dim in range(array.ndim):
        view = numpy.moveaxis(array, dim, 0)
        if not (view[0] == 0).all():
            return False
        if not (view[-1] == 0).all():
            return False
    return True

not (view[0] == 0).all()Eşdeğer olmayan herhangi bir koşul var view[0].any()mı?
Paul Panzer

@PaulPanzer: Sanırım ben view[0].any()de işe yarar . İki seçeneğe dahil olan döküm ve tamponlamanın verimlilik etkilerinden tamamen emin değilim - view[0].any()teorik olarak daha hızlı uygulanabilir, ancak daha önce garip sonuçlar gördüm ve tamponlamayı tam olarak anlamıyorum.
user2357112 Monica

Sanırım view[0].view(bool).any()yüksek hızlı çözüm olurdu.
Paul Panzer

@PaulPanzer: argmaxaslında anyboolean görünümü yenebilir . Bu şeyler garipleşiyor.
user2357112 Monica

(Aynı zamanda, ister argmaxveya anynormal sıfıra eşit olarak negatif sıfır taşıma bir Boole görünüşüdür araçlar kullanılarak,.)
user2357112 Monica destekler

2

Diziyi yeniden şekillendirdim ve sonra tekrarladım. Maalesef cevabım, en az üç boyutunuz olduğunu ve normal matrisler için hata yapacağınızı varsayar, 1 ve 2 boyutlu şekilli diziler için özel bir madde eklemeniz gerekir. Buna ek olarak, bu yavaş olacaktır, bu nedenle muhtemelen daha iyi çözümler vardır.

x = np.array(
        [
            [
                [0 , 1, 1, 0],
                [0 , 2, 3, 0],
                [0 , 4, 5, 0]
            ],
            [
                [0 , 6, 7, 0],
                [0 , 7, 8, 0],
                [0 , 9, 5, 0]
            ]
        ])

xx = np.array(
        [
            [
                [0 , 0, 0, 0],
                [0 , 2, 3, 0],
                [0 , 0, 0, 0]
            ],
            [
                [0 , 0, 0, 0],
                [0 , 7, 8, 0],
                [0 , 0, 0, 0]
            ]
        ])

def check_edges(x):

    idx = x.shape
    chunk = np.prod(idx[:-2])
    x = x.reshape((chunk*idx[-2], idx[-1]))
    for block in range(chunk):
        z = x[block*idx[-2]:(block+1)*idx[-2], :]
        if not np.all(z[:, 0] == 0):
            return False
        if not np.all(z[:, -1] == 0):
            return False
        if not np.all(z[0, :] == 0):
            return False
        if not np.all(z[-1, :] == 0):
            return False

    return True

Hangi üretecek

>>> False
>>> True

Temelde tüm boyutları üst üste yığarım ve kenarlarını kontrol etmek için onlara bakarım.


Bu, dizinin yanlış kısımlarını inceler. 3 boyutlu bir dizi için, her 2 boyutlu alt dizinin kenarlarını değil, tüm dizinin yüzlerini incelemek istiyoruz.
user2357112 Monica

Ah, bu daha mantıklı. Yanlış
anladım

1

belki üç nokta için çalışacak üç nokta operatörü aradığınız şeydir:

import numpy as np

# data
x = np.random.rand(2, 5, 5)
x[..., 0:, 0] = 0
x[..., 0, 0:] = 0
x[..., 0:, -1] = 0
x[..., -1, 0:] = 0

test = np.all(
    [
        np.all(x[..., 0:, 0] == 0),
        np.all(x[..., 0, 0:] == 0),
        np.all(x[..., 0:, -1] == 0),
        np.all(x[..., -1, 0:] == 0),
    ]
)

print(test)

Bu tüm yüzleri renklendirmez. Örneğin, bir (4, 4, 4) küp ile deneyin.
Luca

Yüzleri renklendirerek ne demek istediğinizden emin değilim, ama x (4, 4, 4)
yaparsanız işe yarar

1

sliceİşi yapmak için boolean maskelemeyi kullanabilirsiniz:

def get_borders(arr):
    s=tuple(slice(1,i-1) for i in a.shape)
    mask = np.ones(arr.shape, dtype=bool)
    mask[s] = False
    return(arr[mask])

Bu işlev önce dizinin "çekirdeğini" tuple olarak şekillendirir sve sonra Trueyalnızca sınır noktaları için gösterilen bir maske oluşturur . Boole indekslemesi daha sonra sınır noktalarını verir.

Çalışma örneği:

a = np.arange(16).reshape((4,4))

print(a)
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])

borders = get_borders(a)
print(borders)
array([ 0,  1,  2,  3,  4,  7,  8, 11, 12, 13, 14, 15])

Sonra, np.all(borders==0)size istenen bilgileri verecektir.


Not: Bu bir boyutlu diziler için kırılıyor, ancak bunları bir kenar durumu olarak görüyorum. Muhtemelen orada söz konusu iki noktayı kontrol etmek daha iyidir


Bu, yalnızca kenarlık yerine dizideki toplam öğe sayısıyla orantılı olarak zaman alır. Ayrıca, tek boyutlu diziler alakasız bir kenar durumu değildir.
user2357112 Monica

1
Ayrıca, np.arange(15)15'i içermez.
user2357112 Monica

Ben sadece bir 1d dizi için iki ilgili noktaları kontrol daha iyi hissediyorum, ancak "alakasız" güçlü bir ifade olduğunu kabul ediyorum. 15 bir yazım hatası, iyi yakalamak
Lukas Thaler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.