Python Numpy - 从一维数组中删除最后一个元素的最佳方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32932866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Numpy - the best way to remove the last element from 1 dimensional array?
提问by Meni
What is the most efficient way to remove the last element from a numpy 1 dimensional array? (like pop for list)
从 numpy 一维数组中删除最后一个元素的最有效方法是什么?(如列表弹出)
采纳答案by MSeifert
NumPy arrays have a fixed size, so you cannot remove an element in-place. For example using del
doesn't work:
NumPy 数组具有固定大小,因此您无法就地删除元素。例如使用del
不起作用:
>>> import numpy as np
>>> arr = np.arange(5)
>>> del arr[-1]
ValueError: cannot delete array elements
Note that the index -1
represents the last element. That's because negative indices in Python (and NumPy) are counted from the end, so -1
is the last, -2
is the one before last and -len
is actually the first element. That's just for your information in case you didn't know.
请注意,索引-1
表示最后一个元素。这是因为 Python(和 NumPy)中的负索引是从最后开始计算的,所以-1
也是最后一个,-2
也是最后一个之前的,-len
实际上是第一个元素。这只是为了您的信息,以防您不知道。
Python lists are variable sized so it's easy to add or remove elements.
Python 列表的大小可变,因此可以轻松添加或删除元素。
So if you want to remove an element you need to create a new array or view.
所以如果你想删除一个元素,你需要创建一个新的数组或视图。
Creating a new view
创建新视图
You can create a new view containing all elements except the last one using the slice notation:
您可以使用切片表示法创建一个包含除最后一个元素之外的所有元素的新视图:
>>> 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])
However a view shares the data with the original array, so if one is modified so is the other:
然而,一个视图与原始数组共享数据,所以如果一个被修改,另一个也会被修改:
>>> 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])
Creating a new array
创建一个新数组
1. Copy the view
1.复制视图
If you don't like this memory sharing you have to create a new array, in this case it's probably simplest to create a view and then copy (for example using the copy()
method of arrays) it:
如果您不喜欢这种内存共享,则必须创建一个新数组,在这种情况下,创建视图然后复制(例如使用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. Using integer array indexing [docs]
2. 使用整数数组索引 [ docs]
However, you can also use integer array indexing to remove the last element and get a new array. This integer array indexing will always (not 100% sure there) create a copy and not a view:
但是,您也可以使用整数数组索引来删除最后一个元素并获得一个新数组。此整数数组索引将始终(不是 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])
This integer array indexing can be useful to remove arbitrary elements from an array (which can be tricky or impossible when you want a view):
这个整数数组索引对于从数组中删除任意元素很有用(当你想要一个视图时,这可能很棘手或不可能):
>>> 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])
If you want a generalized function that removes the last element using integer array indexing:
如果您想要一个使用整数数组索引删除最后一个元素的通用函数:
def remove_last_element(arr):
return arr[np.arange(arr.size - 1)]
3. Using boolean array indexing [docs]
3. 使用布尔数组索引 [文档]
There is also boolean indexing that could be used, for example:
也可以使用布尔索引,例如:
>>> 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])
This also creates a copy! And a generalized approach could look like this:
这也创建了一个副本!通用方法可能如下所示:
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]
If you would like more information on NumPys indexing the documentation on "Indexing"is quite good and covers a lot of cases.
如果您想了解有关 NumPys 索引的更多信息,“索引”文档非常好,涵盖了很多情况。
4. Using np.delete()
4. 使用 np.delete()
Normally I wouldn't recommend the NumPy functions that "seem" like they are modifying the array in-place (like np.append
and np.insert
) but do return copies because these are generally needlessly slow and misleading. You should avoid them whenever possible, that's why it's the last point in my answer. However in this case it's actually a perfect fit so I have to mention it:
通常我不会推荐 NumPy 函数,它们“看起来”像是在原地修改数组(如np.append
和np.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.) Using np.resize()
5.) 使用 np.resize()
NumPy has another method that sounds like it does an in-place operation but it really returns a new array:
NumPy 有另一种方法,听起来像是就地操作,但它实际上返回了一个新数组:
>>> arr = np.arange(5)
>>> arr
array([0, 1, 2, 3, 4])
>>> np.resize(arr, arr.size - 1)
array([0, 1, 2, 3])
To remove the last element I simply provided a new shape that is 1 smaller than before, which effectively removes the last element.
为了删除最后一个元素,我只是提供了一个比以前小 1 的新形状,这有效地删除了最后一个元素。
Modifying the array inplace
就地修改数组
Yes, I've written previously that you cannot modify an array in place. But I said that because in most cases it's not possible or only by disabling some (completely useful) safety checks. I'm not sure about the internals but depending on the old size and the new size it could be possible that this includes an (internal-only) copy operation so it mightbe slower than creating a view.
是的,我之前写过你不能就地修改数组。但我这么说是因为在大多数情况下这是不可能的,或者只能通过禁用一些(完全有用的)安全检查来实现。我不确定内部结构,但根据旧尺寸和新尺寸,这可能包括(仅限内部)复制操作,因此它可能比创建视图慢。
Using np.ndarray.resize()
使用 np.ndarray.resize()
If the array doesn't share its memory with any other array, then it's possible to resize the array in place:
如果数组不与任何其他数组共享其内存,则可以就地调整数组大小:
>>> arr = np.arange(5, 10)
>>> arr.resize(4)
>>> arr
array([5, 6, 7, 8])
However that will throw ValueError
s in case it's actually referenced by another array as well:
但是,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
You can disable that safety-check by setting refcheck=False
but that shouldn't be done lightly because you make yourself vulnerable for segmentation faults and memory corruption in case the other reference tries to access the removed elements! This refcheck
argument should be treated as an expert-only option!
您可以通过设置禁用该安全检查,refcheck=False
但这不应该轻易完成,因为如果其他引用尝试访问已删除的元素,您会使自己容易受到分段错误和内存损坏的影响!此refcheck
参数应视为专家专用选项!
Summary
概括
Creating a view is really fast and doesn't take much additional memory, so whenever possible you should try to work as much with views as possible. However depending on the use-cases it's not so easy to remove arbitrary elements using basic slicing. While it's easy to remove the first n elements and/or last n elements or remove every x element (the step argument for slicing) this is all you can do with it.
创建视图非常快并且不会占用太多额外内存,因此只要有可能,您应该尽可能多地使用视图。然而,根据用例,使用基本切片删除任意元素并不容易。虽然删除前 n 个元素和/或最后 n 个元素或删除每个 x 元素(切片的 step 参数)很容易,但这就是您所能做的。
But in your case of removing the last element of a one-dimensional array I would recommend:
但是在您删除一维数组的最后一个元素的情况下,我建议:
arr[:-1] # if you want a view
arr[:-1].copy() # if you want a new array
because these most clearly express the intent and everyone with Python/NumPy experience will recognize that.
因为这些最清楚地表达了意图,每个有 Python/NumPy 经验的人都会认识到这一点。
Timings
时间安排
Based on the timing framework from this 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()
I get the following timings as log-log plot to cover all the details, lower time still means faster, but the range between two ticks represents one order of magnitude instead of a fixed amount. In case you're interested in the specific values, I copied them into this gist:
我得到以下时序作为 log-log plot 以涵盖所有细节,较短的时间仍然意味着更快,但两个刻度之间的范围代表一个数量级而不是固定数量。如果您对特定值感兴趣,我将它们复制到此要点中:
According to these timings those two approaches are also the fastest. (Python 3.6 and NumPy 1.14.0)
根据这些时间,这两种方法也是最快的。(Python 3.6 和 NumPy 1.14.0)
回答by David M. Helmuth
To delete the last element from a 1-dimensional NumPy array, use the numpy.deletemethod, like so:
要从一维 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)
Output: [1 2 3 4]
输出:[1 2 3 4]
The last value of the NumPy array, which was 5, is now removed.
NumPy 数组的最后一个值5现已被删除。