100天搞定机器学习(100-Days-Of-ML)(十一)Numpy数组的排序

第十一天

Numpy数组的排序

前面我们关注了用Numpy获取和操作数组。下面介绍用于排序Numpy数组的相关算法。这些算法也是计算机科学类课程非常喜欢的话题。比如插入排序、归并排序、快速排序、冒泡排序等。这些方法的任务:对一个列表或者数组进行排序。

1.Numpy快速排序

Python有内置的sort和sorted函数可以对列表进行排序,但是Numpy的sort函数实际上效率会更高。默认情况下,np.sort函数式快速排序,其实时间复杂度为O(NlogN)。

# 不修改原始数组的排序
x = np.array([2, 1, 4, 3, 5])
np.sort(x)
# 用排好序的数组代替原数组
x.sort()
print(x)
​
# [1 2 3 4 5]

另外一个函数式argsort,该函数返回的是原始数组排好序的索引值:

x = np.array([2, 1, 4, 3, 5])
i = np.argsort(x)
print(i)
​
# [1 0 3 2 4]

以上结果的第一个元素是数组中最小元素的索引值,第二个值给出的是次小元素的索引值,以此类推。这些索引值可以被用于创建有序的数组:

# 花哨的索引
x[i]
array([1, 2, 3, 4, 5])

当然,Numpy排序算法的一个有用的功能是通过axis参数,沿着多维数组的行或列进行排序。

rand = np.random.RandomState(42)
x = rand.randint(0, 10, (4, 6))
print(x)
# [[6 3 7 4 6 9]
   [2 6 7 4 3 7]
   [7 2 5 4 1 7]
   [5 1 4 0 9 5]]
   
# 对x的每一列进行排序
np.sort(x, axis=0)
​
# 对x的每一行进行排序
np.sort(x, axis=1)

2.部分排序:分割

有时候我们不希望对整个数组进行排序,仅仅希望找到数组中第K小的值,Numpy的np.partition函数提供了该功能。np.partition函数输入的是数组和数字K,输出结果是一个新数组,最左边的是第K小的值(数组中1-K个最小值,不论排序),往右是任意顺序的其他值。

x = np.array([7, 2, 3, 1, 6, 5, 4])
np.partition(x, 3)
​
# array([2, 1, 3, 4, 6, 5, 7])

从上面看,结果数组中钱三个值是数组中最小的三个值,剩下的位置是原始数组中的值。在这两个发分割区中,元素都是任意排序的。

与排序类似,也可以沿着多维数组任意的轴进行分割:

rand = np.random.RandomState(42)
x = rand.randint(0, 10, (4, 6))
np.partition(x, 2, axis=1)

结果输出的是一个数组,该数组每一行的前两个元素是该行最小的两个值,每一行其他的值分布在剩下的位置。

当然,正如np.argsort函数计算的是排序的索引值,也有一个np.argpartition函数计算的是分割的索引值。

二、Numpy的结构化数组

1.简单的复合类型

大多时候,我们的数据可以通过一个异构类型值组成的数组表示,但是有的时候并非如此简单。Numpy的结构化数组和记录数组,它们为复合的、异构的数据提供了非常有效的存储。

假定现在有关于一些人的分类数据(如姓名、年龄和体重),我们需要存储这些数据用于Python项目,那么一种可行的方法是将它们存在三个单独的数组中:

name = ['Alice', 'Bob', 'Cathy']
age = [25, 11, 26]
weight = [55.0, 54.5, 61.0]

当然这个方法不好,因为没有将这三个数组联系在一起。而Numpy可以用结构化数组来实现单一结构存储这些数据。这些结构化数组是复合数据类型的。

# 和生成简单的数组类似
x = np.zeros(4, dtype=int)
# 指定复合数据类型
data = np.zeros(4, dtype={'names':('name', 'age', 'weight'), 'formats':('U10', 'i4', 'f8')})
print(data.dtype)
# [('name', '<U10'), ('age', '<i4'), ('weight', '<f8')]
# 这里的U10表示长度不超过10的Unicode字符串
# i4表示4字节整型
# f8表示8字节的浮点型
------------------
然后将数据放入数组中
data['name'] = name
data['age'] = age
data['weight'] = weight
​
# [('Alice', 25, 55.0) ('Bob', 11, 54.5) ('Cathy', 26, 61.0)]

结构化数组的方便之处,你可以通过索引或者名称查看相应的值:

# 获取所有name
data['name']
​
# 获取数据的第一行
data[0]
​
# 获取最后一行的名字
data[-1]['name']

还可以利用布尔掩码,做一些更复杂的操作,如按照年龄进行筛选:

# 获取年龄小于20岁的人的名字
data[data['age'] < 20]['name']

如果希望实现比上面更为复杂的操作,可以考虑为Pandas工具的DataFrame对象,构建在Numpy数组之上,提供了很多有用的数据操作功能,是数据科学中必不可少的工具。

2.生成结构化数组

结构化数组的数据类型有多种制定方式。前面我们是采用的字典的方法:

np.dtype({'names':('name', 'age', 'weight'), 'formats':('U10', 'i4', 'f8')})
​
# 也可以是元组列表
np.dtype([('name', 'S10'), ('age', 'i4'), ('weight', 'f8')])
​
# 或者类型名称不重要。仅仅用一个字符串来指定
np.dtype('S10, i4, f8')
# dtype([('f0', 'S10'), ('f1', '<i4'), ('f2', '<f8')])

Numpy的数据类型表:

Numpy数据类型符号描述示例
'b'字节型np.dtype('b')
'i'有符号整型np.dtype('i4')==np.int32
'u'无符号整型np.dtype('u1')==np.uint8
'f'浮点型np.dtype('f8')==np.int64
'c'复数浮点型np.dtype('c16')==np.complex128
'S'、'a'字符串np.dtype('S5')
'U'Unicode字符串np.dtype('U')==np.str_
'V'原生数据np.dtype('V')==np.void

3.高级的复合类型

Numpy中也可以定义更高级的复合数据类型。例如你可以创建一种类型,其中每个元素都包含一个数组或矩阵。

tp = np.dtype([('id', 'i8'), ('mat', 'f8', (3, 3))])
x = np.zeros(1, dtype=tp)
print(x[0])
# (0, [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

现在x数组的每个元素都包含了一个id和一个3X3的矩阵。Numpy的dtype直接映射到C结构的定义,因此包含数组内容的缓存可以直接在C程序中使用,效率比较高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值