Удаление начальных нулей массива numpy без использования цикла for - PullRequest
0 голосов
/ 04 мая 2018

Как я могу удалить только начальные нули из массива numpy без использования цикла?

import numpy as np

x = np.array([0,0,1,1,1,1,0,1,0,0])

# Desired output
array([1, 1, 1, 1, 0, 1, 0, 0])

Я написал следующий код

x[min(min(np.where(x>=1))):] 

Мне было интересно, есть ли более эффективное решение.

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

Поскольку np.trim_zeros использует for цикл , вот действительно векторизованное решение:

x = x[np.where(x != 0)[0][0]:]

Однако я не уверен, в какой момент он станет более эффективным, чем np.trim_zeros. Это будет более эффективно в худшем случае (то есть массив с большинством ведущих нулей).

В любом случае, это может быть полезным примером обучения.

Двусторонняя отделка:

>>> idx = np.where(x != 0)[0]
>>> x = x[idx[0]:1+idx[-1]]
0 голосов
/ 04 мая 2018

Вот грубый подход, который замыкает накоротко. Он использует тот факт, что представление 0 для любого (?) Dtype является нулевым байтом.

import numpy as np
import itertools

# check assumption that for example 0.0f is represented as 00 00 00 00
allowed_dtypes = set()
for dt in map(np.dtype, itertools.chain.from_iterable(np.sctypes.values())):
    try:
        if not np.any(np.zeros((1,), dtype=dt).view(bool)):
            allowed_dtypes.add(dt)
    except:
        pass

def trim_fast(a):
    assert a.dtype in allowed_dtypes
    cut = a.view(bool).argmax() // a.dtype.itemsize
    if a[cut] == 0:
        return a[:0]
    else:
        return a[cut:]

Сравнение с другими методами:

enter image description here

Код для генерации сюжета:

def np_where(a):
    return a[np.where(a != 0)[0][0]:]

def np_trim_zeros(a):
    return np.trim_zeros(a, 'f')

import perfplot

tf, nt, nw = trim_fast, np_trim_zeros, np_where
def trim_fast(A): return [tf(a) for a in A]
def np_trim_zeros(A): return [nt(a) for a in A]
def np_where(A): return [nw(a) for a in A]

perfplot.save('tz.png',
    setup=lambda n: np.clip(np.random.uniform(-n, 1, (100, 20*n)), 0, None),
    n_range=[2**k for k in range(2, 11)],
    kernels=[
        trim_fast,
        np_where,
        np_trim_zeros
        ],
    logx=True,
    logy=True,
    xlabel='zeros per nonzero',
    equality_check=None
    )
0 голосов
/ 04 мая 2018

Вы можете использовать np.trim_zeros(x, 'f').

«f» означает обрезать нули спереди. Опция «b» обрезает нули сзади. Опция по умолчанию 'fb' обрезает их с обеих сторон.

x = np.array([0,0,1,1,1,1,0,1,0,0])
# [0 0 1 1 1 1 0 1 0 0]
np.trim_zeros(x, 'f')
# [1 1 1 1 0 1 0 0]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...