注:本文采用 import numpy as np 的方式导入模块,后续不再提示
一、数组是什么(ndarray)
所谓数组,是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式。这些无序排列的同类数据元素的集合称为数组
二、数据类型和结构数组
1.数据类型
numpy支持很多数据类型,并且可以使用 astype 方法转换数组的数据类型
完整的 ndarry 数据类型可以用下面的方法进行查看:
>>> print set(np.typeDict.values())
set([<type 'numpy.int8'>, <type 'numpy.uint8'>, <type 'numpy.float16'>, <type 'numpy.timedelta64'>, <type 'num
py.bool_'>, <type 'numpy.object_'>, <type 'numpy.int16'>, <type 'numpy.uint16'>, <type 'numpy.float32'>, <type
'numpy.complex64'>, <type 'numpy.string_'>, <type 'numpy.int32'>, <type 'numpy.uint32'>, <type 'numpy.float64
'>, <type 'numpy.complex128'>, <type 'numpy.unicode_'>, <type 'numpy.int32'>, <type 'numpy.uint32'>, <type 'nu
mpy.float64'>, <type 'numpy.complex128'>, <type 'numpy.void'>, <type 'numpy.int64'>, <type 'numpy.uint64'>, <t
ype 'numpy.datetime64'>])
2.结构数组
数组数据的类型可以由用户自定义。自定义数据类型是一种异质结构数据类型,通常用来记录一行数据或一系列数据,即结构数组。(我个人觉得跟数据库建表插入数据有点类似)
例1:
- 第一步:使用 dtype 函数自定义字段类型
>>> exlist=np.dtype([('name',np.str_,50),('volume',np.int32)])
>>> exlist
dtype([('name', 'S50'), ('volume', '<i4')])
- 第二步:定义好数据类型后,使用 array 函数,便可以构造结构数组
>>> lists=np.array([('Blue',22),('Sony',55),('Apple',10),('KK',100)],dtype=exlist)
>>> # dtype 指定第一步创建的结构数组 exlist
>>> lists
array([('Blue', 22), ('Sony', 55), ('Apple', 10), ('KK', 100)],
dtype=[('name', 'S50'), ('volume', '<i4')])
例2:
另外还可以使用描述结构烈性的各个字段的字典来定义结构数组。该字典需要两个键:names 和 formats
- names:定义结构中每个字段的名称
- formats:定义每个字段的类型
>>> exdict=np.dtype({'names':['name','volume'],'formats':['S50','i']})
>>> exdict
dtype([('name', 'S50'), ('volume', '<i4')])
>>>
>>> list_new=np.array([('Blue',22),('Sony',55),('Apple',10),('KK',100)],dtype=exdict)
>>> list_new
array([('Blue', 22), ('Sony', 55), ('Apple', 10), ('KK', 100)],
dtype=[('name', 'S50'), ('volume', '<i4')])
结构数组可以直接使用字段名进行索引和切片
三、索引与切片
1.基本索引和切片
- " [ ] ":用中括号选定下标来进行数组的索引与切片
- " : " : 用冒号分隔起止位置与间隔
单冒号 [ 开始:结束 ]
双冒号 [ 开始:结束:步长]
- "," : 表示不同维度
- " ... ":表示遍历剩下的维度
例子这里就不做介绍了,跟python的基础库中索引差不多
多维数组的索引与切片也类似,这里展示几个例子:
>>> b=np.arange(24).reshape(2,3,4) # 使用 reshape 来定义多维数组形状
>>> b
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> b[1,2,1] # 2层3行第2个数
21
>>> b[0,2,:] # 1层 3行 所有数
array([ 8, 9, 10, 11])
>>> b[0,...] # 第一层 所有的数字,多个冒号可以用 ... 来代替,省略... 也可以
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b[:,1] # 选取各层第二行数字
array([[ 4, 5, 6, 7],
[16, 17, 18, 19]])
>>> b[:,:,1] # 选取各层第二列的数字
array([[ 1, 5, 9],
[13, 17, 21]])
>>> b[...,1]
array([[ 1, 5, 9],
[13, 17, 21]])
>>> b[0,::2,-2] # 在0层中每隔一行选取改行倒数第二个数
array([ 2, 10])
2.逻辑索引
逻辑索引又称布尔索引、条件索引
也就是数学里面的 或、且、非
注:逻辑运算符 and 和 or 在布尔型数组中无效,需使用 &(且)、|(或)之类的布尔算术运算符
依旧使用前面创建的数组 b,例:
>>> b[b>=15]
array([15, 16, 17, 18, 19, 20, 21, 22, 23])
>>> b[~(b>=15)]
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
>>> b[(b>=5)&(b<=15)]
array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
>>> b_bool1=np.array([False,True],dtype=bool) # 使用bool 索引,需要先创建布尔型的数组
>>> b[b_bool1]
array([[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
# 使用布尔型数组去索引,每级需有True 并且正确对应,否则会类型错误抛异常
>>> b_bool2=np.array([False,True,True],dtype=bool)
>>> b_bool3=np.array([False,True,True,False],dtype=bool)
>>> b[b_bool1,b_bool2]
array([[16, 17, 18, 19],
[20, 21, 22, 23]])
>>> b[b_bool1,b_bool2,b_bool3] # 可去思考下为什么结果是 17 和 22
array([17, 22])
3.花式索引
利用整数数组进行索引,其可使用指定顺序对数组提取子集
例1:
>>> b[[[0],[1,2],[2,3]]] # 提取第0层第1行第2列、第0层第2行第3列
array([ 6, 11])
注:b[0][1] 等价于 b[0,1]
ix_ 函数可将若干一维整数数组转换为一个用于选取矩形区域的索引器:(增强可读性)
例2:
>>> b[np.ix_([1,0],[2,1],[0,3,2])]
array([[[20, 23, 22],
[16, 19, 18]],
[[ 8, 11, 10],
[ 4, 7, 6]]])
# 先取第1层 第2行 的0,3,2 号元素 和 第1层 第1行的 0,3,2号元素
# 然后再取 第0层 第2行 的0,3,2 号元素 和 第0层 第1行的 0,3,2号元素
注:可以思考下 ix_ 和上面方式的区别,ix_ 有点类似于遍历,而之前的方式有点类似于坐标
数组切片是原始数据的视图(view),与原始数据共享一块数据存储空间,即:数据不会被复制,视图上的任何修改都会直接反映到原始数据。如果需要数组切片是一个副本而不是视图,可以使用 copy 方法进行浅复制:
>>> b_slice=b[0,1,1:3]
>>> b_copy=b[0,1,1:3].copy() # 采用浅复制
>>> b_slice
array([5, 6])
>>> b_copy
array([5, 6])
>>> b_slice[1]=666 # 将数组元素重赋值
>>> b_slice
array([ 5, 666])
>>> b # 可以看到原始数组已经被改变
array([[[ 0, 1, 2, 3],
[ 4, 5, 666, 7],
[ 8, 9, 10, 11]],
[[ 12, 13, 14, 15],
[ 16, 17, 18, 19],
[ 20, 21, 22, 23]]])
>>>
>>> b_copy[1]=999 # 对浅复制的组元素重新赋值
>>> b_copy
array([ 5, 999])
>>> b
array([[[ 0, 1, 2, 3],
[ 4, 5, 666, 7],
[ 8, 9, 10, 11]],
[[ 12, 13, 14, 15],
[ 16, 17, 18, 19],
[ 20, 21, 22, 23]]]) # 可以看到原始数据没有发生变化
而花式索引跟数组切片不一样,它总是将数据复制到新的数组中
四、数组的属性
数组的属性包括维度、大小、数据类型,等
定义个数组来解析
>>> ac=np.arange(12)
>>> ac.shape=(2,2,3) # 使用 shape 来定义数组的形状
>>> ac
array([[[ 0, 1, 2],
[ 3, 4, 5]],
[[ 6, 7, 8],
[ 9, 10, 11]]])
-
思考:shape定义数组形状和 reshape 定义数组形状有什么区别
shape 直接修改内存地址中数组的形状而 reshape 不会修改,即 shape会修改原始数组,reshape 不会修改
属性 | 含义 | 示例 | 结果 |
---|---|---|---|
shape | 返回数组的形状,如行、列、层等 | ac.shape | (2,2,3) |
ndim | 返回数组的维数或数组轴的个数(有多少对 [ ] 就有多少维度) | ac.ndim | 3 |
dtype | 返回数组中各元素的类型 | ac.dtype | dtype('int64') |
size | 返回数组元素的总个数 | ac.size | 12 |
itemsize | 返回数组中的元素在内存中所占的字节数 | ac.itemsize | 8 |
nbyte | 返回数组所占的存储空间,即 itemsize 与 size 的乘积 | ac.nbyte | 96 |
T | 返回数组的转置数组 | print ac.T | [[[ 0 6] [ 3 9]] [[ 1 7] [ 4 10]] [[ 2 8] [ 5 11]]] |
flat | 展平迭代器,像遍历一维数组一样去遍历任意多维数组,也可从迭代器中获取指定数组元素 | acf=ac.flat;acf for i in acf: print i, acf[5:] acf[[1,3,11]]=100 print ac |
<numpy.flatiter object at 0x000000000933A8D0> 0 1 2 3 4 5 6 7 8 9 10 11 array([ 5, 6, 7, 8, 9, 10, 11]) [[[ 0 100 2] [100 4 5]] [[ 6 7 8] [ 9 10 100]]] |
五、数组排序
这里暂时只列几个进行介绍,其他的可以上官文查看
1. numpy 有以下多种排序:
- sort : 返回排序后的数组
- lexsort: 根据键值的字典序进行排序
- argsort: 返回数组排序后的下标
- msort:沿着第一个轴排序
- sort_complex : 对复数按照先实后虚的顺序进行排序
1.1 numpy.sort(a, axis=-1, kind='quicksort', order=None)
使用方法:numpy.sort(a)
参数说明:
- axis:排序沿着数组的方向,0表示按行,1表示按列
- kind:排序的算法,提供了快排、混排、堆排
- order:不是指的顺序,以后用的时候再去分析这个
- a:要排序的数组
作用效果:对数组a排序,返回一个排序后的数组(与a相同维度),a不变
例:
>>> s=np.array([1,2,3,4,7,54,32,23,2,5,8,3])
>>> np.sort(s)
array([ 1, 2, 2, 3, 3, 4, 5, 7, 8, 23, 32, 54])
>>> s
array([ 1, 2, 3, 4, 7, 54, 32, 23, 2, 5, 8, 3])
1.2 numpy.argsort(a, axis=-1, kind='quicksort', order=None)
使用方法:numpy.argsort(a)
参数跟上面的一样
作用效果:对数组a排序,返回一个排序后索引,a不变
例:
>>> np.argsort(s) # 显示排序后的下标
array([ 0, 1, 8, 2, 11, 3, 9, 4, 10, 7, 6, 5], dtype=int64)
>>> s[np.argsort(-s)] # 对s进行降序排序,原理就是先获取下标再取反,通过取反的下标得出结果
array([54, 32, 23, 8, 7, 5, 4, 3, 3, 2, 2, 1])
>>> s # 原数组不改变
array([ 1, 2, 3, 4, 7, 54, 32, 23, 2, 5, 8, 3])
1.3 numpy.lexsort
指定排序的顺序
例:
>>> a=[1,5,1,4,3,4,4]
>>> b=[9,4,0,4,0,2,1]
>>> ind=np.lexsort((b,a)) # 先按a排序,再按b排序,得到的ind是下标
>>> [(a[i],b[i]) for i in ind]
[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)]
>>> print ind
[2 0 4 6 5 3 1]
2. ndarry 的排序:
2.1 ndarray.sort(axis=-1, kind='quicksort', order=None)
使用方法:a.sort
参数说明:
axis:排序沿着数组的方向,0表示按行,1表示按列
kind:排序的算法,提供了快排、混排、堆排
order:不是指的顺序,以后用的时候再去分析这个
作用效果:对数组a排序,排序后直接改变了a
>>> s.sort()
>>> s
array([ 1, 2, 2, 3, 3, 4, 5, 7, 8, 23, 32, 54])
在多维数组中,可以指定按照数组的轴进行排序:
>>> s_r=np.array([3,23,52,34,52,3,5,645,34,7,85,23]).reshape(6,2)
>>> s_r
array([[ 3, 23],
[ 52, 34],
[ 52, 3],
[ 5, 645],
[ 34, 7],
[ 85, 23]])
>>> s_r.sort(axis=1) # 对行进行排序
>>> s_r
array([[ 3, 23],
[ 34, 52],
[ 3, 52],
[ 5, 645],
[ 7, 34],
[ 23, 85]])
>>> s_r.sort(axis=0) # 对列进行排序
>>> s_r
array([[ 3, 23],
[ 3, 34],
[ 5, 52],
[ 7, 52],
[ 23, 85],
[ 34, 645]])
六、数组维度
数组的维度可以进行变换,如行列互换、降维等。numpy 中可以使用 reshape 函数改变数组的维数,使用 ravel 函数、flatten 函数可将数组展平为一维数组。
1. 展平
将数组转为一维数组
直接来例子吧:
>>> b=np.arange(24).reshape(2,3,4)
>>> b
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>>
>>> b.ndim
3
>>> br=np.ravel(b) # 将数组转为一维数组
>>> br
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
>>> br.ndim
1
reshape 同样也能转成一维数组的样子,但是不是真正的一维数组:
>>> brsh=b.reshape(1,1,24)
>>> brsh
array([[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23]]])
>>> brsh.ndim
3
ndarray.flatten 方法也能将数组展平,效果与 numpy.ravel 相同,区别就是 flatten 会分配内存保存结果,ravel 函数只是返回数组的一个视图
>>> b.flatten()
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
2. 维度改变
数组 reshape 方法和 resize 方法均可改变数组的维度和数组尺寸,如:
>>> bd=b.reshape(4,6) # 这里再次提示,reshape不改变原始值,所以采用赋值的方式
>>> bd
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])
也可以使用 shape 来直接改变数组的尺寸或维度,resize方法跟 shape 赋值一样:
>>> b.shape=(1,1,24)
>>> b
array([[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23]]])
>>> bd.resize(1,1,24)
>>> bd
array([[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23]]])
shape 和 resize 均会改变原始数组
3. 转置
转置即把数组的尺寸大小互换,可使用 numpy 中的 transpose 函数也可以使用之前提到的 nadarry.T :
>>> b.shape=(3,4,2)
>>> b
array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11],
[12, 13],
[14, 15]],
[[16, 17],
[18, 19],
[20, 21],
[22, 23]]])
>>> np.transpose(b) # 等价于 b.T
array([[[ 0, 8, 16],
[ 2, 10, 18],
[ 4, 12, 20],
[ 6, 14, 22]],
[[ 1, 9, 17],
[ 3, 11, 19],
[ 5, 13, 21],
[ 7, 15, 23]]])
>>> np.transpose(b).shape
(2, 4, 3) # 可以看到数组的结构被互换了
七、数组组合
这里只介绍几个主要的组合函数
- 水平组合(hstack)
- 垂直组合(vstack)
- 深度组合(dstack)
- 列组合(colume_stack)
- 行组合(row_stack)
1. 水平组合
把所有参加组合的数组拼接起来,各数组行数应当相等
>>> a=np.arange(9).reshape(3,3)
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> b=np.array([[0,11,22,33],[44,55,66,77],[88,99,00,11]])
>>> b
array([[ 0, 11, 22, 33],
[44, 55, 66, 77],
[88, 99, 0, 11]])
>>> np.hstack((a,b)) # 因为 hstack 函数的参数只有一个,所以把要参加组合的数组对象以元祖的形式传参
array([[ 0, 1, 2, 0, 11, 22, 33],
[ 3, 4, 5, 44, 55, 66, 77],
[ 6, 7, 8, 88, 99, 0, 11]])
如果参加组合的数组行不一致,则会报错:
>>> c=np.array([[0,11,22],[44,55,66],[88,99,00],[22,33,44]])
>>> print c
[[ 0 11 22]
[44 55 66]
[88 99 0]
[22 33 44]]
>>> np.hstack((a,c))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\numpy\core\shape_base.py", line 288, in hstack
return _nx.concatenate(arrs, 1)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
2. 垂直组合
垂直组合即吧所有参加组合的数组追加在一起,各数组列数应一致:
>>> np.vstack((a,c))
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 11, 22],
[44, 55, 66],
[88, 99, 0],
[22, 33, 44]])
此外再介绍一个函数,concatenate 可以直接进行水平组合以及垂直组合:
numpy.concatenate((a1,a2,...),axis=0)
参数解释:
a1,a2,... : 需要拼接的矩阵
axis : 拼接的方式,0 表示按列(也就是追加,垂直组合)
1表示按行(也就是水平组合)
例:
>>> np.concatenate((a,b),axis=1) # 水平组合
array([[ 0, 1, 2, 0, 11, 22, 33],
[ 3, 4, 5, 44, 55, 66, 77],
[ 6, 7, 8, 88, 99, 0, 11]])
>>>
>>> np.concatenate((a,c),axis=0) # 垂直组合
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 11, 22],
[44, 55, 66],
[88, 99, 0],
[22, 33, 44]])
3. 深度组合
深度组合即将参加组合的个数组相同位置的数组组合在一起,我的理解就是下标相同的组合在一起,所以需要数组的维度相同
例:
>>> d=np.delete(b,3,axis=1)
# delete 函数可以删除数组中的指定数据,axis=1 表示列, axis=0 表示行
>>> d
array([[ 0, 11, 22],
[44, 55, 66],
[88, 99, 0]])
>>> np.dstack((a,d))
array([[[ 0, 0],
[ 1, 11],
[ 2, 22]],
[[ 3, 44],
[ 4, 55],
[ 5, 66]],
[[ 6, 88],
[ 7, 99],
[ 8, 0]]])
4. 列组合
column_stack 对于一维数组按列的方向进行组合,对于二维数组和水平组合相同
>>> a1=np.arange(4)
>>> a2=np.arange(4)*2
>>> np.column_stack((a1,a2))
array([[0, 0],
[1, 2],
[2, 4],
[3, 6]])
5. 行组合
row_stack 对于一维数组按行的方向组合,对于二维数组和垂直组合效果相同
>>> np.row_stack((a1,a2))
array([[0, 1, 2, 3],
[0, 2, 4, 6]])
八、数组分拆
分拆类型分为:
- 水平分拆(hsplit)
- 垂直分拆(vsplit)
- 深度分拆(dsplit)
1. 水平分拆
把数组沿着水平方向进行分拆,每个数组分拆成单个元素
>>> a=np.arange(9).reshape(3,3)
>>> print a
[[0 1 2]
[3 4 5]
[6 7 8]]
>>>
>>> ahs=np.hsplit(a,3)
>>> print ahs
[array([[0],
[3],
[6]]), array([[1],
[4],
[7]]), array([[2],
[5],
[8]])]
>>> type(ahs) # 分拆的结果返回是列表,列表中的元素才是numpy数组
<type 'list'>
>>> type(ahs[1])
<type 'numpy.ndarray'>
2. 垂直分拆
把数组沿着垂直方向进行分拆:
>>> np.vsplit(a,3)
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
同样水平分拆和垂直分拆都可以调用 split 函数进行分拆
>>> np.split(a,3,axis=1) # axis=1 为水平拆分
[array([[0],
[3],
[6]]), array([[1],
[4],
[7]]), array([[2],
[5],
[8]])]
>>> np.split(a,3,axis=0) # axis=0 为垂直拆分
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
3. 深度拆分
按照深度方向分拆3个维度以上(含)的数组:
>>> ads=np.arange(12)
>>> ads.shape=(2,2,3)
>>> print ads
[[[ 0 1 2]
[ 3 4 5]]
[[ 6 7 8]
[ 9 10 11]]]
>>> np.dsplit(ads,3)
[array([[[0],
[3]],
[[6],
[9]]]), array([[[ 1],
[ 4]],
[[ 7],
[10]]]), array([[[ 2],
[ 5]],
[[ 8],
[11]]])]
九、ufunc运算
ufunc是universal function的缩写,它是一种能对数组的每个元素进行操作的函数。NumPy内置的许多ufunc函数都是在C语言级别实现的,因此它们的计算速度非常快。这些函数可以进行四则运算,比较运算以及布尔运算等。可以使用“out=” 关键字来指定把函数返回结果存储在指定数组中,用户可以用 frompyfunc 函数来自定义 ufunc 函数。
我这里只介绍部分 ufunc 运算,感兴趣的可以去找下相关资料
1. 函数运算、比较运算、布尔运算
>>> a1=np.arange(0,10)
>>> a1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a2=np.arange(0,20,2)
>>> a2
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
>>> a3=np.add(a1,a2,out=a1) # numpy.add 两个数组相加,out=后面的数组需是事先定义过的数组,out=关键字可以省略
>>> print a3,a1
[ 0 3 6 9 12 15 18 21 24 27] [ 0 3 6 9 12 15 18 21 24 27]
>>> id(a3) == id(a1)
True
# 从运算结果可以看书,使用 out 关键字指定数组与通常使用赋值方式得到的函数运算结果数组是绑定到同一个对象的
>>> a1 > a2
array([False, True, True, True, True, True, True, True, True,
True])
>>> any(a1>a2) # 或
True
>>> all(a1>a2) # 且
False
2. 自定义 ufunc 函数
有时候用户需要自定义函数对数组元素进行操作,这时可以用 frompyfun 函数将一个计算单个元素的函数转换成 ufunc 函数。frompyfunc 的调用格式为:
frompyfunc(func, n_in, n_out) n_in、n_out分别表示输入参数的个数和返回值的个数
比如,在考试中由于出题难度偏大,需要对所有人的分数进行提升,并且保持分数的相对位置不变,可编制一个函数:
def liftscore(n):
n_new=np.sqrt((n^2)*100) #平方根
return n_new
使用 frompyfunc 将其自定义为 ufunc 函数,并对数组对象进行操作:
>>> score=np.array([87,77,56,100,60])
>>> score_1=np.frompyfunc(liftcore,1,1)(score)
>>> score_1
array([92.19544457292888, 88.88194417315589, 76.15773105863909,
100.99504938362078, 78.74007874011811], dtype=object)
注意:frompyfunc 转换的 ufunc 函数所返回数组的元素类型是 object。因此还需要调用数组的 astype 方法以将其转换为浮点数组。
>>> score_1=score_1.astype(float)
使用 vectorize 可以实现 frompyfunc 类似的功能,但它可以通过 otypes 参数指定返回数组的元素类型。otypes 参数可以是一个表示元素类型的字符串,也可以是一个类型列表,使用列表可以描述多个返回数组的元素类型:
>>> score_2=np.vectorize(liftcore,otypes=[float])(score)
>>> any(score_1==score_2)
True
3. 广播 (这两块后续再补上吧。我自己都还没玩6)
4. ufunc 的方法
十、矩阵
矩阵是 numpy 提供的另外一种数据类型,可以使用 mat 或 matrix 函数将数组转化为矩阵
>>> m1=np.mat([[1,2,3],[4,5,6]])
>>> m1
matrix([[1, 2, 3],
[4, 5, 6]])
>>> m1*8
matrix([[ 8, 16, 24],
[32, 40, 48]])
>>>
>>> m2=np.matrix([[1,2,3],[4,5,6],[7,8,9]])
>>>
>>> m1*m2 # 矩阵乘法:两个矩阵的乘法仅当第一个矩阵的列数和另一个矩阵的行数相等时才能定义
matrix([[30, 36, 42],
[66, 81, 96]])
上面计算的流程:(不知道简书矩阵markdown 怎么写,心塞)
1*1+2*4+3*7=30,1*2+2*5+3*8=36,1*3+2*6+3*9=42
4*1+5*4+6*7=66,4*2+5*5+6*8=81,4*3+5*6+6*9=96
一般情况 python 中都会使用数组进行运算,如果实在要使用矩阵进行运算的话,自行使用
dir 函数查看矩阵对象的方法和属性。
十一、文件读写
文件读写通常通过 savetxt、loadtxt 等 I/O 函数来实现:
>>> np.savetxt('m2.txt',m2) # 将上面定义的 m2 对象作为 m2.txt 存储在当前文件夹中
loadtxt 函数主要用来读取 csv 格式的文件,自动切分字段,并将数据载入 numpy 数组:
>>> m2_reload=np.loadtxt('m2.txt',delimiter=' ') # delimiter 指定读取文本的分隔符
>>> m2_reload
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
这里我来尝试读一个 excel 文件,文件名为1.xlsx ,内容如下:
需要将其读入 numpy 中作为一个数组对象:
>>> stock=np.dtype([('name',np.str_,4),('num',np.int32),('content',np.str_,20)])
>>> l_stock=np.loadtxt('C:\Users\EPAY\Desktop\\1.xlsx',delimiter=',',dtype=stock)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\numpy\lib\npyio.py", line 1044, in loadtxt
first_line = next(fh)
UnicodeDecodeError: 'gbk' codec can't decode bytes in position 22-23: illegal multibyte sequence
好了,理论上来说应该是可以读进去的,但是可能由于我 excel 的编码问题,导致读进去出现异常,参考了这个文档,暂时还未解决:
https://stackoverflow.com/questions/24694736/numpy-loadtxt-encoding
欢迎读者帮忙解决此类问题,这里附上 excel 源文件:百度网盘
本文参考文档:
http://old.sebug.net/paper/books/scipydoc/numpy_intro.html#ufunc
https://www.cnblogs.com/woaielf/p/5556553.html
梅西镇楼~~~