Numpy的索引和ufunc
一、基本的索引和切片:
1、数组索引
返回来的都是视图,并不会对数据进行复制,如果想复制可以使用copy()
arr=np.arange(10)
print(arr)
arr[5]=8
print(arr)
arr[2:5]=6
print(arr)
输出结果:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([0, 1, 2, 3, 4, 8, 6, 7, 8, 9])
array([0, 1, 6, 6, 6, 8, 6, 7, 8, 9])
numpy 设计的目的是处理大数据,如果每次操作都把数据进行复制,那会产生很大的性能浪费。如果需要得到副本而不是视图,则需要进行显式地复制, arr[5:8].copy()
2、切片索引
ndarry 地切片语法和 python 列表地一维对象差不多,如果是多维度地 ndarray 还可以在多个轴进行切片,也可以跟整数索引混合使用。如果是只用:的切片,那会得到和 array 相同维度地视图
arra2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
arra2d[:2,1:]
arra2d[:2,1:2]
arra2d[2:]
输出结果:
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
array([[2, 3],
[5, 6]])
array([[2],
[5]])
array([[7, 8, 9]])
可以看到,使用了非整数的切片,得到的都还是二维数组。这是因为如果只有一个冒号(:)是对整个轴进行选取的,冒号两边的数字只不过是对轴数量限制,但还是轴。
# 如果使用了整数的切片,就会降维
arra2d[1:,2]
arra2d[2,2]
输出结果:
array([6, 9])
9
注意:切片索引和数组索引返回来的都是视图(布尔索引返回来的是副本),所以对切片的操作也会影响到原数据。
# 使用视图对原数据进行修改
arra2d[:,:]=2
输出结果:
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2]])
3、布尔型索引
布尔型索引的长度必须跟被索引的轴一致(先写就是横轴,后写就是纵轴),还可以将布尔型数组和切片、整数 或 整数序列进行混合使用
names=np.array(['bob','joe','ang','will'])
data=np.random.randn(4,3)
data[names=='bob']
输出结果:
array(['bob', 'joe', 'ang', 'will'],
dtype='<U4')
array([[-0.09280068, 0.58965549, 0.00679073],
[ 0.64898363, 0.28057725, -0.31246341],
[ 0.76704748, 1.56162526, -1.27835386],
[ 1.70463106, -1.6897867 , -1.31967934]])
array([[-0.09280068, 0.58965549, 0.00679073]])
# 布尔索引和整数一起混合使用
data[names=='bob',2:]
输出结果:
array([[ 0.00679073]])
如果有多个条件,可以用 & | ! (与或非),并且非还可以通过加负号的形式实现
# 使用整数索引,会降维
data[(names=='bob')|(names=='ang'),2]
输出结果:
array([ 0.00679073, -1.27835386])
应用,可以批量修改数据,例如把所有负数变成0
data[data<0]=0
注意:通过布尔型索引选取数组的数据,将总会创建副本,即使返回的数据一模一样也是如此。
4、花式索引
花式索引是Numpy 得一个术语,它指的是利用整数数组进行索引。如果想以特定顺序选取行子集,只需传入一个用于指定顺序的整数列表或者 ndarray 就可以了,甚至还可以用负数。
arr = np.empty((8,4))
for i in range(8):
arr[i]=i
arr[[4,3,0,6]]
arr[[-1,2,4]]
输出结果:
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.]])
array([[ 4., 4., 4., 4.],
[ 3., 3., 3., 3.],
[ 0., 0., 0., 0.],
[ 6., 6., 6., 6.]])
array([[ 7., 7., 7., 7.],
[ 2., 2., 2., 2.],
[ 4., 4., 4., 4.]])
多轴花式索引: 会返回交叉位置的数据
arr[[1,5,7,2],[0,3,1,2]]
输出结果:
array([ 1., 5., 7., 2.])
如果不想选取对应位置的数,可以使用 np.ix_ 函数
index = np.ix_([1,5,7,2],[0,3,1,2])
arr[index]
输出结果: 是一个元组,元组里面
(array([[1],
[5],
[7],
[2]]), array([[0, 3, 1, 2]]))
array([[ 1., 1., 1., 1.],
[ 5., 5., 5., 5.],
[ 7., 7., 7., 7.],
[ 2., 2., 2., 2.]])
注意:花式索引会复制数据
二、通用函数:快速的元素级数组函数
通用函数(即 ufunc)是一种对 ndarray 种的数据执行元素级运算的函数。可以将其看作是简单函数的矢量化包装器。(接受一个可变参数,给任意个标量数据都可以返回任意个值)
arr=np.arange(10).reshape(2,5)
np.sqrt(arr)
np.exp(arr)
输出结果:
array([[ 0. , 1. , 1.41421356, 1.73205081, 2. ], [ 2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ]])
array([[ 1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01, 5.45981500e+01], [ 1.48413159e+02, 4.03428793e+02, 1.09663316e+03, 2.98095799e+03, 8.10308393e+03]])
sqrt、exp 都是一元的 ufunc,另外一些(如 add 或者 maximum) 则可以接受2个参数,叫做二元通用函数。
123.pngx = np.random.randn(8)
y = np.random.randn(8)
# 对比返回大的值
np.maximum(x,y)
输出结果:
array([-0.10488341, -1.18010624, 0.46492552, 0.58947382, -0.01015324, 2.08139131, 0.35234464, -0.82338906])
array([-1.30925346, -0.14092102, 0.56775544, 1.46416221, 0.67749745, -1.22717291, -0.50538792, 0.95247714])
array([-0.10488341, -0.14092102, 0.56775544, 1.46416221, 0.67749745, 2.08139131, 0.35234464, 0.95247714])
有些 ufunc 可以返回多个数组,但是比较少见,modf 就是一个例子,它是 Python 内置函数,它是Python内置函数 divmod 的矢量化版本,用于浮点数组的小数和整数部分。
# 得到两个数组组成的元组,一个是小数部分数据,一个是整数部分的数据
np.modf(y)
输出结果: 前面是小数部分,后面是整数部分
(array([-0.30925346, -0.14092102, 0.56775544, 0.46416221, 0.67749745, -0.22717291, -0.50538792, 0.95247714]), array([-1., -0., 0., 1., 0., -1., -0., 0.]))
根据通用函数的参数个数,可以划分为 一元ufunc 和 二元ufunc
一元 ufunc :
sqrt、cos、floor、modf
二元 ufunc :
add、maximum、mod