NumPy之于数值计算特别重要的原因之一,是因为它可以高效处理大数组的数据。这是因为:
- NumPy是在一个连续的内存块中存储数据,独立于其他Python内置对象。NumPy的C语言编写的算法库可以操作内存,而不必进行类型检查或其它前期工作。比起Python的内置序列,NumPy数组使用的内存更少。
- NumPy可以在整个数组上执行复杂的计算,而不需要Python的for循环。
一、创建ndarray
(1)arange()函数:
调用格式:arange(start,stop,step)
start:间隔开始。间隔包括此值,默认开始值为0。
stop:间隔结束。间隔不包括此值。
step:间隔步长。
例子:
import numpy as np >>> np.arange(3) #array([0, 1, 2]) >>> np.arange(3.0) #array([ 0., 1., 2.]) >>> np.arange(3,7) #array([3, 4, 5, 6]) >>> np.arange(3,7,2) #array([3, 5])
arr = np.arange(
32).reshape((
8,
4))
(2)random模块:随机数生成
rand():函数根据给定维度生成[0,1)之间的数据,包含0,不包含1。如:>>> data1 = np.random.rand(2,3)
randn():函数根据给定维度生成一个或一组样本,具有标准正态分布。如:>>>data2 = np.random.randn(2,3)
(3) 每个数组都有一个shape(一个表示各维度大小的元组)和一个dtype(一个用于说明数组数据类型的对象)属性。
>>> data.shape #(2,3) >>> data.dtype #float64 >>> data.ndim #2
(4)创建数组函数
array函数:它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的NumPy数组。
>>> data1 = [1,2,3,4] >>> data2 = [[1,3,4,6],[2,4,6,9]] >>> data_arr1 = np.array(data1) >>> data_arr2 = np.array(data2) >>> print(data_arr1) >>> print(data_arr2)
[1 2 3 4]
[[1 3 4 6]
[2 4 6 9]]
除np.array之外,还有一些函数也可以新建数组。比如,zeros和ones分别可以创建指定长度或形状的全0或全1数组。empty可以创建一个没有任何具体值的数组。要用这些方法创建多维数组,只需传入一个表示形状的元组。
二、ndarray的数据类型
dtype(数据类型)是一个特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息:
arr1 = np.array([1, 2, 3], dtype=np.float64)
可以通过ndarray的astype方法明确地将一个数组从一个dtype转换成另一个dtype:
>>> arr = np.array([1, 2, 3, 4, 5]) >>> arr.dtype
dtype(
'int64')
>>> float_arr = arr.astype(np.float64) >>> float_arr.dtype
dtype(
'float64')
调用astype总会创建一个新的数组(一个数据的备份),即使新的dtype与旧的dtype相同。
三、numpy数组的运算
数组很重要,因为它使你不用编写循环即可对数据执行批量运算。NumPy用户称其为矢量化(vectorization)。大小相等的数组之间的任何算术运算都会将运算应用到元素级。
arr = np.array([[2,4,6,8],[1,4,7,3]]) print(arr) print(arr*arr) print(arr-arr)
[[2 4 6 8]
[1 4 7 3]]
[[ 4 16 36 64]
[ 1 16 49 9]]
[[0 0 0 0]
[0 0 0 0]]
数组与标量的算术运算会将标量值传播到各个元素:
print(1/arr) print(arr**0.5)
[[0.5 0.25 0.16666667 0.125 ]
[1. 0.25 0.14285714 0.33333333]]
[[1.41421356 2. 2.44948974 2.82842712]
[1. 2. 2.64575131 1.73205081]]
大小相同的数组之间的比较会生成布尔值数组:
arr1 = np.array([[2,4,9,12],[2,4,7,3]]) print(arr<arr1)
[[False False True True]
[ True False False False]]
四、基本的索引和切片
当你将一个标量值赋值给一个切片时(如arr[5:8]=12),该值会自动传播(也就说后面将会讲到的“广播”)到整个选区。跟列表最重要的区别在于,数组切片是原始数组的视图。这意味着数据不会被复制,视图上的任何修改都会直接反映到源数组上。
如果你想要得到的是ndarray切片的一份副本而非视图,就需要明确地进行复制操作,例如arr[5:8].copy()。
(1)切片索引
arr = np.array([0, 1, 2, 3, 4, 64, 64, 64, 8, 9]) print(arr) print(arr[1:6]) arr2d = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]]) print(arr2d) print(arr2d[1]) print(arr2d[:2]) print(arr2d[:,:2])
[ 0 1 2 3 4 64 64 64 8 9]
[ 1 2 3 4 64]
[[1 2 3]
[4 5 6]
[7 8 9]]
[4 5 6]
[[1 2 3]
[4 5 6]]
[[1 2]
[4 5]
[7 8]]
对切片表达式的赋值操作也会被扩散到整个选区
(2)布尔型索引
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) data = np.random.randn(7,4) print(names=='Bob') print(data[names == 'Bob']) #布尔型数组的长度必须跟被索引的轴长度一致。此外,还可以将布尔型数组跟切片、整数混合使用 print(data[names == 'Bob',2:]) print(data[names == 'Bob',2]) print(data[names != 'Bob']) #~操作符用来反转条件很好用 print(data[~(names == 'Bob')]) #Python关键字and和or在布尔型数组中无效。要使用&与|。 print((names == 'Bob')|(names == 'Will')) print(data[(names == 'Bob')|(names == 'Will')]) #将data中的所有负值都设置为0 data[data<0]=0 print(data)
[ True False False True False False False]
[[ 0.56947009 -0.61103578 -0.83001537 -1.03831856]
[-0.72723257 0.72598221 0.36284245 -1.6662993 ]]
[[-0.83001537 -1.03831856]
[ 0.36284245 -1.6662993 ]]
[-0.83001537 0.36284245]
[[ 0.8576646 1.37711165 -0.97693128 0.70626358]
[ 0.5193894 -1.07092886 -1.60173978 0.03837702]
[ 0.25293635 0.09664311 2.20232715 0.44455463]
[-0.4188091 -1.62252806 -1.435578 1.18620694]
[-0.78747297 1.35354608 0.20774316 0.84989592]]
[[ 0.8576646 1.37711165 -0.97693128 0.70626358]
[ 0.5193894 -1.07092886 -1.60173978 0.03837702]
[ 0.25293635 0.09664311 2.20232715 0.44455463]
[-0.4188091 -1.62252806 -1.435578 1.18620694]
[-0.78747297 1.35354608 0.20774316 0.84989592]]
[ True False True True True False False]
[[ 0.56947009 -0.61103578 -0.83001537 -1.03831856]
[ 0.5193894 -1.07092886 -1.60173978 0.03837702]
[-0.72723257 0.72598221 0.36284245 -1.6662993 ]
[ 0.25293635 0.09664311 2.20232715 0.44455463]]
[[0.56947009 0. 0. 0. ]
[0.8576646 1.37711165 0. 0.70626358]
[0.5193894 0. 0. 0.03837702]
[0. 0.72598221 0.36284245 0. ]
[0.25293635 0.09664311 2.20232715 0.44455463]
[0. 0. 0. 1.18620694]
[0. 1.35354608 0.20774316 0.84989592]]
(3)花式索引
利用整数数组进行索引,花式索引跟切片不一样,它总是将数据复制到新数组中。
arr = np.empty((8,4)) for i in range(8): arr[i] = i print(arr) print(arr[[1,2,4,0]])
[[1. 1. 1. 1.]
[2. 2. 2. 2.]
[4. 4. 4. 4.]
[0. 0. 0. 0.]]
四、快速的元素级数组函数
五、利用数组进行数据处理
numpy.where(cond, xarr, yarr)
函数是三元表达式x if condition else y的矢量化版本。np.where的第二个和第三个参数不必是数组,它们都可以是标量值。在数据分析工作中,where通常用于根据另一个数组而产生一个新的数组。
arr = np.random.randn(3,4) print(arr) cond = arr>0 print(cond) narr = np.where(cond,2,arr) print(narr)
[[ 0.38456504 1.61308418 2.38985258 0.23335973]
[-1.43672573 -1.29377899 -0.27695053 1.01830536]
[-1.37364818 -1.17896878 0.32970775 1.34110048]]
[[ True True True True]
[False False False True]
[False False True True]]
[[ 2. 2. 2. 2. ]
[-1.43672573 -1.29377899 -0.27695053 2. ]
[-1.37364818 -1.17896878 2. 2. ]]
数学和统计方法
arr = np.random.randn(5, 4) arr.mean() arr.sum() arr.cumsum() arr.cumprod()
排序
顶级方法np.sort返回的是数组的已排序副本,而就地排序则会修改数组本身。
arr = np.random.randn(6) arr.sort()
唯一化
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) np.unique(names)