一、生成ndarray
1. 最简单的方法就是使用array函数。array函数接收任何的序列型对象(当然也包括其他的数组),生成一个新的包含传递数组的numpy数组。例如:
import numpy as np
data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
arr1
array([ 6. , 7.5, 8. , 0. , 1. ])
2.嵌套序列,例如同等长度的列表,将会自动转换成多维数组
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
arr2
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
通过ndim和shape可以查看属性:
arr2.ndim
2
arr2.shape
(2, 4)
3. 除了用np.array,还有很多其他的函数可以创建新数组。
例如,给定长度和形状后,zeros可以一次性创建全为0的数组,ones可以创建全为1的数组。empty可以创建一个没有初始化数组的数组。想要创建高维数组,则需要为shape传递一个元组:
np.zeros(10)
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.zeros((3, 6))
array([[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.]])
np.empty((2, 3, 2))
array([[[ 6.93191462e-310, 1.59160125e-316],
[ 0.00000000e+000, 0.00000000e+000],
[ 0.00000000e+000, 5.68519743e-062]],
[[ 3.59789606e+179, 6.52172099e-038],
[ 1.41915235e+161, 4.42531362e-062],
[ 1.46169329e+185, 7.13064093e-067]]])
想要用np.empty创建一个全为0的数组并不安全,有些时候它可能返回未初始化的垃圾数值
arange是python内建函数range的数组版:
np.arange(15)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
下表是标准数组的生成函数,如果没有特别声明。默认的数据类型都是float64
函数名 | 描述 |
---|---|
array | 将输入数据转换为ndarray,如不显式致命数据类型,将自动推断 |
asarray | 将输入转为ndarray,如果已经是ndarray则不再复制 |
arange | python内建函数range的数组版,返回一个数组 |
ones | 根据形状生成一个全1的数组 |
ones_like | 根据所给的数组生成一个形状一样的全1数组 |
zeros | 根据形状生成一个全0的数组 |
zeros_like | 根据所给的数组生成一个形状一样的全0数组 |
empty | 根据形状生成一个没有初始化数值的空数组 |
empty_like | 根据所给的数组生成一个形状一样但没有初始化数据的空数组 |
full | 根据形状生成一个制定数值的数组 |
full_like | 根据所给的数组生成一个形状一样但内容是指定数值的数组 |
eye,identity | 生成一个 N ⋅ N N\cdot N N⋅N的单位矩阵 |
二、ndarray的数据类型
numpy数据类型如下表所示:
类型 | 类型代码 |
---|---|
int8,uint8 | i1,u1 |
int16,uint16 | i2,u2 |
int32,uint32 | i4,u4 |
int64,uint64 | i8,u8 |
float16 | f2 |
float32 | f4或f |
float64 | f8或d |
float128 | f16或g |
complex64 | c8 |
complex128 | c16 |
complex256 | c32 |
bool | ? |
object | o |
string_ | S |
unicode_ | U |
你可以使用astype方法显式地转换数组的数据类型
arr = np.array([1, 2, 3, 4, 5])
arr.dtype
dtype('int64')
float_arr = arr.astype(np.float64)
float_arr.dtype
dtype('float64')
在上面例子中,整数被转换成了浮点数,如果我把浮点数转换成整数,则小数点后的部分将被消除
arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
arr.dtype
dtype('float64')
arr.astype(np.int32)
array([ 3, -1, -2, 0, 12, 10], dtype=int32)
三、基础索引与切片
一位数组比较简单,看起来和python的列表很类似:
arr = np.arange(10)
arr[5]
5
arr[5:8]
array([5, 6, 7])
arr[5:8] = 12
arr
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
如你所见,如果你传入了一个数值给数组的切片,数值被传递给了整个切片,区别于python的内建列表,数组的切片是原数组的视图。这意味着数据并不是被复制了,任何对于视图的修改都会放映到原数组上。
arr_slice = arr[5:8]
arr_slice
array([12, 12, 12])
当我改变arr_slice,变化也会体现在原数组上:
arr_slice[1] = 12345
arr
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8, 9])
如果你想要一份数组切片的拷贝而不是一份视图的化话,你就逆序显式地复制这个数组,例如arr[5:8].copy
对于更高唯独的数组,你会有更多选择。在一个二维数组中,每个索引值对应的元素不再是一个值,而是一个数组:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]
array([7, 8, 9])
arr2d[0][2]
3
arr2d[0, 2]
3
arr2d[:2, 1:]
array([[2, 3],
[5, 6]])
arr2d[2]
array([7, 8, 9])
arr2d[:, :2]
array([[1, 2],
[4, 5],
[7, 8]])
arr2d[1, :2]和arr2d[1:2, :2]有所不同
arr2d[1, :2] # shape = (2, )
array([4, 5])
arr2d[1:2, :2] # shape = (1, 2)
array([[4, 5]])
四、布尔索引
让我们考虑以下例子,假设我们的数据都在数组中,并且数组中的数据是一些存在重复的人名。我会使用numpy.random中的randn函数来生成一些随机正态分布的数据:
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
names
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'],
dtype='<U4')
data
array([[-0.70522835, 1.47087563, 0.35250176, 0.02848163],
[-0.78749969, -0.72789731, -0.7797904 , 0.77486765],
[ 1.30127429, 0.62887439, 1.06599137, 1.52760906],
[ 0.9931709 , 0.96859579, 0.89749706, 0.09828308],
[ 1.46165639, 0.42842885, 0.24971774, 0.26540473],
[-1.34049878, 0.39110936, -1.40111365, 0.6045064 ],
[ 0.30309953, 1.29267219, 0.66753705, -0.86407424]])
假设每个人名都和data数组中的一行相对应,并且我们想要选中所有的‘Bob’对应的行。与数学操作类似,数组的比较操作(比如 == )也是可以向量化的。因此,比较names数组和字符串’Bob’会产生一个布尔值数组:
names == 'Bob'
array([ True, False, False, True, False, False, False], dtype=bool)
data[names == 'Bob']
array([[-0.70522835, 1.47087563, 0.35250176, 0.02848163],
[ 0.9931709 , 0.96859579, 0.89749706, 0.09828308]])
布尔值数组的长度必须和数组轴索引长度一致。你甚至还可以用切片或者整数值(或整数值的序列)对布尔值数组进行混合和匹配。
data[names == 'Bob', 2:]
array([[ 0.35250176, 0.02848163],
[ 0.89749706, 0.09828308]])
当要选择三个名字中的两个来组合多个布尔值条件时,需要使用布尔算术运算符,如&(and)和|(or):
注意:当使用复合条件时,只能用&和|,不能用and和or
mask = (names == 'Bob') | (names == 'Will')
mask
array([ True, False, True, True, True, False, False], dtype=bool)
mask = (names == 'Bob') or (names == 'Will')
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-58-bae01d3eeda5> in <module>()
----> 1 mask = (names == 'Bob') or (names == 'Will')
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
基于常识来设置布尔值数组的值也是可行的。将data中所有的负值设置为0,我们需要做:
data[data < 0] = 0
data
array([[ 0. , 1.47087563, 0.35250176, 0.02848163],
[ 0. , 0. , 0. , 0.77486765],
[ 1.30127429, 0.62887439, 1.06599137, 1.52760906],
[ 0.9931709 , 0.96859579, 0.89749706, 0.09828308],
[ 1.46165639, 0.42842885, 0.24971774, 0.26540473],
[ 0. , 0.39110936, 0. , 0.6045064 ],
[ 0.30309953, 1.29267219, 0.66753705, 0. ]])
五、神奇索引
假设我们有一个8 × 4的数组:
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i
arr
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.]])
为了选出一个符合特定顺序的子集,你可以简单地通过传递一个包含指明所需顺序的列表或数组来完成:
arr[[4, 3, 0 ,6]]
array([[ 4., 4., 4., 4.],
[ 3., 3., 3., 3.],
[ 0., 0., 0., 0.],
[ 6., 6., 6., 6.]])
arr[[-3, -5, -7]]
array([[ 5., 5., 5., 5.],
[ 3., 3., 3., 3.],
[ 1., 1., 1., 1.]])
传递多个索引数组时情况有些许不同,这样会根据每个索引元组对应的元素选出一个一位数组:
arr = np.arange(32).reshape((8, 4))
arr
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]])
arr[[1, 5, 7, 2], [0, 3, 1, 2]]
array([ 4, 23, 29, 10])
通常情况下,我们所设想的结果是通过选择矩阵中行列的子集所形成的矩形区域。下面是实现我们想法的一种方式:
arr[[1, 5, 7, 2]] [:, [0, 3, 1, 2]]
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
注意,神奇索引与切片不同,它总是将数据负值到一个新的数组中