在本教程中,我们将讨论如何对NumPy 数组使用不同的技术。
接下来,我们将了解如何按升序和降序对 NumPy 数组进行排序,以及如何处理多维数组、就地排序、间接排序以及排序时遇到的常见问题。
使用 np.sort() 对 NumPy 数组进行排序
我们可以使用以下方法对给定数组进行排序np.sort()
功能。默认情况下,该函数按升序对数组进行排序。
import numpy as np
arr = np.array([6, 4, 8, 1, 3])
sorted_arr = np.sort(arr)
print("Sorted Array:", sorted_arr)
Output:
Sorted Array: [1 3 4 6 8]
这里我们使用了np.sort()
,它按升序对 NumPy 数组进行排序。我们将原始数组作为参数传递,它返回数组的排序副本,而不修改原始数组。
按降序对 NumPy 进行排序
要按降序(从最大到最小)对 NumPy 数组进行排序,我们仍将使用np.sort()
,但我们将颠倒已排序数组的顺序。
descending_arr = np.sort(arr)[::-1]
print("Array in Descending Order:", descending_arr)
Output:
Array in Descending Order: [8 6 4 3 1]
在这里,我们使用了切片技术[::-1]
反转已排序的数组。这将按降序返回数组。
按多列排序(结构化数组)
要按多列对 NumPy 结构化数组进行排序,可以将要排序的列名称传递给order
的参数numpy.sort()
功能:
import numpy as np
data_type = np.dtype([('name', 'S15'), ('age', 'i4'), ('height', 'f4')])
data = np.array([('John', 20, 170.1),
('Doe', 20, 180.8),
('Alice', 22, 155.3),
('Bob', 22, 175.2),
('Charlie', 23, 165.7)],
dtype=data_type)
data_sorted = np.sort(data, order=['age', 'height'])
print(data_sorted)
Output:
[(b'John', 20, 170.1)
(b'Doe', 20, 180.8)
(b'Alice', 22, 155.3)
(b'Bob', 22, 175.2)
(b'Charlie', 23, 165.7)]
在此示例中,我们有一个包含三个字段的 NumPy 结构化数组 - “name”、“age”和“height”。我们首先按“年龄”排序,然后按“身高”排序。
这意味着,如果有两个人年龄相同,则较短的将排在第一位。
要按多列对 2D(或更高)数组进行排序,您可以使用lexsort()
正如我们将在本教程后面看到的。
沿轴排序(多维数组)
对于多维非结构化数组,我们可以指定对元素进行排序的轴。
对 2D NumPy 数组进行排序
# Create a 2-dimensional array
arr_2d = np.array([[2, 3, 1], [5, 0, 4]])
print("Original 2D Array:n", arr_2d)
# Sort along the first axis
sorted_arr_2d_axis0 = np.sort(arr_2d, axis=0)
print("Array sorted along the first axis:n", sorted_arr_2d_axis0)
Output:
Original 2D Array:
[[2 3 1]
[5 0 4]]
Array sorted along the first axis:
[[2 0 1]
[5 3 4]]
在这段代码中,我们首先创建了一个二维数组。为了沿第一个轴(即沿列)对该数组进行排序,我们使用了np.sort()
功能与axis=0
.
这将分别重新排列数组每列中的元素,从最小到最大排序。
对 3D NumPy 数组进行排序
对 3 维(或 n 维)数组进行排序涉及与对 2D 数组进行排序相同的原理。您只需指定要排序的轴即可。
# Create a 3-dimensional array
arr_3d = np.array([[[3, 2, 1], [6, 5, 4]], [[9, 8, 7], [12, 11, 10]]])
print("Original 3D Array:n", arr_3d)
# Sort along the last axis
sorted_arr_3d = np.sort(arr_3d, axis=-1)
print("3D Array sorted along the last axis:n", sorted_arr_3d)
Output:
Original 3D Array:
[[[ 3 2 1]
[ 6 5 4]]
[[ 9 8 7]
[12 11 10]]]
3D Array sorted along the last axis:
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
在此代码中,我们首先创建了一个 3D 数组。为了沿最后一个轴(即 axis=-1)对该数组进行排序,我们使用了np.sort()
功能与axis=-1
。因此,每个一维子数组都是独立排序的。
排序算法
np.sort()
默认情况下使用快速排序算法,但您可以使用以下命令选择不同的排序算法kind
范围。可用的算法包括“快速排序”、“合并排序”、“堆排序”和“稳定”。
快速排序(最快)
您可以使用kind
参数来指定快速排序算法像这样:
sorted_arr = np.sort(arr, kind='quicksort')
print("Array sorted using quicksort:", sorted_arr)
Output:
Array sorted using quicksort: [1 3 4 6 8]
归并排序
合并排序是 NumPy 中提供的另一种排序算法,以其可预测的 O(n log n) 时间复杂度而闻名。
sorted_arr = np.sort(arr, kind='mergesort')
print("Array sorted using mergesort:", sorted_arr)
Output:
Array sorted using mergesort: [1 3 4 6 8]
堆排序(最慢)
堆排序是一种基于比较的排序算法,时间复杂度为 O(n log n)。
sorted_arr = np.sort(arr, kind='heapsort')
print("Array sorted using heapsort:", sorted_arr)
Output:
Array sorted using heapsort: [1 3 4 6 8]
稳定排序
“稳定”算法使相等的元素保持与原始数组中相同的顺序。该算法基于基数排序或合并排序,具体取决于数据类型。
sorted_arr = np.sort(arr, kind='stable')
print("Array sorted using stable sort:", sorted_arr)
Output:
Array sorted using stable sort: [1 3 4 6 8]
何时使用每种算法?
为 NumPy 数组选择正确的排序算法可以极大地影响代码的效率。以下是选择正确算法的一般指南:
-
快速排序: 这往往是最快的算法对于数值数据。如果您需要对大型数组进行排序,并且不需要担心最坏情况或稳定性,那么这是一个不错的选择。但是,请记住,快速排序最坏情况的时间复杂度为 O(n^2)。
-
归并排序:如果您需要稳定的排序(即保留相等元素的顺序),合并排序是一个不错的选择。它的时间复杂度始终为 O(n log n),但是需要额外的内存,这对于大型阵列可能是一个问题。
-
Heapsort: 如果内存是一个问题,堆排序是一个不错的选择,时间复杂度为 O(n log n)。然而,它并不稳定。
-
稳定排序:如果您需要稳定的排序并且内存不是问题,或者您是处理非数字数据,稳定排序算法是一个不错的选择。
使用 np.ndarray.sort() 进行就地排序
如果要对原始数组进行排序而不创建副本,可以使用sort()
的方法ndarray
目的。这执行就地排序。
# Original array
arr = np.array([4, 3, 1, 6, 8])
print("Original Array:", arr)
# In-place sort
arr.sort()
print("Sorted Array:", arr)
Output:
Original Array: [4 3 1 6 8]
Sorted Array: [1 3 4 6 8]
在这段代码中,我们调用了sort()
NumPy 数组对象上的方法,该方法对数组进行就地排序。不像np.sort()
它修改了原始数组。
间接排序:argsort 和 lexsort
间接排序,例如argsort()
and lexsort()
,不对数组的值进行排序,而是返回一个索引数组,如果将其应用于该数组,将产生一个已排序的数组。
argsort
# Using argsort
sorted_indices = np.argsort(arr)
print("Sorted Indices:", sorted_indices)
# Apply the sorted indices to arr
sorted_arr = arr[sorted_indices]
print("Sorted Array:", sorted_arr)
Output:
Sorted Indices: [2 1 0 3 4]
Sorted Array: [1 3 4 6 8]
Here, np.argsort()
返回一个索引数组,用于对数组进行排序。然后我们将这些索引应用于数组以获得排序后的数组。
lexsort(按多列对非结构化数组进行排序)
假设我们想要根据第一列中的值对二维数组进行排序,然后根据第二列中的值进行排序。
我们可以使用np.lexsort()
函数,它对多个键执行间接排序。
# Create a 2-dimensional array
arr_2d = np.array([[2, 3], [1, 5], [1, 4], [2, 2]])
print("Original 2D Array:n", arr_2d)
# Sequence of keys
keys = (arr_2d[:, 1], arr_2d[:, 0])
# Indices for sorted array
sorted_indices = np.lexsort(keys)
# Apply array indexing to obtain sorted array
sorted_arr_2d = arr_2d[sorted_indices]
print("Array sorted by multiple columns:n", sorted_arr_2d)
Output:
Original 2D Array:
[[2 3]
[1 5]
[1 4]
[2 2]]
Array sorted by multiple columns:
[[1 4]
[1 5]
[2 2]
[2 3]]
在此代码中,我们创建了一个 2D 数组,然后创建了一个键序列,我们要根据该序列对数组进行排序。我们用了np.lexsort()
获取可用于生成排序数组的索引数组。
最后,我们应用数组索引来获得排序后的数组。
衡量绩效
根据经验测量不同排序算法的性能非常重要,尤其是在处理较大的数据集时。
这是我编写的一个小脚本,用于测量每个排序算法在大小为 1 亿的大型随机数组上的执行时间:
import numpy as np
import time
# Create a large numpy array
large_arr = np.random.randint(0, high=1000000, size=100000000)
algorithms = ['quicksort', 'mergesort', 'heapsort', 'stable']
for algorithm in algorithms:
start = time.time()
np.sort(large_arr, kind=algorithm)
end = time.time()
print(f"{algorithm.capitalize()} Time: {end - start} seconds")
# Test the in-place sort
start = time.time()
arr_copy = np.copy(large_arr)
arr_copy.sort() # Uses quicksort by default
end = time.time()
print(f"In-place sort Time: {end - start} seconds")
Output:
Quicksort Time: 14.426326036453247 seconds
Mergesort Time: 18.75661039352417 seconds
Heapsort Time: 47.7882182598114 seconds
Stable Time: 18.685729265213013 seconds
In-place sort Time: 14.05978536605835 seconds
这些结果将根据系统的特定硬件和软件配置而有所不同。但一般来说,正如预期的那样,快速排序对于数值数据来说往往是最快的。
常见问题及解决方法
对 NumPy 数组进行排序时可能存在几个问题和注意事项:
对不同数据类型的 NumPy 数组进行排序:NumPy 数组可以包含不同的数据类型,这可能会导致排序时出现问题。
解决方案是确保数组只包含一种数据类型,或者将其转换为可以排序的类型。
例如,如果您有一个字符串和整数的数组,则可以在排序之前将整数转换为字符串。
# An array with different data types
arr = np.array(['banana', 2, 'apple'])
print("Original array:", arr)
# Convert all elements to strings
arr = arr.astype(str)
print("Converted array:", arr)
# Now we can sort the array
print("Sorted array:", np.sort(arr))
Output:
Original array: ['banana' '2' 'apple']
Converted array: ['banana' '2' 'apple']
Sorted array: ['2' 'apple' 'banana']
对缺失值 (NaN) 的数组进行排序:NumPy 认为 NaN(非数字)大于任何其他值,这可能会导致意外的排序结果。
您可能希望在排序之前处理 NaN 值(例如,通过替换或删除它们)。
大型数组的内存使用情况:大数组会消耗大量内存。在这些情况下,您可能需要使用就地排序。
进一步阅读
https://numpy.org/doc/stable/reference/ generated/numpy.sort.html
https://numpy.org/doc/stable/reference/ generated/numpy.ndarray.sort.html