python语言直接提供的数据类型数组类型_深度学习中的Python语言2:Numpy数组、索引、数据类型、运算、广播的介绍...

文章目录:数组(Arrays)

数组索引(Array indexing)

数据类型(Datatypes)

数组运算(Array math)

广播(Broadcasting)

注意,该文章不是大而全的python使用说明,如果你想要的话可以去python官方文档查看。

此文章的重点在于,介绍一些基本概念和方法,理解这些概念在深度学习中的应用。

下面是正文:

1. 数组(Arrays)

先介绍一下Numpy。

Numpy是Python语言用于科学计算的核心库之一。

想要使用Numpy库的话,只需要在Python代码的开头引用该库即可:

import numpy as np

这行代码的意思是引用numpy库,别称是np,也就是说下面你可以使用np代替numpy。

数组是‘网格化’的值的集合,也就是说,数组是多维的,如果说列表(list)可以用于表示向量的话(请参考这里),数组可以用于表示矩阵(二维数组)。这在机器学习中非常常用,一定要记住!!!重要的内容要加粗!!!

import numpy as np

a = np.array([1, 2, 3]) # Create a rank 1 array

print(type(a)) # Prints ""

print(a.shape) # Prints "(3,)"

print(a[0], a[1], a[2]) # Prints "1 2 3"

a[0] = 5 # Change an element of the array

print(a) # Prints "[5, 2, 3]"

b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array

print(b.shape) # Prints "(2, 3)"

print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"

注意以下的代码:

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

这里创建二维数组要用中括号把两个列表都包括进来。而不是b = np.array([1,2,3],[4,5,6])

注意,这里创建数组用的是括号(),里面的元素是列表[ ],这在数学上也能对应起来了,向量组成矩阵。

另外,数组里的维度也叫做rank。

numpy提供可很多创建数组的方法:

import numpy as np

a = np.zeros((2,2)) # Create an array of all zeros

print(a) # Prints "[[ 0. 0.]

# [ 0. 0.]]"

b = np.ones((1,2)) # Create an array of all ones

print(b) # Prints "[[ 1. 1.]]"

c = np.full((2,2), 7) # Create a constant array

print(c) # Prints "[[ 7. 7.]

# [ 7. 7.]]"

d = np.eye(2) # Create a 2x2 identity matrix

print(d) # Prints "[[ 1. 0.]

# [ 0. 1.]]"

e = np.random.random((2,2)) # Create an array filled with random values

print(e) # Might print "[[ 0.91940167 0.08143941]

# [ 0.68744134 0.87236687]]"

其他创建数组的方法见这里。

2. 数组索引(Array indexing)

另外一个重要的就是数组索引,这里先介绍第一种方法:

切片(slicing),这里的切片和列表的切片方式一样,不同的是,由于数组是多维的,因此需要对不同维度分别切片。

import numpy as np

# Create the following rank 2 array with shape (3, 4)

# [[ 1 2 3 4]

# [ 5 6 7 8]

# [ 9 10 11 12]]

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

# Use slicing to pull out the subarray consisting of the first 2 rows

# and columns 1 and 2; b is the following array of shape (2, 2):

# [[2 3]

# [6 7]]

b = a[:2, 1:3]

# A slice of an array is a view into the same data, so modifying it

# will modify the original array.

print(a[0, 1]) # Prints "2"

b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]

print(a[0, 1]) # Prints "77"

上面的代码解释一下:

首先,array的索引是从0开始,所以[:2]指的是从0到2,但是不包括2,也就是第0行和第1行。

同理,[1:3]指的是1到3,但是不包括3,也就第1列和第2列(前面还有一个第0列,这里没有索引)。

另外需要说明的是,如果b是通过切片的方式得到的a的子数组,其实在内存中,b只是指向a中对应的元素。因此改变b的值,a的值也会跟着改变。这点非常重要!!!

再来看下面一段代码。

import numpy as np

# Create the following rank 2 array with shape (3, 4)

# [[ 1 2 3 4]

# [ 5 6 7 8]

# [ 9 10 11 12]]

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

# Two ways of accessing the data in the middle row of the array.

# Mixing integer indexing with slices yields an array of lower rank,

# while using only slices yields an array of the same rank as the

# original array:

row_r1 = a[1, :] # Rank 1 view of the second row of a

row_r2 = a[1:2, :] # Rank 2 view of the second row of a

print(row_r1, row_r1.shape) # Prints "[5 6 7 8] (4,)"

print(row_r2, row_r2.shape) # Prints "[[5 6 7 8]] (1, 4)"

# We can make the same distinction when accessing columns of an array:

col_r1 = a[:, 1]

col_r2 = a[:, 1:2]

print(col_r1, col_r1.shape) # Prints "[ 2 6 10] (3,)"

print(col_r2, col_r2.shape) # Prints "[[ 2]

# [ 6]

# [10]] (3, 1)"

这段代码解释了“用切片和整数混合的方式进行索引”和“用索引的方式进行索引”的区别:

也就是a[1, :]和a[1:2, :]的区别,很明显,这里1是整数方式,“:”是索引方式。

这个区别可以用一句话概括:用整数方式有可能得到降维的数组,而用切片方式得到的数组永远是原数组的子数组。

下面介绍使用整数数组对另一个数组进行索引。

import numpy as np

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

# An example of integer array indexing.

# The returned array will have shape (3,) and

print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]"

# The above example of integer array indexing is equivalent to this:

print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"

# When using integer array indexing, you can reuse the same

# element from the source array:

print(a[[0, 0], [1, 1]]) # Prints "[2 2]"

# Equivalent to the previous integer array indexing example

print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"

也就是说,[0, 1, 2]是一个数组,用它来索引数组a。

这样得到的是一个新的数组,也就是说改变这个新的数组的值是不会影响原来的数组的。

再来看一个例子:

import numpy as np

# Create a new array from which we will select elements

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

print(a) # prints "array([[ 1, 2, 3],

# [ 4, 5, 6],

# [ 7, 8, 9],

# [10, 11, 12]])"

# Create an array of indices

b = np.array([0, 2, 0, 1])

# Select one element from each row of a using the indices in b

print(a[np.arange(4), b]) # Prints "[ 1 6 7 11]"

# Mutate one element from each row of a using the indices in b

a[np.arange(4), b] += 10

print(a) # prints "array([[11, 2, 3],

# [ 4, 5, 16],

# [17, 8, 9],

# [10, 21, 12]])

这是用整数数组进行索引的另一个例子,还可以用整数数组给原数组的元素加上一个数值。

最后介绍一下布尔型数组索引的例子:

import numpy as np

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

bool_idx = (a > 2) # Find the elements of a that are bigger than 2;

# this returns a numpy array of Booleans of the same

# shape as a, where each slot of bool_idx tells

# whether that element of a is > 2.

print(bool_idx) # Prints "[[False False]

# [ True True]

# [ True True]]"

# We use boolean array indexing to construct a rank 1 array

# consisting of the elements of a corresponding to the True values

# of bool_idx

print(a[bool_idx]) # Prints "[3 4 5 6]"

# We can do all of the above in a single concise statement:

print(a[a > 2]) # Prints "[3 4 5 6]"

这是一个非常常用的方法,用于选出数组中符合某种特定条件的元素。

3. 数据类型(Datatypes)

首先,数组是具有相同数据类型的数据的集合。

数组的数据类型(Datatypes)在创建数组时已经自动指定了,但是我们也可以强迫数组使用我们指定的数据类型。见下面的代码例子。

import numpy as np

x = np.array([1, 2]) # Let numpy choose the datatype

print(x.dtype) # Prints "int64"

x = np.array([1.0, 2.0]) # Let numpy choose the datatype

print(x.dtype) # Prints "float64"

x = np.array([1, 2], dtype=np.int64) # Force a particular datatype

print(x.dtype) # Prints "int64"

更多的资料看这里。

4. 数组运算(Array math)

基础的数学运算都是元素运算(elementwise),无论是使用重载的运算符还是函数。

import numpy as np

x = np.array([[1,2],[3,4]], dtype=np.float64)

y = np.array([[5,6],[7,8]], dtype=np.float64)

# Elementwise sum; both produce the array

# [[ 6.0 8.0]

# [10.0 12.0]]

print(x + y)

print(np.add(x, y))

# Elementwise difference; both produce the array

# [[-4.0 -4.0]

# [-4.0 -4.0]]

print(x - y)

print(np.subtract(x, y))

# Elementwise product; both produce the array

# [[ 5.0 12.0]

# [21.0 32.0]]

print(x * y)

print(np.multiply(x, y))

# Elementwise division; both produce the array

# [[ 0.2 0.33333333]

# [ 0.42857143 0.5 ]]

print(x / y)

print(np.divide(x, y))

# Elementwise square root; produces the array

# [[ 1. 1.41421356]

# [ 1.73205081 2. ]]

print(np.sqrt(x))

也就是说,无论是使用运算符:+、-、*、/,还是使用函数 np.add, np.subtract, np.multiply, np.divide都是对矩阵对应位置的元素进行运算。

计算向量内积、矩阵与向量相乘、矩阵相乘均可以使用函数np.dot。

import numpy as np

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

y = np.array([[5,6],[7,8]])

v = np.array([9,10])

w = np.array([11, 12])

# Inner product of vectors; both produce 219

print(v.dot(w))

print(np.dot(v, w))

# Matrix / vector product; both produce the rank 1 array [29 67]

print(x.dot(v))

print(np.dot(x, v))

# Matrix / matrix product; both produce the rank 2 array

# [[19 22]

# [43 50]]

print(x.dot(y))

print(np.dot(x, y))

np.sum是非常常用的函数之一,可以方便的对行或列进行求和:

import numpy as np

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

print(np.sum(x)) # Compute sum of all elements; prints "10"

print(np.sum(x, axis=0)) # Compute sum of each column; prints "[4 6]"

print(np.sum(x, axis=1)) # Compute sum of each row; prints "[3 7]"

常用数学计算函数列表见官网。

转置的话在python中可以非常方便:

import numpy as np

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

print(x) # Prints "[[1 2]

# [3 4]]"

print(x.T) # Prints "[[1 3]

# [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:

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

print(v) # Prints "[1 2 3]"

print(v.T) # Prints "[1 2 3]"

python提供了大量用于操作矩阵的函数,非常方便,见官网。

5. 广播(Broadcasting)

python中的‘广播’是一个稍微复杂一点的概念,需要多加练习,加强理解。

但是一旦学会使用‘广播’,这将是一个强大的工具,它能够帮助我们完成大量重复工作,化简为繁,也是深度学习算法中向量化的重要步骤!

‘广播’可以用来计算不同维度的矩阵之间的计算问题,一般用来解决这样的问题:我们有一个大矩阵和一个小矩阵,我们想用小矩阵对大矩阵进行多次重复的操作。

举例说明:我们想对矩阵的每一列加上一个向量,常规方法是这样操作:

import numpy as np

# We will add the vector v to each row of the matrix x,

# storing the result in the matrix y

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

v = np.array([1, 0, 1])

y = np.empty_like(x) # Create an empty matrix with the same shape as x

# Add the vector v to each row of the matrix x with an explicit loop

for i in range(4):

y[i, :] = x[i, :] + v

# Now y is the following

# [[ 2 2 4]

# [ 5 5 7]

# [ 8 8 10]

# [11 11 13]]

print(y)

当然,上述方法是可行的,但是,当矩阵x非常大时,利用循环进行运算将耗时耗力。

一个巧妙的方法是,我们将向量v复制并扩展成vv,vv的行数与x相同,上述操作等同于x与vv的对应元素相加。用代码表示就是:

import numpy as np

# We will add the vector v to each row of the matrix x,

# storing the result in the matrix y

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

v = np.array([1, 0, 1])

vv = np.tile(v, (4, 1)) # Stack 4 copies of v on top of each other

print(vv) # Prints "[[1 0 1]

# [1 0 1]

# [1 0 1]

# [1 0 1]]"

y = x + vv # Add x and vv elementwise

print(y) # Prints "[[ 2 2 4

# [ 5 5 7]

# [ 8 8 10]

# [11 11 13]]"

利用numpy中的‘广播’可以帮我们节省创建vv的过程:

import numpy as np

# We will add the vector v to each row of the matrix x,

# storing the result in the matrix y

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

v = np.array([1, 0, 1])

y = x + v # Add v to each row of x using broadcasting

print(y) # Prints "[[ 2 2 4]

# [ 5 5 7]

# [ 8 8 10]

# [11 11 13]]"

也就是说,numpy自动将v复制并扩展为(4,3)的矩阵并与x相加,却不需要我们做任何事,仅仅使用‘+’即可!

‘广播’更加通用的规则见官网。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值