前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >快速上手Numpy模块

快速上手Numpy模块

作者头像
触摸壹缕阳光
发布2020-05-13 14:27:01
1.5K0
发布2020-05-13 14:27:01
举报

全文字数:10146字

阅读时间:25分钟

前言

我们都知道在Python中有一个list的数据类型,list拥有强大的功能,它是元素的集合并且它里面的元素可以是任何Python数据类型,list可以很方便的对它里面的元素进行增删改查的操作。但是对于科学计算来说需要满足下面两点:

  1. 能直接对集合进行数学操作;
  2. 运算速度要快,对于机器学习来说需要进行科学计算的数据量可能很大;
代码语言:javascript
复制
heigh = [1.74,1.68,1.71]
weight = [65.4,59.2,63.6]

ibm = heigh/weight**2
print(ibm)

Traceback (most recent call last):
  File "G:/Python源码/numpy_test/numpy_test.py", line 58, in <module>
    ibm = heigh/weight**2
TypeError: unsupported operand type(s) for ** or pow(): 'list' and 'int'

从上面的代码可以看出: list并不能直接对整个集合进行数学的相关操作,因为list中的元素可以是任意类型,如果进行数学运算的话list不知道元素的数据类型。

我们的解决方案就是我们的NumPy模块。NumPy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。由于NumPy提供了一个简单易用的C API,因此很容易将数据传递给低级语言编写的外部库,外部库也能以NumPy数组的形式将数据返回给Python。这个功能使Python成为一种包装C/C++/Fortran历史代码库的选择,并使被包装库拥有一个动态的、易用的接口。numpy数组是Python中list数据类型的一个替代品,它能够对整个数组(集合)进行数学的操作。

代码语言:javascript
复制
import numpy as np
np_heigh = np.array([1.74,1.68,1.71])
np_weight = np.array([65.4,59.2,63.6])

ibm = np_heigh/np_weight**2
print(ibm)

[ 0.00040681  0.00047936  0.00042275]

从上面代码可以看出: 我们可以很轻松的对numpy ndarray进行集合的数学操作。

我们说完了对于科学计算很重要的能直接对集合进行数学操作。那速度是如何体现出来的呢?

代码语言:javascript
复制
#在list中
list = [1.0,'is',True]
print(list)

[1.0, 'is', True]

#在numpy中
import numpy as np
np_a = np.array([1.0,'is',True])
print(np_a)

['1.0' 'is' 'True']

从上面代码可以看出:

  1. 对于list来说里面的元素可以是任意Python数据类型,而numpy array中的元素必须是一致的,如果我们定义的数据类型不一致的话,就会自动帮我们转换成一致的数据类型。
  2. 如果对NumPy中的元素进行操作的话,因为他里面都是相同类型的数据类型,速度一定比对list操作要快的很多。如果对list中的元素进行操作的话,使用loop结构,效率就不会很高的。

a

Numpy的ndarray:一种多维数组对象

我们从上面了解到,我们使用array函数创建的对象都是ndarray,其实这也是NumPy的最重要的一个特点N维数组对象,这个对象是一个快速而灵活的大数据集容器。我们通过上面对集合进行数学运算时候也看到了,我们可以利用ndarray这种数组对整块的数据执行一些数学运算。当然他的语法和标量元素之间的运算是一样的。

还有一点我们上面也提到了,就是ndarray是一个通用的同构数据多维容器,也就是说,其中所有元素必须是相同类型的(与Python中的list很明显的区别)

b

Numpy数组可以表示的类型

你肯定会说这里又是数组有是ndarray对象的,他们有什么区别呢?其实我们可以认为他们是等同的。我们从上面知道了对于list数据类型的替代品numpy ndarray。其实ndarray就是n维的一个array,我们可以通过numpy的array函数来创建一个ndarray对象。ndarray可以有任意数量的维度。由于他可以存储任意数量的维度,所以我们可以使用ndarray来表示我们所熟知的任意数据的类型。下面我就详细的介绍用numpy ndarray来表示标量、向量、矩阵以及张量。

当然在介绍能表示的数据之前,我们需要先了解ndarray对象的shape属性以及说明数组数据类型的dtype对象(说白了就是数组中元素的类型)。shape他返回的是一个表示各个维度大小的元组,当然如果想要改变形状,可以使用ndarray.shape = 元组进行更改,也可以使用asshape函数。dtype说明数组数据类型的对象,由于我们上面说过,我们的数组是一个通用的数据多维容器,所以他里面的元素的类型都是一样的,也就是说对于我们每个数组来说,他的dtype只有一个。

代码语言:javascript
复制
import numpy as np
array = np.array([1,2,3])
print(array)
print(array.shape)
print(array.dtype)
print(type(array))

[1,2,3]
(3,)
int32
<class 'numpy.ndarray'>
  • 标量

我们都知道在Python中有int、float、string...这些基本的数据类型,所以能表示的标量可以是整数、浮点数以及字符...类型。但在NumPy中他能表示的标量的类型比Python所能表示的还要多。NumPy 可以让你指定有符号和无符号的类型以及不同的大小。因此,你可以使用 uint8、int8、uint16、int16、uint32、int32、uint64、int64、float8、float16、float32、float64等类型,后面的8、16、32以及64是代表位数。后面讲dtype时候在详细的讲解他们的类型。

  • 位数越大,精确度就越高,但是占用的空间就会越大
  • 位数越小,精确度就越低,但是占用的空间就会越小
代码语言:javascript
复制
import numpy as np
scalar = np.array(5)
print(scalar)
print(scalar.dtype)
print(scalar.shape)
print(type(scalar))
print("---------------")

scalar = scalar + 15
print(scalar)
print(scalar.dtype)
print(scalar.shape)
print(type(scalar))

5
int32
()
<class 'numpy.ndarray'>
---------------
20
int32
()
<class 'numpy.int32'>

从上面的代码可以看出:

  1. NumPy中的标量不论是与Python中的标量还是Python中的标量都是可以直接进行运算的。
  2. 使用array函数创建ndarray对象,但是他如果和标量(无论是Python中还是numpy中的标量)运算。他的结果都会是numpy.变量数据类型的对象。而不会再是ndarray对象。
  3. 我们打印标量的形状,打印输出一个()。我们从上面知道,调用shape属性,返回的是一个表示维度的一个元组。那么在标量中调用shape我们可以看出他返回的是一个()。这个()在Python中表示的是一个tuple对象。()这表示它的维度为零,是标量。
  • 向量(Vectors)
代码语言:javascript
复制
import numpy as np
vector = np.array([1,2,3,4,5])
print(vector)
print(vector.dtype)
print(type(vector))
print(vector.shape)

[1 2 3 4 5]
int32
<class 'numpy.ndarray'>
(5,)

从上面的代码可以看出:

  1. 我们可以看出返回的结果是(5,)元组,因为向量只有一个维度,所以元组中仅仅包含了一个数字和一个逗号。
  2. 我们看标量的形状为(),为什么不是(5)这样表示呢?我们的shape总是返回元组。因为在Python中如果(5)他并不能理解成仅有一项的元组,所以有了逗号,就能识别他是一个元组了。
代码语言:javascript
复制
a = (5)
print(a)
print(type(a))
print("----------")

b = (5,)
print(b)
print(type(b))

5
<class 'int'>
----------
(5,)
<class 'tuple'>
  • 矩阵(Matrices)
代码语言:javascript
复制
import numpy as np
matrices = np.array([[1,2,3],
                     [4,5,6],
                     [7,8,9]])
print(matrices)
print(matrices.dtype)
print(matrices.shape)
print(type(matrices))

[[1 2 3]
 [4 5 6]
 [7 8 9]]
int32
(3,3)
<class 'numpy.ndarray'>

c

创建数组(ndarray)

上面的代码使用了创建数组最简单的函数array。他接受一切的序列型的对象(序列型的对象可以是list,tuple...其他序列类型,当然这个函数参数也可以是另一个ndarray)。我们使用list序列对象作为array函数的参数为例:

代码语言:javascript
复制
import numpy as np
array = np.array([1,2,3])
print(array)
print(array.dtype)

[1 2 3]
int32

从上面代码可以看出: 我这里并没有给数组中的元素指定一个类型值,但是我的np.array会尝试为新建的这个数组推断出一个较为合适的数据类型本例中是int32。数据类型保存在一个特殊的dtype对象中。

当然也就是说数组中的元素类型不一致,并且我们没有进行显示的给dtype参数赋值的话(当然我们可以在创建ndarray对象的时候给dtype赋值指定数据类型),np.array就会尝试为新建的这个数组推断出一个较为合适的数据类型。数据类型保存在一个特殊dtype对象。一会我们会单独拿出一个部分来说这个dtype对象。

▲创建数组的相关函数

代码语言:javascript
复制
#使用array函数,参数为序列类型
#这里尤为要说明的是他的参数可以是另一个数组(ndarray)
import numpy as np
array = np.array([1,2,3])
array2 = np.array(array)#这里我的array函数参数是ndarray

print(array)
print(array2)
print("----------")
print(type(array))
print(type(array2))
print("----------")
#is判断的是a对象是否就是b对象,是通过id来判断的
print(array is array2)

[1 2 3]
[1 2 3]
----------
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
----------
False

从上面代码可以看出: 我们使用is关键字来查看是否为同一个对象,我们可以看出array和array2是不同的对象,也就是说,当我们使用一个ndarray对象作为array函数的参数的时候得到的另一个ndarray对象的时候,这另一个数组是对参数中数组的一个copy。直白点说就是他们占用不同的内存相互之间没有任何关系。

代码语言:javascript
复制
#使用asarray,其实这个函数和array函数的功能一样
#但是有一点不一样:如果参数是另一个数组(ndarray)
#   1.array函数,创建的另一个对象不是同一个
#   2.asarray函数,创建的另一个对象是同一个
import numpy as np
array = np.asarray([1,2,3])
array2 = np.asarray(array)

print(array)
print(array2)
print("----------")
print(type(array))
print(type(array2))
print("----------")
#is判断的是a对象是否就是b对象,是通过id来判断的
print(array is array2)

[1 2 3]
[1 2 3]
----------
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
----------
True

从上面代码可以看出: 我们可以看出如果对于asarray函数来说参数不是ndarray的话,与array函数没有什么区别,但是如果是ndarray的话,通过asarray不进行复制,也就是他返回的是同一个对象。也就是通过is关键字,返回的结果是True。直白点说就是他们共享同一块内存空间。

代码语言:javascript
复制
import numpy as np
#这里arange函数用的还是比较多的,所以单拿出来
#np.arange(start,end,step)
array = np.arange(4)
print(array)
[0 1 2 3]

array2 = np.arange(1,10,2)
print(array2)
[1 3 5 7 9]

#如果我想通过arange生成矩阵,怎么办呢?
#注意这里生成的行*列一定要等于生成元素的个数
#如果不满足行*列等于元素个数
#会抛出ValueError: total size of new array must be unchanged
array3 = np.arange(1,10,2).reshape((5,1))
print(array3)
[[1]
 [3]
 [5]
 [7]
 [9]]

#这里因为函数中的参数start>end,并且没有指定步长step
#所以输出结果为[]
array4 = np.arange(14,2)
print(array4)
[]

#这里虽然指定了步长,但是步长为>0的一个正数,
#所以这里输出结果也会是[]
array5 = np.arange(14,2,2)#这里的步长>0(用于测试)
print(array5)
[]

array6 = np.arange(14,2,-1)#这里的步长<0(用于测试)
print(array6)

[14 13 12 11 10  9  8  7  6  5  4  3]
代码语言:javascript
复制
import numpy as np
array = np.ones(4)
array2 = np.ones((4,))#
array3 = np.ones((4,4))
#参数是数组或者序列类型,
#返回的根据参数的形状和dtype创建一个为1的数组
array4 = np.ones_like([1,2,3])
array5 = np.ones_like([[1,2,3],
                       [4,5,6]])

print(array)
print(array2)
print(array3)
print("----------")
print(array4)
print(array5)
print("----------")
print(array.dtype)
print(array2.dtype)
print(array3.dtype)

[ 1.  1.  1.  1.]
[ 1.  1.  1.  1.]
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
----------
[1 1 1]
[[1 1 1]
 [1 1 1]]
----------
float64
float64
float64
代码语言:javascript
复制
import numpy as np
array = np.zeros(4)
array2 = np.zeros((4,))#
array3 = np.zeros((4,4))
#参数是数组或者序列类型,
#返回的根据参数的形状和dtype创建一个为1的数组
array4 = np.zeros_like([1,2,3])
array5 = np.zeros_like([[1,2,3],
                       [4,5,6]])

print(array)
print(array2)
print(array3)
print("----------")
print(array4)
print(array5)
print("----------")
print(array.dtype)
print(array2.dtype)
print(array3.dtype)

[ 0.  0.  0.  0.]
[ 0.  0.  0.  0.]
[[ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]
 [ 0.  0.  0.  0.]]
----------
[0 0 0]
[[0 0 0]
 [0 0 0]]
----------
float64
float64
float64
代码语言:javascript
复制
import numpy as np
array = np.empty(4)
array2 = np.empty((4,))#
array3 = np.empty((4,4))
#参数是数组或者序列类型,
#返回的根据参数的形状和dtype创建一个为1的数组
array4 = np.empty_like([1,2,3])
array5 = np.empty_like([[1,2,3],
                       [4,5,6]])

print(array)
print(array2)
print(array3)
print("----------")
print(array4)
print(array5)
print("----------")
print(array.dtype)
print(array2.dtype)
print(array3.dtype)

[  9.90263869e+067   8.01304531e+262   2.60799828e-310   9.48818959e+077]
[  9.90263869e+067   8.01304531e+262   2.60799828e-310   1.57027689e-312]
[[  6.23042070e-307   1.89146896e-307   1.37961302e-306   1.05699242e-307]
 [  8.01097889e-307   1.78020169e-306   7.56601165e-307   1.02359984e-306]
 [  1.33510679e-306   2.22522597e-306   1.24611674e-306   1.29061821e-306]
 [  6.23057349e-307   1.86920193e-306   9.34608432e-307   2.56765117e-312]]
----------
[0 0 0]
[[0 0 0]
 [0 0 0]]
----------
float64
float64
float64

从上面代码可以看出:

  1. np.empty会返回全0数组的想法是不安全的。很多情况下他返回的都是一些未初始化的垃圾值。
  2. 我们从上面可以看出我们创建数组的时候,调用dtype的时候返回的都是float64,这是因为NumPy关注的是数值的计算,所以在NumPy中如果没有特别的指定,数据类型基本上都是float64(浮点数)。
代码语言:javascript
复制
import numpy as np
array = np.eye(4)
array2 = np.identity(4)

print(array)
print(array2)

[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]
[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0.  1.]]

从上面代码可以看出: 就目前来看他们的效果都是一样的,参数都是一个整数,然后创建的是一个方阵。

代码语言:javascript
复制
linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
在指定的间隔内返回均匀间隔的数字。
返回num均匀分布的样本,在[start, stop]。
Parament:
start:序列的起点
stop:序列的结束点,除非endpoint被设置为False,stop被排除
num:int, optional(可选)
生成的样本数,默认是50。必须是非负。
endpoint:如果是真,则一定包括stop,如果为False,一定不会有stop
retstep : bool, optional
If True, return (samples, step), where step is the spacing between samples.(array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]), 1.0)
dtype : dtype, optional
输出数组的类型。如果没有给出,从其他输入参数的数据类型推断

代码语言:javascript
复制
logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):
在指定的间隔内返回等比数列。
Parament:
start:序列的起点
stop:序列的结束点,除非endpoint被设置为False,stop被排除
num:int, optional(可选)
生成的样本数,默认是50。必须是非负。
endpoint:如果是真,则一定包括stop,如果为False,一定不会有stop
base:这里是指数的底数,默认是10,也就是说是  ,可以改成2
dtype : dtype, optional
输出数组的类型。如果没有给出,从其他输入参数的数据类型推断

d

ndarray的数据类型

其实如果直白的说,ndarray的数据类型就是我们创建数组时候的各个元素的数据类型,由于ndarray是一个通用的同构数据多维容器,所以每个ndarray对象有唯一的一个dtype值。当然这里的数据类型都是NumPy中的类型。

dtype(数据类型)是一个特殊的对象,他含有ndarray将一块内存解释为特定数据类型所需的信息。dtype是NumPy如此强大和灵活的原因之一。多数情况下,他们直接映射到相应的机器表示,这使得"读写磁盘上的二进制数据流"以及"集成低级语言代码(如C)"等工作变得更加的简单。标准的双精度浮点值(即Python中的float对象)需要占用8个字节(即64位)。因此,该类型在NumPy中就记作float64。

▲Numpy的数据类型

我们在创建数组的时候可以显式的指定dtype,同时我们也可以不进行指定,他会为新的数组推断出一个合适的数据类型。那么如果我们后期需要再对数组中的数据类型进行转换的话,那怎么办呢?这个时候我们可以通过ndarray数组对象的astype方法显示的转换为其他的dtype。

代码语言:javascript
复制
import numpy as np
#显示的指定dtype
array = np.array([1,2,3],dtype = np.float64)
#隐式的指定dtype
array2 = np.array(['1','2','3'])

print(array.dtype)
print(array2.dtype)
print("----------")
array3 = array2.astype(np.float64)
print(array2.dtype)
print(array3.dtype)

float64
<U1
----------
<U1
float64

我们从上面的(NumPy的数据类型)表格看到了有一个列叫做类型代码,我们其实可以不使用np.数据类型来指定类型,也可以使用对应参数的类型代码来简洁的表示。但是对于数据类型这么多的NumPy,个人建议还是不要使用类型代码这种方式。

代码语言:javascript
复制
import numpy as np
array = np.array([1,2,3],dtype= 'S')

print(array)
print(array.dtype)

[b'1' b'2' b'3']
|S1

这里需要进行三点说明的是:

  1. 如果转换失败的话,比如说某一个字符串类型的数据不能转换成整数类型,就会抛出ValueError的异常;
  2. 如果不指定np.float64,直接将参数写成float,也是可以的,因为NumPy很聪明,他会将Python类型映射到等价的dtype中去;
  3. 其实我们调用astype方法,返回的是一个新的数组,也就是对原始数据的一个完整拷贝,(当然即使astype中的类型与原始数组中的dtype相同,也会返回一个新的数组)。
代码语言:javascript
复制
import numpy as np
array = np.array(['h',1,2],dtype = np.float64)

print(array)

Traceback (most recent call last):
  File "G:/Python源码/numpy_test/numpy_test.py", line 639, in <module>
    array = np.array(['h',1,2],dtype = np.float64)
ValueError: could not convert string to float: 'h'
代码语言:javascript
复制
import numpy as np
array = np.array([1,2,3])
array2 = array.astype(float)

print(array.dtype)
print(array2.dtype)

int32
float64
代码语言:javascript
复制
import numpy as np
array = np.array([1.1,2.3,4,7.8],dtype = np.float64)
array2 = array.astype(np.int64)

print(array)
print(array2)
print("-----打印类型-----")
print(array.dtype)
print(array2.dtype)
print("-----判断是否为同一个对象-----")
array2[0] = 10000
print(array)
print(array2)

[ 1.1  2.3  4.   7.8]
[1 2 4 7]
-----打印类型-----
float64
int64
-----判断是否为同一个对象-----
[ 1.1  2.3  4.   7.8]
[10000     2     4     7]

总结(是否是对源数据的拷贝):

▲总结

e

Numpy数组索引

  • 基本的索引和切片

NumPy数组的索引是一个内容丰富的主题,因为选取数据子集或者是单个元素的方式有很多。对于一维数组来说,他和Python中的list的功能差不太多。

代码语言:javascript
复制
#对于一维数组来说
import numpy as np
array = np.arange(8)

print(array)
print("-----选取单个元素-----")
print(array[3])
print(array[-1])
print("-----选取数据子集-----")
print(array[0:5])
print(array[1:-2])

[0 1 2 3 4 5 6 7]
-----选取单个元素-----
3
7
-----选取数据子集-----
[0 1 2 3 4]
[1 2 3 4 5]

这里要多说几句:

  1. 对于一维数组来说,我们可以认为是与list操作相一致的。我们可以直接通过正负索引来获取单个元素,也可以通过切片来获取一维数组的一个片段,切片的时候都是包左不包右的。
  2. 数组的切片是原始数组的视图,也就是说数据没有被复制,视图上的任何修改都会直接反应到源数组上。(当然这个时候不能使用is关键字来判断是否为同一个对象了),这是 因为NumPy的设计目的是处理大数据,所以你可以想象一下,如果NumPy坚持要将数据复制来复制去的话会产生何等性能和内存问题。当然如果想要拷贝副本的话可以显式的调用copy方法。
  3. 切片也是有步长的你可以指定[1:5:2],这里面的2就是切片的步长。如果特殊点步长为-1也就是[::-1],即我的数组就会反转。
  4. 这里的切片都是从0位置开始的。
  5. 我们从上面可以看出,无论是索引单个元素还是进行切片,我们都可以为其传入一个负值,从数组的后面进行索引。

▲数组索引

代码语言:javascript
复制
import numpy as np
array = np.array([1,2,3,4,5,6,7])
array2 = array[1:]

print("-----原始的数据-----")
print(array)
print(array2)
print("-----更改后的数据-----")
array2[0] = 10000
print(array)
print(array2)

-----原始的数据-----
[1 2 3 4 5 6 7]
[2 3 4 5 6 7]
-----更改后的数据-----
[    1 10000     3     4     5     6     7]
[10000     3     4     5     6     7]

那对于高维数组来说,能做的事情就更多了。在一个二维数组中,各索引位置上的元素不再是标量而是一维数组。

代码语言:javascript
复制
import numpy as np
array = np.arange(1,13).reshape((4,3))
print(array)
print("-----获取单个元素的两种方式-----")
print(array[0][1])
print(array[0,1])
print(array[-1][2])
print(array[-1,2])
print("-----对多维数组进行切片-----")
#因为这里只是一个矩阵,所以有两个轴,也就是说能指定两个位置
print(array[:2])#只有一个值,也就是只有第一个轴的方向,也就是axis=0
print(array[:2,:1])

[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
-----获取单个元素的两种方式-----
2
2
12
12
-----对多维数组进行切片-----
[[1 2 3]
 [4 5 6]]
[[1]
 [4]]

▲二维数组的展示图

  • 布尔型索引

布尔型索引是NumPy特有的功能,他的功能非常的强大。并且应用的场景也非常的多。比如:下表是几个学生的一年中期末期中的语数英三科的考试成绩:

▲三个同学的期中期末成绩

先初始化我们的数据:

代码语言:javascript
复制
import numpy as np
names_array = np.array(['KC','XC','XC','LC','LC','KC'],dtype = np.string_)
grades_array = np.array([[80,98,78],
                         [66,80,77],
                         [68,88,90],
                         [77,61,70],
                         [70,65,80],
                         [82,70,80]],dtype = np.int32)

我们要选出"KC"这名学生的期中期末的成绩:

代码语言:javascript
复制
names_array2 = (names_array == 'KC')

print("-----筛选满足条件的行-----")
print(names_array is names_array2)
print(names_array2)
print("-----进行筛选-----")
print(grades_array[names_array2])

-----筛选满足条件的行-----
False
[ True False False False False  True]
-----进行筛选-----
[[80 98 78]
 [82 70 80]]

这里注意:

  1. 布尔型数组的长度必须和被索引的轴长度一致,就本例而言,是一个二维数组,所以他有两个轴,所以我们默认传入的是一个默认会是第一个轴,也就是行数,所以就本例而言我们的布尔型数组要和我们数据数组的行数相同才可以。

那如果我们要获取除了'KC'这位同学的其他同学的成绩:

代码语言:javascript
复制
print(names_array == 'KC')
print("-----方式一-----")
print(names_array != 'KC')
print("-----方式二-----")
print(-(names_array == 'KC'))

[ True False False False False  True]
-----方式一-----
[False  True  True  True  True False]
-----方式二-----
[False  True  True  True  True False]

当然我们操作还不仅仅是这些,我们还可以组合应用多个布尔条件,使用&(和)、|(或)之类的布尔算术运算符即可(当然这里要注意了,我们不能使用Python中的and和or关键字):

代码语言:javascript
复制
print("-----获取'KC'或者'LC'同学的成绩-----")
print((names_array == 'KC') | (names_array == 'LC'))
print(grades_array[(names_array == 'KC') | (names_array == 'LC')])

-----获取'KC'或者'LC'同学的成绩-----
[ True False False  True  True  True]
[[80 98 78]
 [77 61 70]
 [70 65 80]
 [82 70 80]]

当然因为我们是二维的一个数组,所以我们对应的是两个轴,那我们还可以对列进行筛选,这里其实很灵活的,我们可以使用一个标量来获取整个列,也可以传入一个分片来获取部分列,当然我们对于列的筛选也可以布尔型的索引:

代码语言:javascript
复制
print("-----获取'KC'同学的数学成绩-----")
print(grades_array[(names_array == 'KC'),1])
print(grades_array[names_array == 'KC'][grades_array[names_array == 'KC'] >= 80])

-----获取'KC'同学的数学成绩-----
[98 70]
[80 98 82 80]
  • 花式索引

花式索引(Fancy indexing)是一个NumPy术语,他指的是利用整数数组进行索引。下面是对于二维数组的例子:

代码语言:javascript
复制
import numpy as np
array = np.arange(32).reshape((8,4))
print(array)
print("-----获取第一行和第三行-----")
print(array[[0,2]])
print("-----获取最后两行-----")
print(array[[-1,-2]])
print("-----获取元素值-----")
print(array[[0,2],[0,1]])
print(array[[0,2]][:,[0,1]])
print(array[np.ix_([0,2],[0,1])])

[[ 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]]
-----获取第一行和第三行-----
[[ 0  1  2  3]
 [ 8  9 10 11]]
-----获取最后两行-----
[[28 29 30 31]
 [24 25 26 27]]
-----获取元素值-----
[0 9]
[[0 1]
 [8 9]]
[[0 1]
 [8 9]]

这里要注意的是:

  1. 其实这传入的是一个用于指定顺序的整数列表或者是ndarray就行。这里其实要注意的是花式索引和切片索引还是与很大的区别的:切片索引得到的是同一个源数组的视图,所以无论修改哪个数组其实都是对同一个数组进行操作。但是花式索引就不一样了,他是复制一个源数组。
  2. array[[0,2]][:,[0,1]]这里可能不好理解,但是我们把他拆开来看,array[[0,2]]来获取第1行和第3行的返回的是一个两行的数组,然后在去[:,[0,1]]这里我们的行是:全选,而列只选了第一列和第二列两列。
  3. 使用np.ix_函数,他可以将两个一维整数数组转换为一个用于选取正方形区域的索引器。

总结(是否是对源数据的拷贝):

▲总结

这里所说的源数据的视图说的就是如果我们修改其中一个数组,另一个源数组也会发生变化,他们操作的对象是同一个。当然如果不是的话就是说明我们在操作的时候又重新创建了一个新的数组,这个数组是对源数组的一个拷贝,这个时候去任何一个数组都不会对另一个数组产生影响。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI机器学习与深度学习算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档