ndarray的数据类型
dtype(数据类型)是一个特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息
a = np.array([1,2,3],dtype=np.float64)
a
array([1., 2., 3.])
a.dtype
dtype('float64')
b = np.array([1,2,3],dtype=np.int32)
b
array([1, 2, 3])
b.dtype
dtype('int32')
numpy的数据类型
类型 | 类型代码 | 说明 |
int8、uint8 | i1、u1 | 有符号和无符号的8位(1个字节)整形 |
int16、uint16 | i2、u2 | 有符号和无符号的16位(2个字节)整形 |
int32、uint32 | i3、u3 | 有符号和无符号的32位(4个字节)整形 |
int64、uint64 | i4、u4 | 有符号和无符号的64位(8个字节)整形 |
float16 | f2 | 半精度浮点数 |
float32 | f4或f | 标准的双精度浮点数。与C的float兼容 |
float64 | f8或d | 标准的双精度浮点数。与C的double和python的float对象兼容 |
float128 | f16或g | 扩展精度浮点数 |
complex64 、complex128 | c8、c16 | 分别用两个32位、64位或128位位浮点数表示的复数 |
complex256 | c32 | 复数 |
bool | ? | 存储True和False值得布尔类型 |
object | O | Python对象类型 |
string_ | S | 固定长度的字符串类型(每个字符一个字节)。例如,要创建一个长度为10的字符串,应使用510 |
unicode_ | U | 固定长度的unicode类型(字节数由平台决定)。跟字符串的定义方式一样(如U10) |
可以通过ndarray的astype方法显式的转换其dtype:
#整形转浮点型
a = np.array([1,2,3])
a.dtype
dtype('int32')
a_float = a.astype(np.float64)
a_float.dtype
dtype('float64')
#浮点型转整形,小数点后的数字直接舍去
b = np.array([1.2,2.3,3.4])
b.dtype
dtype('float64')
b_int = b.astype(np.int64)
b_int.dtype
dtype('int64')
b_int
array([1, 2, 3], dtype=int64)
#字符串数组全是数字,也可以转为对应的数值形式
c = np.array(['1.2','2.3','3.4'],dtype=np.string_)
c.dtype
dtype('S3')
c.astype(float)
array([1.2, 2.3, 3.4])
#dtype的另一种用法
a = np.array([1,2,3],dtype=np.int64)
b = np.array([1.1,2.2,3.3],dtype=np.float64)
a.astype(b.dtype)
array([1., 2., 3.])
#dtype的简介表示
empty_uint32 = np.empty(8,dtype='u4')
empty_uint32
array([ 0, 5177428, 424, 0, 3538688192,
482, 65793, 0], dtype=uint32)
数组和标量之间的运算
数组可以使你不用编写循环即可对数据执行批量运算。这通常就叫做矢量化。大小相等的数组之间的任何算术运算都会将运算应用用到元素级。
a = np.array([[1,2,3],[4,5,6]])
a
array([[1, 2, 3],
[4, 5, 6]])
a * a
array([[ 1, 4, 9],
[16, 25, 36]])
a - a
array([[0, 0, 0],
[0, 0, 0]])
1 / a
array([[1. , 0.5 , 0.33333333],
[0.25 , 0.2 , 0.16666667]])
a ** 0.5
array([[1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974]])
基本的索引和切片
一维数组和python列表的功能差不多
a = np.arange(5)
a
array([0,1,2,3,4])
a[3]
3
a[1:3]
array([1, 2])
a[1:3]=15
a
array([ 0, 15, 15, 3, 4])
当把一个标量赋值给一个切片时,该值会自动覆盖原先数组。数组切片是原始数组的视图,视图上的任何修改都会直接反应到原数组上。
a_slice = a[1:3]
In[5]: a_slice[1] = 123456
In[6]: a
Out[6]: array([ 0, 1, 123456, 3, 4])
In[7]: a_slice[:] = 64
In[8]: a
Out[8]: array([ 0, 64, 64, 3, 4])
二维数组
In[9]: a2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
In[10]: a2[2]
Out[10]: array([7, 8, 9])
`In[11]: a2[0][2]
Out[11]: 3
In[12]: a2[0,2]
Out[12]: 3
二维数组的索引如下表示
#三维数组
In[3]: a3 = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
In[4]: a3
Out[4]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In[5]: a3[0]
Out[5]:
array([[1, 2, 3],
[4, 5, 6]])
In[6]: old_values = a3[0].copy()
In[8]: a3[0] = 42
In[9]: a3
Out[9]:
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
In[10]: a3[0] = old_values
In[11]: a3
Out[11]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In[12]: a3[1,0]
Out[12]: array([7, 8, 9])
切片索引
#一维数组
In[13]: a1 = np.arange(10)
In[14]: a1
Out[14]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In[15]: a1[1:6]
Out[15]: array([1, 2, 3, 4, 5])
#二维数组
In[16]: a2 = np.array([[1,2,3],[4,5,6],[7,8,9]])
In[17]: a2
Out[17]:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
In[18]: a2[:2]
Out[18]:
array([[1, 2, 3],
[4, 5, 6]])
通过以上例子可以看出,它是沿着第0轴(即第一个中括号)切片的,即切片是沿着一个轴向选取元素的。
In[19]: a2[:2,1:]
Out[19]:
array([[2, 3],
[5, 6]])
In[20]: a2[1,:2]
Out[20]: array([4, 5])
In[21]: a2[2,:1]
Out[21]: array([7])
In[22]: a2[:,:1]
Out[22]:
array([[1],
[4],
[7]])
In[24]: a2[:2,1:] = 0
In[25]: a2
Out[25]:
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
布尔值索引
假设一个用于存储数据的数组以及一个存储姓名的数组(含有重复项)。使用numpy.random中的randn函数生成一些正态分布的随机数据
In[29]: names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
In[30]: names
Out[30]: array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')
In[31]: data = np.random.randn(7,4)
In[32]: data
Out[32]:
array([[ 1.06804939, 0.53763406, -0.34468005, -0.26877366],
[-0.77521385, -1.22275166, -0.40538837, -0.55845101],
[-1.38442773, -1.45071359, 0.5586666 , 0.07969325],
[-0.16880411, -0.3988792 , -1.28797105, 0.62871321],
[ 1.15519442, -0.40048694, 1.53369361, 0.70366078],
[ 0.51046507, -1.04062609, -1.3817315 , 0.87470915],
[-0.58902799, -0.69330514, 0.49844266, -0.05298475]])
假设每个名字都对应data数组的一行
In[33]: names == "Bob"
Out[33]: array([ True, False, False, True, False, False, False])
In[34]: data[names == 'Bob']
Out[34]:
array([[ 1.06804939, 0.53763406, -0.34468005, -0.26877366],
[-0.16880411, -0.3988792 , -1.28797105, 0.62871321]])
In[35]: data[names == 'Bob',2:]
Out[35]:
array([[-0.34468005, -0.26877366],
[-1.28797105, 0.62871321]])
In[36]: data[names == 'Bob',3]
Out[36]: array([-0.26877366, 0.62871321])
选择‘Bob’以外的值可以用不等符号(!=),也可以直接通过非(~)。
In[37]: names != 'Bob'
Out[37]: array([False, True, True, False, True, True, True])
In[40]: data[~(names == 'Bob')]
Out[40]:
array([[-0.77521385, -1.22275166, -0.40538837, -0.55845101],
[-1.38442773, -1.45071359, 0.5586666 , 0.07969325],
[ 1.15519442, -0.40048694, 1.53369361, 0.70366078],
[ 0.51046507, -1.04062609, -1.3817315 , 0.87470915],
[-0.58902799, -0.69330514, 0.49844266, -0.05298475]])
同时选取多个名字的组合需要使用|(或)
In[45]: mask = (names == 'Bob') | (names == 'Will')
In[46]: mask
Out[46]: array([ True, False, True, True, True, False, False])
In[47]: data[mask]
Out[47]:
array([[ 1.06804939, 0.53763406, -0.34468005, -0.26877366],
[-1.38442773, -1.45071359, 0.5586666 , 0.07969325],
[-0.16880411, -0.3988792 , -1.28797105, 0.62871321],
[ 1.15519442, -0.40048694, 1.53369361, 0.70366078]])
通过布尔型数组设置值
In[54]: data[data < 0] = 0
In[55]: data
Out[55]:
array([[1.06804939, 0.53763406, 0. , 0. ],
[0. , 0. , 0. , 0. ],
[0. , 0. , 0.5586666 , 0.07969325],
[0. , 0. , 0. , 0.62871321],
[1.15519442, 0. , 1.53369361, 0.70366078],
[0.51046507, 0. , 0. , 0.87470915],
[0. , 0. , 0.49844266, 0. ]])
In[57]: data[names != 'Joe'] = 7
In[58]: data
Out[58]:
array([[7. , 7. , 7. , 7. ],
[0. , 0. , 0. , 0. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[0.51046507, 0. , 0. , 0.87470915],
[0. , 0. , 0.49844266, 0. ]])
花式索引
花式索引即利用整数数组进行索引。
In[59]: arr = np.empty((8,4))
In[60]: arr
Out[60]:
array([[6.91409243e-310, 2.20472012e-316, 6.91409302e-310,
6.91409301e-310],
[6.91408939e-310, 6.91409300e-310, 6.91409297e-310,
6.91409301e-310],
[6.91409175e-310, 6.91408937e-310, 6.91409302e-310,
6.91409302e-310],
[6.91409302e-310, 6.91409301e-310, 6.91409300e-310,
6.91409302e-310],
[6.91409300e-310, 6.91409302e-310, 6.91409300e-310,
6.91409193e-310],
[6.91409195e-310, 6.91409302e-310, 6.91409174e-310,
6.91409299e-310],
[6.91409298e-310, 6.91409295e-310, 6.91409301e-310,
6.91409011e-310],
[6.91408640e-310, 6.91409302e-310, 6.91409190e-310,
6.91409300e-310]])
In[61]: for i in range(8):
...: arr[i] = i
...:
In[62]: arr
Out[62]:
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
为了以特定顺序选取行子集,只需要传入一个用于指定顺序的整数列表或者ndarray即可。
In[63]: arr[[1,2,3,4]]
Out[63]:
array([[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.]])
使用负数将从末尾开始选取行
In[64]: arr[[-1,-2,-3]]
Out[64]:
array([[7., 7., 7., 7.],
[6., 6., 6., 6.],
[5., 5., 5., 5.]])
一次传入多个索引数组会有一点特别。他返回的是一个一维数组,其中的元素对应各个索引元组
In[67]: arr = np.arange(32).reshape((8,4))#reshape用于重构多维数组形状
In[68]: arr
Out[68]:
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],
[24, 25, 26, 27],
[28, 29, 30, 31]])
In[70]: arr[[0,1,2,3],[0,1,2,3]]
Out[70]: array([ 0, 5, 10, 15])
为了得到矩阵区域形式的矩阵的行列子集
In[71]: arr[[0,1,2,3]][:,[0,1,2,3]]
Out[71]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In[72]: arr[np.ix_([0,1,2,3],[0,1,2,3])]
Out[72]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
花式索引和切片不一样,它总是将数据复制到新数组中。
数组转置和轴对换
转置是重塑的一种特殊形式,它返回的是源数据的视图(不会进行任何复制操作)。数组不仅有transpose方法,还有一个特殊的T属性。
In[76]: arr = np.arange(15).reshape((3,5))
In[77]: arr
Out[77]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In[78]: arr.T
Out[78]:
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
在进行矩阵计算时,经常需要,比如利用numpy.dot计算矩阵内积X**T * X
n[79]: arr = np.random.randn(6,3)
In[80]: arr
Out[80]:
array([[-1.07635721, -2.07780713, -0.04095446],
[ 0.08187961, -1.02451744, -0.31626861],
[ 1.2343947 , -0.04506441, -0.75610648],
[-1.69744337, 0.12104636, -0.60267598],
[-0.38439969, -0.5898125 , -0.82001761],
[ 1.09967225, 2.18918989, -0.48352121]])
In[81]: np.dot(arr.T,arr)
Out[81]:
array([[ 6.92733555, 4.52559412, -0.10864014],
[ 4.52559412, 10.52403267, -0.20462317],
[-0.10864014, -0.20462317, 1.9428401 ]])
对于高维数组,转置需要得到一个由轴编号组成的元组才能对这些轴进行转置。
In[96]: arr = np.arange(16).reshape((2,2,4))
In[97]: arr
Out[97]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
In[98]: arr.transpose((1,0,2))
Out[98]:
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
shape | index |
2 | 0 |
2 | 1 |
4 | 2 |
transpose的参数即是index的元组,同时也是arr中每一个元素的索引,arr中的元素位置随着参数的改变而改变。
多维数组的swapaxes方法。
In[99]: arr.swapaxes(1,2)
Out[99]:
array([[[ 0, 4],
[ 1, 5],
[ 2, 6],
[ 3, 7]],
[[ 8, 12],
[ 9, 13],
[10, 14],
[11, 15]]])