NumPy 基础操作
什么是 NumPy
NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。
NumPy包的核心是 ndarray 对象。它封装了python原生的同数据类型的 n 维数组(Python Array),为了保证其性能优良,其中有许多操作都是代码在本地进行编译后执行的。
基础知识
创建数组
通常,数组的元素最初是未知的,但它的大小是已知的。因此,NumPy提供了几个函数来创建具有初始占位符内容的数组。这就减少了数组增长的必要,因为数组增长的操作花费很大。默认情况下,创建的数组的dtype是 float64 类型的。
- 函数zeros创建一个由0组成的数组;
- 函数 ones创建一个完整的数组;
- 函数empty 创建一个数组,其初始内容是随机的,取决于内存的状态;
- 函数arange创建数字组成的数组,(开始值、终值、步长)
- 函数linspace创建既定数量元素的函数,(开始值、终值、元素个数)
np.zeros( (3,4) )
np.ones( (2,3,4), dtype=np.int16 )
np.empty( (2,3) )
np.arange( 0, 2, 0.3 )
from numpy import pi
x = np.linspace( 0, 2*pi, 100 )
f = np.sin(x)
基本操作
与许多矩阵语言不同,乘积运算符 * 在NumPy数组中按元素进行运算。矩阵乘积可以使用 @ 运算符(在python> = 3.5中)或dot函数或方法执行:
a = np.array( [20,30,40,50] )
b = np.arange( 4 )
c = a-b
[20 29 38 47]
A = np.array( [[1,1], [0,1]] )
B = np.array( [[2,0], [3,4]] )
A * B 是对应元素相乘
A @ B 和 A.dot(B) 矩阵乘法
许多一元操作,例如计算数组中所有元素的总和,都是作为ndarray类的方法实现的。
b = np.arange(12).reshape(3,4)
b.sum() # 针对所有行列
b.max()
b.min()
b.sum(axis=0) # sum of each column
b.min(axis=1) # min of each row
b.cumsum(axis=1) # cumulative sum along each row 每行累加
NumPy提供熟悉的数学函数,例如sin,cos和exp。在NumPy中,这些被称为“通函数”(ufunc
)。在NumPy中,这些函数在数组上按元素进行运算,产生一个数组作为输出。
>>> B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([ 1. , 2.71828183, 7.3890561 ])
>>> np.sqrt(B)
array([ 0. , 1. , 1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([ 2., 0., 6.])
索引、切片和迭代
一维的数组可以进行索引、切片和迭代操作的,就像 列表 和其他Python序列类型一样。
>>> a = np.arange(10)**3
>>> a
array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729])
>>> a[2]
8
>>> a[2:5]
array([ 8, 27, 64])
>>> a[:6:2] = -1000 # equivalent to a[0:6:2] = -1000; from start to position 6, exclusive, set every 2nd element to -1000
>>> a
array([-1000, 1, -1000, 27, -1000, 125, 216, 343, 512, 729])
>>> a[ : :-1] # reversed a
array([ 729, 512, 343, 216, 125, -1000, 27, -1000, 1, -1000])
>>> for i in a:
... print(i**(1/3.))
...
nan
1.0
nan
3.0
nan
5.0
6.0
7.0
8.0
9.0
多维的数组每个轴可以有一个索引。这些索引以逗号分隔的元组给出:
>>> def f(x,y):
... return 10*x+y
...
>>> b = np.fromfunction(f,(5,4),dtype=int)
>>> b
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
[40, 41, 42, 43]])
>>> b[2,3]
23
>>> b[0:5, 1] # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[ : ,1] # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, : ] # each column in the second and third row of b
array([[10, 11, 12, 13],
[20, 21, 22, 23]])
python 索引的基本格式
-
变量名[x]--索引为x的值
-
变量名[i,j]--索引从i到j-1的值
-
索引值(从左往右)从0开始,到N-1结束(有始无终)
-
索引值(从右往左)从-1开始,到-N结束
list2 = ['江苏','安徽','浙江','上海','山东','山西','湖南','湖北']
print(list2[-1])
湖北
print(list2[0])
江苏
print(list2[-3:-1])
['山西', '湖南']
对多维数组进行 迭代(Iterating) 是相对于第一个轴完成的:
>>> for row in b:
... print(row)
...
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]
但是,如果想要对数组中的每个元素执行操作,可以使用flat属性,该属性是数组的所有元素的迭代器:
>>> for element in b.flat:
... print(element)
...
0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33
40
41
42
43
取整方式
np.around # 四舍五入
np.floor # 向下取整
np.ceil # 向上取整
np.where # 条件选取 根据条件 condition 从 x 和 y 中选择元素,当 condition 为 True 时,选 x,否则选 y。
import numpy as np
data = np.random.random([2, 3])
print data
'''
[[ 0.93122679 0.82384876 0.28730977]
[ 0.43006042 0.73168913 0.02775572]]
'''
result = np.where(data > 0.5, data, 0)
print result
'''
[[ 0.93122679 0.82384876 0. ]
[ 0. 0.73168913 0. ]]
'''
形状操纵
改变数组的形状
使用各种命令更改数组的形状。请注意,以下三个命令都返回一个修改后的数组,但不会更改原始数组:
>>> a = np.floor(10*np.random.random((3,4)))
>>> a
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
>>> a.shape
(3, 4)
>>> a.ravel() # returns the array, flattened
array([ 2., 8., 0., 6., 4., 5., 1., 1., 8., 9., 3., 6.])
>>> a.reshape(6,2) # returns the array with a modified shape
array([[ 2., 8.],
[ 0., 6.],
[ 4., 5.],
[ 1., 1.],
[ 8., 9.],
[ 3., 6.]])
>>> a.T # returns the array, transposed 转置
array([[ 2., 4., 8.],
[ 8., 5., 9.],
[ 0., 1., 3.],
[ 6., 1., 6.]])
>>> a.T.shape
(4, 3)
>>> a.shape
(3, 4)
如果在 reshape 操作中将 size 指定为-1,则会自动计算其他的 size 大小:
>>> a.reshape(3,-1)
array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
数组堆叠
np.vstack((a,b)) # 垂直
np.hstack((a,b)) # 水平
将一个数组拆分成几个较小的数组
使用hsplit,可以沿数组的水平轴拆分数组,方法是指定要返回的形状相等的数组的数量,或者指定应该在其之后进行分割的列:
vsplit沿垂直轴分割,并array_split允许指定要分割的轴。
>>> a = np.floor(10*np.random.random((2,12)))
>>> a
array([[ 9., 5., 6., 3., 6., 8., 0., 7., 9., 7., 2., 7.],
[ 1., 4., 9., 2., 2., 1., 0., 6., 2., 2., 4., 0.]])
>>> np.hsplit(a,3) # Split a into 3
[array([[ 9., 5., 6., 3.],
[ 1., 4., 9., 2.]]), array([[ 6., 8., 0., 7.],
[ 2., 1., 0., 6.]]), array([[ 9., 7., 2., 7.],
[ 2., 2., 4., 0.]])]
>>> np.hsplit(a,(3,4)) # Split a after 3 and 4 column 3,4之间拆开
[array([[ 9., 5., 6.],
[ 1., 4., 9.]]), array([[ 3.],
[ 2.]]), array([[ 6., 8., 0., 7., 9., 7., 2., 7.],
[ 2., 1., 0., 6., 2., 2., 4., 0.]])]
拷贝和视图
当计算和操作数组时,有时会将数据复制到新数组中,有时则不会。这通常是初学者混淆的根源。有三种情况:
完全不复制
简单分配不会复制数组对象或其数据。
>>> a = np.arange(12)
>>> b = a # no new object is created
>>> b is a # a and b are two names for the same ndarray object
True
>>> b.shape = 3,4 # changes the shape of a
>>> a.shape
(3, 4)
视图或浅拷贝
view方法创建一个查看相同数据的新数组对象。
>>> c = a.view()
>>> c is a
False
>>> c.base is a # c is a view of the data owned by a
True
>>> c.flags.owndata
False
>>>
>>> c.shape = 2,6 # a's shape doesn't change
>>> a.shape
(3, 4)
>>> c[0,4] = 1234 # a's data changes
>>> a
array([[ 0, 1, 2, 3],
[1234, 5, 6, 7],
[ 8, 9, 10, 11]])
深拷贝
copy方法生成数组及其数据的完整副本。
>>> d = a.copy() # a new array object with new data is created
>>> d is a
False
>>> d.base is a # d doesn't share anything with a
False
有时,如果不再需要原始数组,则应在切片后调用 copy
。例如,假设a是一个巨大的中间结果,最终结果b只包含a的一小部分,那么在用切片构造b时应该做一个深拷贝:
>>> a = np.arange(int(1e8))
>>> b = a[:100].copy()
>>> del a # the memory of ``a`` can be released.
>>> c=np.copy(a[:10]) # 注意这种用法
如果改为使用 b = a[:100]
,则 a
由 b
引用,并且即使执行 del a
也会在内存中持久存在。
数据类型 Numpy
Numpy 的类型 | C 的类型 | 描述 |
---|---|---|
np.int8 | int8_t | 字节(-128到127) |
np.int16 | int16_t | 整数(-32768至32767) |
np.int32 | int32_t | 整数(-2147483648至2147483647) |
np.int64 | int64_t | 整数(-9223372036854775808至9223372036854775807) |
np.uint8 | uint8_t | 无符号整数(0到255) |
np.uint16 | uint16_t | 无符号整数(0到65535) |
np.uint32 | uint32_t | 无符号整数(0到4294967295) |
np.uint64 | uint64_t | 无符号整数(0到18446744073709551615) |
np.intp | intptr_t | 用于索引的整数,通常与索引相同 ssize_t |
np.uintp | uintptr_t | 整数大到足以容纳指针 |
np.float32 | float | |
np.float64 / np.float_ | double | 请注意,这与内置python float的精度相匹配。 |
np.complex64 | float complex | 复数,由两个32位浮点数(实数和虚数组件)表示 |
np.complex128 / np.complex_ | double complex | 请注意,这与内置python 复合体的精度相匹配。 |
有5种基本数字类型表示布尔值(bool),整数(int),无符号整数(uint)浮点(浮点数)和复数。
溢出错误
当值需要比数据类型中的可用内存更多的内存时,NumPy数值类型的固定大小可能会导致溢出错误。例如,numpy.power对于64位整数正确计算 100 * 10 * 8,但对于32位整数给出1874919424(不正确)。
>>> np.power(100, 8, dtype=np.int64)
10000000000000000
>>> np.power(100, 8, dtype=np.int32)
1874919424
如果64位整数仍然太小,则结果可能会转换为浮点数。浮点数提供了更大但不精确的可能值范围。
>>> np.power(100, 100, dtype=np.int64) # Incorrect even with 64-bit int
0
>>> np.power(100, 100, dtype=np.float64)
1e+200
网友评论