Numpy

数据分析——numpy入门

2019-01-09  本文已影响7人  周二鸭

numpy 是 python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供了大量的数学函数库。
numpy内部解除了 python 中的 PIL(全局解释器锁),故而运算速率大大提高,是许多机器学习框架的基础库。

numpy 的基础入门

emmmm,首先肯定是引入啦

import numpy as np

ndarrar类

ndarray = n dimensional array
numpy 中的数组类被称之为 ndarray 类,它是一切同类型数据的组合。
快速调用 np.array 将 list 初始化成一个数组

>>> import numpy as np
>>> a = np.array([1, 2, 3])
>>> print(a)
[1 2 3]
>>> type(a)
<class 'numpy.ndarray'>

除此之外, ndarray 内置了一些创建 n 维数组的函数:
-np.zeros()
传入一个 tuple,生成一个 n×m 的数组,并且所有元素为 0
-np.ones()
传入一个 tuple,生成一个 n×m 的数组,并且所有元素为 1
-np.full()
传入一个 tuple 以及一个元素值,生成一个 n×m 的数组,并且所有元素为 传入的元素值

>>> b = np.zeros((1, 3))
>>> print(b)
[[0. 0. 0.]]
>>> b = np.ones((2, 4))
>>> print(b)
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]]
>>> b = np.full((4, 4), 5)
>>> print(b)
[[5 5 5 5]
 [5 5 5 5]
 [5 5 5 5]
 [5 5 5 5]]

-np.eye(x)
创建一个 x×x 的矩阵,对角线为 1,其余全部为0

>>> b = np.eye(4)
>>> print(b)
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

-np.random.randn()
生成一个正态分布的随机数矩阵

>>> b = np.random.randn(2, 3)
>>> print(b)
[[-0.33452655  0.90396491 -0.05452721]
 [ 0.70119151 -0.45483284  1.12117508]]

-np.empty()
生成一个空值的数组

>>> b = np.empty((2, 3))
>>> print(b)
[[0.33452655 0.90396491 0.05452721]
 [0.70119151 0.45483284 1.12117508]]

-np.arange()
类似于 python 中的 range()

>>> b = np.arange(15)
>>> print(b)
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]
>>> b.shape
(15,)

ndarray 内部具有以下一些重要的属性和内容:

-ndarray.shape:是一个整形的 truple,用以表示数组中每个维度的大小;

-ndarray.ndim:用以表示矩阵的秩;

-ndarray.itemsize:用以表示矩阵中元素的字节大小

-ndarray.size:用以表示矩阵中元素的个数,等同于 shape 中所有数值的乘积;

-ndarray.dtype:用以描述矩阵中元素的类型 ndarray 中的所有元素都必须是同一种类型。如果在构造数组时,传入的参数不是同一类型的,不同的类型将进行统一转化。除了标准的Python类型外,numpy 额外提供了一些自有的类型,如numpy.int32、numpy.int16 以及 numpy.float64 等。

>>> b = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(b)
[[1 2 3]
 [4 5 6]]
>>> b.shape
(2, 3)
>>> b.ndim
2
>>> b.itemsize
4
>>> b.size
6
>>> b.dtype
dtype('int32')

数组中的元素可以有不同的数据内容
声明数组时使用 dtype 定义类型,例子如下:

>>> b = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(b)
[[1 2 3]
 [4 5 6]]
>>> b.dtype
dtype('int32')
>>> b = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float64)
>>> print(b)
[[1. 2. 3.]
 [4. 5. 6.]]
>>> b.dtype
dtype('float64')
>>>

生成数组时,如果不指定数据的类型,numpy 会自动匹配合适的类型。

使用 astype 复制数组并转换数据类型:

>>> int_arr = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(int_arr)
[[1 2 3]
 [4 5 6]]
>>> float_arr = int_arr.astype(np.float64)
>>> print(float_arr, float_arr.dtype)
[[1. 2. 3.]
 [4. 5. 6.]] float64
# 也可以将 float 转换成 int 类型(小数点后数值消失,不精准)
>>> float_arr = np.array([[2.3, 2.4, 2.8], [3.3, 7.4, 2.8], [2.3, 2.4, 2.8]])
>>> print(float_arr)
[[2.3 2.4 2.8]
 [3.3 7.4 2.8]
 [2.3 2.4 2.8]]
>>> int_arr = float_arr.astype(np.int32)
>>> print(int_arr, int_arr.dtype)
[[2 2 2]
 [3 7 2]
 [2 2 2]] int32
# 使用 astype 也可将字符串数组转换成 int 类型或其他类型的数组,失败则抛出异常
>>> str_arr = np.array(['1.2', '2.3', '9.88'], dtype=np.string_)
>>> print(str_arr, str_arr.dtype)
[b'1.2' b'2.3' b'9.88'] |S4
>>> float_arr = str_arr.astype(np.float)
>>> print(float_arr, float_str.dtype)
[1.2  2.3  9.88] float64
>>> float_str = str_arr.astype(np.float)
>>> print(float_str, float_str.dtype)
[1.2  2.3  9.88] float64
>>> str_arr = np.array(['1.2', '2.3', '9.88', 'str'], dtype=np.string_)
>>> float_arr = str_arr.astype(np.float)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: 'str'

numpy 中也提供了许多种取值方式:

-可以像 list 一样切片(多维数组可以从各个维度同时切片)

>>> a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
>>> print(a, '\n', a.shape)
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
 (3, 4)
>>> b = a[0: 2, 2: 4].copy()
>>> print(b)
[[3 4]
 [7 8]]
# 下面将切片出来的某个元素赋值
>>> b[0, 0] = 99999
>>> print(b)
[[99999     4]
 [    7     8]]
# 下面就是刚刚创建 b 时要使用 copy() 函数的原因了(emmmm,我觉得你能懂)
>>> c = a[0:2 ,2: 4]
>>> c[0, 0] = 99999
>>> print(c, '\n', a)
[[99999     4]
 [    7     8]]
 [[    1     2 99999     4]
 [    5     6     7     8]
 [    9    10    11    12]]

python 中 list 支持的切片操作, ndarray 也是可以的:

>>> a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
>>> row_r1 = a[1,:]
>>> print(row_r1, row_r1.shape)
[5 6 7 8] (4,)

下面的操作更加高级些,可以自由的取值和组合:

>>> a = np.array([[1,2], [3, 4], [5, 6]])
>>> print(a)
[[1 2]
 [3 4]
 [5 6]]
# 下面代码代表分别取在 a 中下标为 (0, 0), (2, 1), (2, 0)
>>> print(a[[0,1,2], [0,1,0]])
[1 4 5]
>>> print(a[[0,1,2], [0,1,0]].shape)
(3,)
# emmmm,熟悉下操作
>>> a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
>>> print(a)
[[ 1  2  3]
 [ 4  5  6]
 [ 7  8  9]
 [10 11 12]]
>>> b = np.array([0, 2, 0, 1])
>>> a[np.arange(4), b]
array([ 1,  6,  7, 11])
# 元素取出来之后,自然也可以对这些元素进行操作
>>> a[np.arange(4), b] += 10
>>> print(a)
[[11  2  3]
 [ 4  5 16]
 [17  8  9]
 [10 21 12]]
# 还可以通过条件判断去取
>>> a = np.array([[1,2], [3, 4], [5, 6]])
>>> print(a)
[[1 2]
 [3 4]
 [5 6]]
>>> bool_index = (a > 2)
>>> print(bool_index)
[[False False]
 [ True  True]
 [ True  True]]
>>> print(a[bool_index], a[bool_index].shape)
[3 4 5 6] (4,)
# 其实也可以通过一句话完成
>>> print(a[a>2])
[3 4 5 6]

数学运算

下面的运算是在平时在科学运算中经常会遇见的,比如
矩阵间的逐元素的加减乘除

>>> x+y
array([[ 6.,  8.],
       [10., 12.]])
>>> np.add(x, y)
array([[ 6.,  8.],
       [10., 12.]])
>>> x-y
array([[-4., -4.],
       [-4., -4.]])
>>> np.subtract(x, y)
array([[-4., -4.],
       [-4., -4.]])
>>> x*y
array([[ 5., 12.],
       [21., 32.]])
>>> np.multiply(x, y)
array([[ 5., 12.],
       [21., 32.]])
>>> x/y
array([[0.2       , 0.33333333],
       [0.42857143, 0.5       ]])
>>> np.divide(x, y)
array([[0.2       , 0.33333333],
       [0.42857143, 0.5       ]])

逐元素求平方根

>>> np.sqrt(x)
array([[1.        , 1.41421356],
       [1.73205081, 2.        ]])

接下来就矩阵间的乘法:
矩阵间的乘法:matrix multiplication
求矩阵的内积

>>> a = np.array([9, 10])
>>> b = np.array([10, 11])
>>> a.dot(b)
200
>>> np.dot(a, b)
200

矩阵的转置

>>> a = np.array([[1, 2, 4], [5, 7, 12]])
>>> print(a)
[[ 1  2  4]
 [ 5  7 12]]
>>> a.T
array([[ 1,  5],
       [ 2,  7],
       [ 4, 12]])

利用矩阵的转置来求 dot product

>>> arr = np.random.randn(6,3)
>>> arr
array([[ 0.26379869, -0.74783591, -1.67933297],
       [-1.17108359,  0.97889562,  1.1089747 ],
       [ 2.22396729,  0.04233509, -0.38194605],
       [ 1.26126883, -0.27800004, -0.55361537],
       [ 0.01063307, -1.36537705,  0.68440918],
       [ 1.82748333,  2.06832898, -1.13805167]])
>>> print(arr.T.dot(arr))
[[11.31766447  2.16519094 -5.36189433]
 [ 2.16519094  7.73881073 -0.80917051]
 [-5.36189433 -0.80917051  6.26593439]]
>>>

高维的 tensor 也有对应的转置函数

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

       [[ 7,  8,  9],
        [10, 11, 12]]])
>>> arr.transpose(1, 0, 2)
array([[[ 1,  2,  3],
        [ 7,  8,  9]],

       [[ 4,  5,  6],
        [10, 11, 12]]])
>>> arr = np.arange(16).reshape(2, 2, 4)
>>> arr
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])
>>> print(arr.swapaxes(1,2))
[[[ 0  4]
  [ 1  5]
  [ 2  6]
  [ 3  7]]

 [[ 8 12]
  [ 9 13]
  [10 14]
  [11 15]]]

科学运算中,矩阵最常用到的矩阵内元素的运算——求和、取平均数运算,numpy 也提供了对应的函数:
sum()
mean()

>>> arr
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])
>>> arr.sum()
120
>>> np.sum(arr)
120
>>> arr.sum(axis=1)
array([[ 4,  6,  8, 10],
       [20, 22, 24, 26]])
>>> np.sum(arr, axis=1)
array([[ 4,  6,  8, 10],
       [20, 22, 24, 26]])
>>> arr.mean()
7.5
>>> np.mean(arr)
7.5
>>> arr.mean(axis=1)
array([[ 2.,  3.,  4.,  5.],
       [10., 11., 12., 13.]])
>>> np.mean(arr, axis=1)
array([[ 2.,  3.,  4.,  5.],
       [10., 11., 12., 13.]])

当然,numpy 中还提供了许多其他的运算函数,具体还是得看官方文档。

NumPy 广播 (Broadcast)

broadcasting
广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。

如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。

当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制,如:

>>> a = np.array([1,2,3,4])
>>> b = np.array([10,20,30,40])
>>> c = a * b
>>> print (c)
[ 10  40  90 160]
# 以下代码 a.shape != b.shape, 将自动触发 numpy 中的广播机制
>>> a = np.array([[ 0, 0, 0],
...            [10,10,10],
...            [20,20,20],
...            [30,30,30]])
>>> b = np.array([1,2,3])
>>> print(a + b)
[[ 1  2  3]
 [11 12 13]
 [21 22 23]
 [31 32 33]]

当操作两个array时,numpy会逐个比较它们的shape,在下述情况下,两arrays会兼容和输出broadcasting结果:

相等
其中一个为1,(进而可进行拷贝拓展已至,shape匹配)

比如求和的时候有:

Image (3d array): 256 x 256 x 3
Scale (1d array): 3
Result (3d array): 256 x 256 x 3

A (4d array): 8 x 1 x 6 x 1
B (3d array): 7 x 1 x 5
Result (4d array): 8 x 7 x 6 x 5

A (2d array): 5 x 4
B (1d array): 1
Result (2d array): 5 x 4

A (2d array): 15 x 3 x 5
B (1d array): 15 x 1 x 5
Result (2d array): 15 x 3 x 5

下图展示了两个数组如何通过广播来互相兼容:


fig_broadcast_visual_1.png

广播的规则:

1.让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
2.输出数组的形状是输入数组形状的各个维度上的最大值。
3.如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
4.当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

1.数组拥有相同形状。
2.当前维度的值相等。
3.当前维度的值有一个是 1。

若条件不满足,抛出 "ValueError: frames are not aligned" 异常。

连接/拆分数组

numpy 中提供的多个函数来支持数组的连接和拆分:

concatenate():沿 axis 连接数组序列

>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> np.concatenate((a, b.T), axis=1)
array([[1, 2, 5],
       [3, 4, 6]])
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])


参考文档:
NumPy Reference

上一篇下一篇

猜你喜欢

热点阅读