"отменить" numpy.delete, numpy.insert? - PullRequest
1 голос
/ 29 октября 2019

У меня есть массив numpy, и я хочу удалить небольшое количество записей. После этого я хотел бы вставить предыдущие индексы, где они принадлежат. numpy.insert не работает:

import numpy

a = numpy.random.rand(7)
idx = [5, 0]

# delete some indices
b = numpy.delete(a, idx)

# magic
b /= 1.0

# insert back?
c = numpy.insert(b, idx, a[idx])

# nope :(
assert numpy.all(numpy.abs(a - c) < 1.0e-10)

Есть какие-нибудь подсказки? (Предпочтительнее простые ответы.)

Возможно, есть лучшее решение, чем сначала использовать delete, например, с помощью нарезки или около того.

Ответы [ 3 ]

1 голос
/ 29 октября 2019

Я думаю, что вы хотите сделать это просто замаскировать целочисленными индексами:

import numpy as np

a = np.random.rand(7)
c = a.copy()
idx = 5, 0

# get the complement of idx
not_idx = np.fromiter((i for i in range(a.size) if i not in idx), dtype=int)
# ...or (mind the final comma: you need a `tuple` of `tuple`s):
not_idx = tuple(i for i in range(a.size) if i not in idx),

# magic
a[not_idx] /= 1.0

# yes!
assert np.all(np.abs(a - c) < 1.0e-10)
# perhaps you would prefer: `np.all(np.isclose(a, c))`?

Более эффективный подход может заключаться в том, чтобы сделать «магию» всему, а затем скопировать материал, которыйвы хотели, чтобы результат не изменялся, например:

import numpy as np

a = np.random.rand(7)
c = a.copy()
idx = 5, 0

# magic
a /= 1.0

# copy stuff back
a[idx,] = c[idx,]

# yes!
assert np.all(np.abs(a - c) < 1.0e-10)
1 голос
/ 29 октября 2019

Вот подход, который сначала выравнивает не удаленные биты, а затем заполняет удаленные. По общему признанию, не слишком отличается от первого метода @ Divakar, но, насколько я могу сказать, немного быстрее:

enter image description here

Код:

import numpy as np
from simple_benchmark import BenchmarkBuilder, MultiArgument

B = BenchmarkBuilder()

@B.add_function()
def pp(b,idx,aidx):
    N,n = b.size,idx.size
    B = np.empty(N+n,b.dtype)
    m = np.ones(N+n,bool)
    m[idx] = False
    B[m] = b
    B[idx] = aidx
    return B

@B.add_function()
def div1(b,idx,vals):
    out = np.empty(len(b)+len(idx),dtype=b.dtype)
    out[idx] = vals
    out[np.isin(np.arange(len(out)),idx, invert=True)] = b
    return out

@B.add_function()
def div2(b,idx,vals):
    sidx = idx.argsort()
    return np.insert(b, idx[sidx]-np.arange(len(idx)), vals[sidx])

@B.add_arguments('array size')
def argument_provider():
    for exp in range(1,13):
        sz = int(2**exp)
        a = np.random.randint(0,100,sz*sz)
        idx = np.random.choice(sz*sz,sz,replace=False)
        b = np.delete(a,idx)
        yield sz*sz,MultiArgument([b,idx,a[idx]])

r = B.run()
r.plot(relative_to=pp)

import pylab
import pathlib
pylab.savefig(pathlib.Path(__file__).stem + '.png')
1 голос
/ 29 октября 2019

Вот один способ с array-assignment -

out = np.empty(len(b) + len(idx), dtype=b.dtype)
out[idx] = vals
out[np.isin(np.arange(len(out)), idx, invert=True)] = b

Другой способ включает некоторую сортировку -

sidx = idx.argsort()
out = np.insert(b, idx[sidx] - np.arange(len(idx)), vals[sidx])

Обратите внимание, что решения предполагают, что входные данные являются массивами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...