numpy 如何从一维数组中删除最后一个元素

pdtvr36n  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(149)

从numpy一维数组中删除最后一个元素的最有效方法是什么?(like pop for list)

0dxa2lsx

0dxa2lsx1#

NumPy数组的大小是固定的,因此不能就地删除元素。例如,使用del不工作:

>>> import numpy as np
>>> arr = np.arange(5)
>>> del arr[-1]
ValueError: cannot delete array elements

注意,索引-1表示最后一个元素。这是因为Python(和NumPy)中的负索引是从末尾开始计数的,所以-1是最后一个,-2是最后一个,-len实际上是第一个元素。这只是给你的信息,以防你不知道。
Python列表的大小是可变的,因此可以很容易地添加或删除元素。
因此,如果你想删除一个元素,你需要创建一个新的数组或视图。

创建新视图

您可以使用切片表示法创建一个包含除最后一个元素之外的所有元素的新视图:

>>> arr = np.arange(5)
>>> arr
array([0, 1, 2, 3, 4])

>>> arr[:-1]  # all but the last element
array([0, 1, 2, 3])
>>> arr[:-2]  # all but the last two elements
array([0, 1, 2])
>>> arr[1:]   # all but the first element
array([1, 2, 3, 4])
>>> arr[1:-1] # all but the first and last element
array([1, 2, 3])

然而,视图与原始数组共享数据,因此如果一个被修改,那么另一个也会被修改:

>>> sub = arr[:-1]
>>> sub
array([0, 1, 2, 3])
>>> sub[0] = 100
>>> sub
array([100,   1,   2,   3])
>>> arr
array([100,   1,   2,   3,   4])

创建新数组

1.复制视图

如果你不喜欢这种内存共享,你必须创建一个新的数组,在这种情况下,最简单的方法可能是创建一个视图,然后复制(例如使用数组的copy()方法):

>>> arr = np.arange(5)
>>> arr
array([0, 1, 2, 3, 4])
>>> sub_arr = arr[:-1].copy()
>>> sub_arr
array([0, 1, 2, 3])
>>> sub_arr[0] = 100
>>> sub_arr
array([100,   1,   2,   3])
>>> arr
array([0, 1, 2, 3, 4])

2.使用整数数组索引[docs]

但是,您也可以使用整数数组索引来删除最后一个元素并获得新数组。这个整数数组索引总是(不是100%确定)创建一个副本而不是一个视图:

>>> arr = np.arange(5)
>>> arr
array([0, 1, 2, 3, 4])
>>> indices_to_keep = [0, 1, 2, 3]
>>> sub_arr = arr[indices_to_keep]
>>> sub_arr
array([0, 1, 2, 3])
>>> sub_arr[0] = 100
>>> sub_arr
array([100,   1,   2,   3])
>>> arr
array([0, 1, 2, 3, 4])

这个整数数组索引可以用来从数组中删除任意元素(当你想要一个视图时,这可能很棘手或不可能):

>>> arr = np.arange(5, 10)
>>> arr
array([5, 6, 7, 8, 9])
>>> arr[[0, 1, 3, 4]]  # keep first, second, fourth and fifth element
array([5, 6, 8, 9])

如果你想要一个使用整数数组索引删除最后一个元素的广义函数:

def remove_last_element(arr):
    return arr[np.arange(arr.size - 1)]

3.使用布尔数组索引[docs]

也可以使用布尔索引,例如:

>>> arr = np.arange(5, 10)
>>> arr
array([5, 6, 7, 8, 9])
>>> keep = [True, True, True, True, False]
>>> arr[keep]
array([5, 6, 7, 8])

这也创造了一个副本!一般的方法可能是这样的:

def remove_last_element(arr):
    if not arr.size:
        raise IndexError('cannot remove last element of empty array')
    keep = np.ones(arr.shape, dtype=bool)
    keep[-1] = False
    return arr[keep]

如果你想了解更多关于NumPys索引的信息,documentation on "Indexing"非常好,涵盖了很多情况。

4.使用np.delete()

通常我不会推荐NumPy函数,它们“看起来”像是在就地修改数组(如np.appendnp.insert),但确实会返回副本,因为这些函数通常不必要地慢和误导。你应该尽可能避免它们,这就是为什么它是我回答的最后一点。然而,在这种情况下,它实际上是一个完美的适合,所以我必须提到它:

>>> arr = np.arange(10, 20)
>>> arr
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
>>> np.delete(arr, -1)
array([10, 11, 12, 13, 14, 15, 16, 17, 18])

5.)使用np.resize()

NumPy有另一个方法,听起来像是在原地操作,但它实际上返回了一个新数组:

>>> arr = np.arange(5)
>>> arr
array([0, 1, 2, 3, 4])
>>> np.resize(arr, arr.size - 1)
array([0, 1, 2, 3])

为了删除最后一个元素,我简单地提供了一个比以前小1的新形状,这有效地删除了最后一个元素。

就地修改数组

是的,我之前已经写过,你不能修改一个数组的位置。但我这么说是因为在大多数情况下,这是不可能的,或者只能禁用一些(完全有用的)安全检查。我不确定内部结构,但根据旧的大小和新的大小,这可能包括一个(仅内部)复制操作,所以它 * 可能 * 比创建视图慢。

使用np.ndarray.resize()

如果数组不与任何其他数组共享其内存,则可以就地调整数组大小:

>>> arr = np.arange(5, 10)
>>> arr.resize(4)
>>> arr
array([5, 6, 7, 8])

然而,如果它实际上也被另一个数组引用,那么它将抛出ValueError s:

>>> arr = np.arange(5)
>>> view = arr[1:]
>>> arr.resize(4)
ValueError: cannot resize an array that references or is referenced by another array in this way.  Use the resize function

您可以通过设置refcheck=False来禁用安全检查,但不应该轻易这样做,因为这样会使您自己容易受到分段错误和内存损坏的影响,以防其他引用试图访问已删除的元素!refcheck参数应被视为仅限Maven使用的选项!

摘要

创建视图的速度非常快,而且不会占用太多额外的内存,因此只要有可能,您就应该尽可能多地使用视图。然而,根据不同的用例,使用基本切片来删除任意元素并不那么容易。虽然很容易删除前n个元素和/或后n个元素,或者删除每个x元素(切片的步骤参数),但这是您可以使用它做的所有事情。
但在删除一维数组的最后一个元素的情况下,我建议:

arr[:-1]          # if you want a view
arr[:-1].copy()   # if you want a new array

因为这些最清楚地表达了意图,每个有Python/NumPy经验的人都会认识到这一点。

计时

基于此answer的时序框架:

# Setup
import numpy as np

def view(arr):
    return arr[:-1]

def array_copy_view(arr):
    return arr[:-1].copy()

def array_int_index(arr):
    return arr[np.arange(arr.size - 1)]

def array_bool_index(arr):
    if not arr.size:
        raise IndexError('cannot remove last element of empty array')
    keep = np.ones(arr.shape, dtype=bool)
    keep[-1] = False
    return arr[keep]

def array_delete(arr):
    return np.delete(arr, -1)

def array_resize(arr):
    return np.resize(arr, arr.size - 1)

# Timing setup
timings = {view: [], 
           array_copy_view: [], array_int_index: [], array_bool_index: [], 
           array_delete: [], array_resize: []}
sizes = [2**i for i in range(1, 20, 2)]

# Timing
for size in sizes:
    print(size)
    func_input = np.random.random(size=size)
    for func in timings:
        print(func.__name__.ljust(20), ' ', end='')
        res = %timeit -o func(func_input)   # if you use IPython, otherwise use the "timeit" module
        timings[func].append(res)

# Plotting
%matplotlib notebook

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(1)
ax = plt.subplot(111)

for func in timings:
    ax.plot(sizes, 
            [time.best for time in timings[func]], 
            label=func.__name__)
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('size')
ax.set_ylabel('time [seconds]')
ax.grid(which='both')
ax.legend()
plt.tight_layout()

我将以下时间作为对数-对数图来覆盖所有细节,较低的时间仍然意味着更快,但两个滴答之间的范围代表一个数量级而不是一个固定的数量。如果您对特定值感兴趣,我将它们复制到gist中:

根据这些时间,这两种方法也是最快的。(Python 3.6和NumPy 1.14.0)

q9rjltbz

q9rjltbz2#

如果你想快速得到没有最后一个元素的数组(不删除显式的),使用切片:

array[:-1]
laawzig2

laawzig23#

要从一维NumPy数组中删除最后一个元素,请使用numpy.delete方法,如下所示:

import numpy as np

# Create a 1-dimensional NumPy array that holds 5 values
values = np.array([1, 2, 3, 4, 5])

# Remove the last element of the array using the numpy.delete method
values = np.delete(values, -1)
print(values)

输出:[1 2 3 4]

NumPy数组的最后一个值,即 5,现在已被删除。

相关问题