numpy 入门练习

NumPy 是一个 Python 包。 它代表 “Numeric Python”。 它是一个由多维数组对象和用于处理数组的例程集合组成的库。

数据类型 ndarray

  • 全称 N-dimensiona array, N维数组, ndarray 是一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数据.
  • ndarray 是一种由相同元素组成的多维数组,元素数量是事先指定好的
  • 元素的类型由 dtype 对象来指定,每个 ndarray 只有一种 dtype 类型
  • 大小固定,创建好数组时一旦指定好大小,就不会再发生改变

``

ndarray 属性

  • ndim: 维度数量
  • shape: 数组的形状, 是一个表示各维度大小的元组
  • dtype: 表示数组元素类型的对象
  • size: 数组中元素的总个数,是 shape 中各维度数量相乘得到的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 约定俗成的引用方法是 import numpy as np
import numpy as np

arr = np.array([
[
[1, 2, 4, 9],
[2, 5, 6, 8],
],
[
[4, 2, 7, 1],
[9, 5, 6, 5],
],
[
[3, 9, 6, 9],
[2, 7, 2, 8],
]
])

arr.ndim # 3
arr.dtype # dtype('int64')
arr.shape # (3, 2, 4), 表示第一层中括号下有 3 个元素.第二层中括号下有 2 个元素,第三层中括号下有 4 个元素
arr.size # 24

ndarray 常见的创建方式

array 函数

接收一个普通的 python 序列, 转成 ndarray

1
2
arr = np.array([1, 2, 3, 4])
arr = np.array((1, 2, 3, 4))

zeros 函数

创建指定长度或形状的全零数组

1
2
3
4
5
arr = np.zeros((3, 4))
# 创建的数组如下,zeros 的参数其实就是要创建的数组的 shape 值,
# array([[0., 0., 0., 0.],
# [0., 0., 0., 0.],
# [0., 0., 0., 0.]])

ones 函数

创建指定长度或形状的全 1 数组

1
2
3
4
5
arr = np.ones((3, 4))

# array([[1., 1., 1., 1.],
# [1., 1., 1., 1.],
# [1., 1., 1., 1.]])

empty 函数

创建一个没有任何具体值的数组, 所以创建速度会比 zeros 和 ones 快, 但这种方式需要手动指定所有值,慎用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在测试中发现一个有趣的现象,如果在 empty() 中指定的 shape 在之前已经被 zeros 或 ones 指定过,然么 empty 会直接使用 zeros 或 ones 的值

arr = np.empty((2, 2))

# array([[4.9e-324, 9.9e-324],
# [1.5e-323, 2.0e-323]])

arr = np.ones((2, 2))
# array([[1., 1.],
# [1., 1.]])

arr = np.empty((2, 2))
# array([[1., 1.],
# [1., 1.]])

arange 函数

类似于 python 中的 range 函数,通过指定开始值,终值和步长来创建一维数组,注意不包括终值

1
2
3
4
5
6
7
8
9
10
11
12
arr = np.arange(6)
# array([0, 1, 2, 3, 4, 5])

# 同 python 的 range 类似, 第三个参数是步长
arr = np.arange(0, 7, 2)
# array([0, 2, 4, 6])

# 可以使用 reshape 把一维数组转为多维
arr = np.arange(12).reshape(3, 4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

linespace 函数

通过指定开始值,终值和元素个数来创建一维数组(等差数列),可以通过 endpoint 关键字指定是否包括终值, 默认包括

1
2
3
# 第三个参数表示元素个数
arr = np.linspace(0, 10, 5)
# array([ 0. , 2.5, 5. , 7.5, 10. ])

logspace 函数

和 linespace 类似,不过它创建等比数列

1
2
arr = np.logspace(0, 2, 3)
# array([ 1., 10., 100.])

random() 函数生成数组

1
2
3
arr = np.random.random((2, 2))
# array([[0.34659492, 0.83549888],
# [0.83618173, 0.0771643 ]])

改变 ndarray 的形状的

1. 直接修改 ndarray 的 shape 值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
arr = np.arange(10)  
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr.shape # (10,)
arr.shape = 2, 5
arr
# array([[0, 1, 2, 3, 4],
# [5, 6, 7, 8, 9]])

arr.shape = -1, 2
arr
# array([[0, 1],
# [2, 3],
# [4, 5],
# [6, 7],
# [8, 9]])
2. 使用 reshape 函数
1
2
3
4
5
6
7
8
arr = np.arange(9)
# array([0, 1, 2, 3, 4, 5, 6, 7, 8])
arr.shape # (9,)
arr.reshape(3, 3)
arr
# array([[0, 1, 2],
# [3, 4, 5],
# [6, 7, 8]])

注意: 当指定新数组某个轴的元素为 -1 时, 将根据数组元素的个数自动计算此轴的长度

numpy 中的数据类型

创建 ndarray 数据时,可以通过 dtype 属性显示指定数据类型, 如果不指定, numpy 会自动推断出合适的数据类型,所以一般无需显示指定

astype 方法,可以转换数组的元素数据类型, 得到一个新数组

数据类型 类型代码 说明
int_ 默认整型 (与 C 中的 long 相同, 通常为 int64 或 int32)
intc 完全等同于 C 中的 long (通常为 int64 或者 int32)
intp 表示索引的整型, 与 C 中的 size_t 相同, 通常为 int64 或者 int32
int8 i1 字节(-128 ~ 127), 1个字节
int16 i2 整型(-32768 ~ 32767). 2个字节
int32 i4 整型 (-2147483648 ~ 2147483647), 4个字节
int64 i8 整型 (-9223372036854775808 ~ 9223372036854775807), 8个字节
uint8 u1 无符号整型 (0 ~ 255)
uint16 u2 无符号整型 (0 ~ 65535)
uint32 u4 无符号整型 (0 ~ 4294967295)
unint64 u8 无符号整型 (0 ~ 18446744073709551615)
float_ float64 的简写形式
float16 f2 半精度浮点型: 符号位, 5 位指数, 10 位小数部分
float32 f4 或者 f 单精度浮点数:32位,符号位, 8 位指数, 23 位小数部分
float64 f8 或者 d 双精度浮点数:64位,符号位, 11 位指数, 52 位小数部分
float128 f16 或者 g 扩展精度浮点数
complex_ c16 complex128 的简写形式
complex64 c8 复数,由两个 32 位的浮点数来表示(实数部分和虚数部分)
complex128 c16 复数,由两个 64 位的浮点数来表示(实数部分和虚数部分)
bool_ 以一个字节形式存储的布尔值(True / False)
bool ? 存储 True 和 False 值的布尔类型
object O python 对象类型
String_ S 固定长度的字符串类型(每个字符1个字节) eg.创建一个长度为 8 的字符串使用 S8
Unicode_ U 固定长度的 unicode 类型(字节数由平台决定), 跟字符串的定义方式一样, eg U8
1
2
3
4
5
6
7
8
9
10
arr = np.array(["python", "scala", "javascript", "lua"])
arr.dtype # dtype('<U10')
arr = np.array(["python", "scala", "javascript", "lua"], dtype='S6')
# array([b'python', b'scala', b'javasc', b'lua'], dtype='|S6') 注意有元素被截断
arr.dtype # dtype('S6')

## 在需要指定类型的时候,推荐使用 np 对象内提供的类型

arr = np.array(["python", "scala", "javascript", "lua"], dtype=np.string_)
# array([b'python', b'scala', b'javascript', b'lua'], dtype='|S10')

numpy 基本操作

数组与标量, 数组之间的运算

  • 数组不用循环即可对每个元素执行批量运算,这通常就叫做矢量化,即用数组表达式代替循环的做法
  • 矢量化数组运算性能要比纯 python 方式快一两个数量级
  • 大小相等的数组之间的任何算术运算都会将运算应用到元素级
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
32
33
34
35
36
37
38
39
40
import numpy as np
## 数组与标量之间的运算
arr = np.arange(1, 6)
# array([1, 2, 3, 4, 5])

arr + 2
# array([3, 4, 5, 6, 7])

arr - 2
# array([-1, 0, 1, 2, 3])

arr * 2
# array([ 2, 4, 6, 8, 10])

arr / 2
# array([0.5, 1. , 1.5, 2. , 2.5])

arr ** 2
# array([ 1, 4, 9, 16, 25])

## shape 相同的数组之间的运算
arr1 = np.arange(4).reshape(2, 2)
# array([[0, 1],
# [2, 3]])

arr2 = np.arange(1, 5).reshape(2, 2)
# array([[1, 2],
# [3, 4]])

arr1 + arr2
# array([[1, 3],
# [5, 7]])

arr1 * arr2
# array([[ 0, 2],
# [ 6, 12]])

arr1 / arr2
# array([[0. , 0.5 ],
# [0.66666667, 0.75 ]])

数组的矩阵积(matrix product)

  • 两个多为矩阵(通常是二维)满足第一个矩阵的列数与第二个矩阵的行数相同,那么可以进行矩阵乘法
  • 两个矩阵相乘结果所得到的数据中每个元素为,第一个矩阵中与该元素行号相同的元素与第二个矩阵中与该元素列号相同的元素,两两相乘后的求和

eg. 假设有一下两张表格,要求计算每个部门购买产品的总价格和总占用空间

\ 产品A 产品B 产品C
部门1 2 4 6
部门2 1 3 5
部门3 2 3 4
\ 单价 单件体积
产品A 6 5
产品B 4 3
产品C 2 1

分别计算每个部分的用花费和总体积:

部门1 总花费: 2 x 6 + 4 x 4 + 6 x 2 = 40 总体积: 2 x 5 + 4 x 3 + 6 x 1 = 28
部门2 总花费: 1 x 6 + 3 x 4 + 5 x 2 = 28 总体积: 1 x 5 + 3 x 3 + 5 x 1 = 19
部门3 总花费: 2 x 6 + 3 x 4 + 4 x 2 = 32 总体积: 2 x 5 + 3 x 3 + 4 x 1 = 23

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 用 numpy 的矩阵积计算

arr1 = np.array([
[2, 4, 6],
[1, 3, 5],
[2, 3, 4]
])
arr2 = np.array([
[6, 5],
[4, 3],
[2, 1]
])

# 直接就可以计算出满足需求的结果
res = np.dot(arr1, arr2)
# array([[40, 28],
# [28, 19],
# [32, 23]])

数组的索引与切片

多维数组的索引

对于二维数组的索引如表中所示,其他维度的数组索引与此类似
横轴\ 纵轴| 0 | 1 | 2 | 3
—|—|—|—|—
0 | [0, 0] | [0, 1] | [0, 2] | [0, 3]
1 | [1, 0] | [1, 1] | [1, 2] | [1, 3]
2 | [2, 0] | [2, 1] | [2, 2] | [2, 3]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
arr = np.arange(12).reshape(2, 2, 3)
# array([[[ 0, 1, 2],
# [ 3, 4, 5]],
#
# [[ 6, 7, 8],
# [ 9, 10, 11]]])

arr[1]
# array([[ 6, 7, 8],
# [ 9, 10, 11]])

arr[1][1]
# array([ 9, 10, 11])

arr[1, 1]
# array([ 9, 10, 11])

arr[1, 1, 2]
# 11
布尔型索引
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
32
33
34
35
36
37
38
39
arr = np.arange(12).reshape(2, 2, 3)
# array([[[ 0, 1, 2],
# [ 3, 4, 5]],
#
# [[ 6, 7, 8],
# [ 9, 10, 11]]])

arr < 5
# array([[[ True, True, True],
# [ True, True, False]],
#
# [[False, False, False],
# [False, False, False]]])

arr[arr < 5]
# array([0, 1, 2, 3, 4]) 中 True 位置上取出的元素组成新的数组


names = np.array(['zj', 'zk', 'zl'])
scores = np.array([
[98, 97, 96],
[89, 79, 69],
[77, 66, 55]
])

# 取出 'zj' 对应的分数
scores[names == 'zj']
# array([[98, 97, 96]])

# 取出 'zj' 对应的分数的第二项分数
scores[names=='zj', 1]
# array([97])

# numpy 中可以使用 逻辑与 &, 逻辑或 |, 逻辑非 ~
# 取出不是 zj 的分数
scores[~(names == "zj")]
# array([[89, 79, 69],
# [77, 66, 55]])array([[89, 79, 69],
# [77, 66, 55]])
花式索引

指的是利用整数数组进行索引

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
arr = np.arange(12).reshape(6, 2)
# array([[ 0, 1],
# [ 2, 3],
# [ 4, 5],
# [ 6, 7],
# [ 8, 9],
# [10, 11]])

# 取第一维度的第 0, 3, 5 这几个元素
arr[[0, 3, 5]]
# array([[ 0, 1],
# [ 6, 7],
# [10, 11]])

# 取第一维度的第 0 个元素中的 第 1 个元素,第 3 个元素中的第 0 个元素,第 4 个元素中的第 1 个元素
arr[[0, 3, 5], [1, 0 ,1]]
# array([ 1, 6, 11])

# ix_函数产生一个索引器
ix = np.ix_([0, 3, 5], [1, 0, 1])
# (array([[0],[3],[5]]), array([[1, 0, 1]]))

arr[ix]
# array([[ 1, 0, 1],
# [ 7, 6, 7],
# [11, 10, 11]])
numpy 数组的切片
  • 在各维度上单独切片,如果某维度都要保留,则直接使用 : 冒号, 不指定起始值和终止值
  • numpy 中通过切片得到的新数组,只是原来数组的一个视图, 因此对新数组进行操作也会影响原数组
1
2
3
4
5
6
7
8
9
10
11
12
13
arr = np.arange(12).reshape(2, 2, 3)
# array([[[ 0, 1, 2],
# [ 3, 4, 5]],
#
# [[ 6, 7, 8],
# [ 9, 10, 11]]])

arr[1][1][1:]
# array([10, 11])

arr[0, : , 1:]
# array([[1, 2],
# [4, 5]])

数组转置

transpose 函数和数组的 T 属性用于数组转置,对于二维数组就是行列互换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
arr = np.arange(12).reshape(3, 4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

arr.transpose()
# array([[ 0, 4, 8],
# [ 1, 5, 9],
# [ 2, 6, 10],
# [ 3, 7, 11]])

arr.T
# array([[ 0, 4, 8],
# [ 1, 5, 9],
# [ 2, 6, 10],
# [ 3, 7, 11]])

通用函数: 快速的元素级数组函数

ufunc: 一种对 dnarray 中的数据执行元素级运算的函数,也可以看做是简单函数(接受一个或多个标量值,并产生一个或多个标量值)的矢量化包装器

常见的一元通用函数
一元 ufunc 说明
abs, fabs 计算整数,浮点数或复数的绝对值,对于非复数值
sqrt 计算各元素的平方根, 相当于 arr**0.5
square 计算各元素的平方, 相当于 arr**2
exp 计算各元素的指数 e 的 x 次方
log. log10, log2, log1p 分别为自然对数,底数是 10 的 log, 底数为 2 的 log, log(1+x)
sign 计算各元素的正负号, 1: 正数, 0: 零, -1 负数
cell 计算大于等于该值的最小正数
floor 计算小于等于该值的最大整数
rint 将各元素值四舍五入到最接近的整数, 保留 dtype
modf 将数组的小数位和整数部分以两个独立数组的形式返回
isnan 返回一个表示 “哪些值是 NaN” 的布尔类型数组
isfinite, isinf 分别返回一个表示 “哪些元素是有穷的(非 inf, 非 nan)” 或 “哪些元素是无穷的” 的布尔型整数
cos, cosh, sin, sinh, tan, tanh 普通型和双曲型三角函数
arccos, arccosh, arc, sin, arctan, arctanh 反三角函数
logical_not 计算各元素 not x 的真值, 相当于 ~ 和 -arr
常见的二元通用函数
二元 ufunc 说明
add 将数据中相同位置对应的元素相加
substract 从第一个数组中减去第二个数组中的元素
multiply 数据元素相乘
divide, floor_divive 除法或者向下整除法(丢弃余数)
pow 对第一个数组中的元素 A, 根据第二个数组中相应元素 B, 计算 A 的 B 次方
maximum, fmax 元素级别的最大值, fmax 会忽略 NaN
minimum, fmin 元素级别的最小值, fmin 会忽略 NaN
mod 元素级求模(除法的余数)
copysign 将第二个数组中的值的符号复制给第一个数组中对应位置的值
greater,greater_equal,less,less_equal,equal,not_equal 执行元素级别的比较运算,最终产生布尔型数组
logical_and, logical_or, logical_xor 执行元素级别的布尔逻辑运算, 相当于 &,

聚合函数

聚合函数是对一组值(比如一个数组)进行操作,返回一个单一值作为结果的函数.

1
2
3
4
5
6
arr = np.array([1, 2, 3, 4])
arr.max() #最大值 4
arr.min() # 最小值 1
arr.mean() # 均值 2.5
arr.std() # 标准差 1.118033988749895
np.sqrt(np.power(arr - arr.mean(), 2).sum()/arr.size) # 标准差 1.118033988749895

聚合函数可以指定对数值的某个轴元素进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
arr = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8]
])
# 对同一列上的元素计算均值, axis=0 表示横轴, axis=1 表示纵轴
arr.mean(axis=0) # array([3., 4., 5., 6.])
# 对同一行上的元素计算均值
arr.mean(axis=1) # array([2.5, 6.5])
# 同一列求和
arr.sum(axis=0) # array([ 6, 8, 10, 12])
# 同一行求最大值
arr.max(axis=1) # array([4, 8])
# 同一列求标准差
arr.std(axis=0) # array([2., 2., 2., 2.])

np.where 函数

三元表达式 x if condition else y 的矢量化版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xarr = np.array([1, 2, 3, 4, 5])
yarr = np.array([2, 3, 4, 5, 6])
condition = np.array([True, False, True, False, True])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, condition)]
# [1, 3, 3, 5, 5]

result = np.where(condition, xarr, yarr)
# array([1, 3, 3, 5, 5])


## 将数组中所有的 NaN 缺失值替换为 0
arr = np.array([
[1, 2, np.NaN, 4],
[3, 4, 5, np.NaN]
])
condition = np.isnan(arr)
result = np.where(condition, 0, arr)
# array([[1., 2., 0., 4.],
# [3., 4., 5., 0.]])

np.unique 函数

求数组中去掉重复元素后的一维数组

1
2
3
4
5
6
arr = np.array([
['a', 'a', 'c', 'd', 'h', 'c', 'f'],
['a', 'a', 'c', 'd', 'h', 'c', 'f']
])
result = np.unique(arr)
# array(['a', 'c', 'd', 'f', 'h'], dtype='<U1')

数组数据文件读写

将数组以二进制格式保存到磁盘

1
2
3
4
5
6
7
8
9
10
11
12
13
arr = np.arange(12).reshape(3, 4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

# 可以存储到本地文件名为 'arr', 后缀名为 '.npy' 的文件中,
np.save('arr', arr)

# 读取二进制文件
arr = np.load('arr.npy')
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

存取文本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
arr = np.arange(12, dtype=np.int).reshape(3, 4)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

# 转存为 'csv' 格式文件
np.savetxt('arr.csv', arr, delimiter=',', fmt="%s")

# 从 csv 文件中读取
arr = np.loadtxt('arr.csv', delimiter=',', dtype=np.int)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

# 从 csv 文件中读取
arr = np.genfromtxt('arr.csv', delimiter=',', dtype=np.int)
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])

使用 genformtxt 还可以指定 header, 假设有文件内容如下的 test.csv 文件:

1
2
3
4
A,B,C,D
0,1,2,3
4,5,6,7
8,9,10,11

可以这样灵活操作:

1
2
3
4
5
6
arr = np.genfromtxt("test.csv", delimiter=",", names=True, dtype=np.int)
# array([(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)],
# dtype=[('A', '<i8'), ('B', '<i8'), ('C', '<i8'), ('D', '<i8')])

arr['A'] # array([0, 4, 8])
arr[0] # (0, 1, 2, 3)

文章标题:numpy 入门练习

文章字数:4.2k

本文作者:Waterandair

发布时间:2018-02-10, 11:20:47

最后更新:2019-12-28, 14:03:59

原始链接:https://waterandair.github.io/2018-02-10-numpy-intro.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

github