Numpy自学教程1-numpy简介

本文不是原创,是对Machine Learning Plus网站一篇文章的翻译,自己在学习的时候看着不错,想翻译过来和大家一些学习交流。原文地址:Numpy Tutorial Part 1 – Introduction to Arrays

下面正式开始:

Numpy教程的第一部分涵盖了使用Numpy的ndarray进行分析、展现和操作的所有核心知识。Numpy是python中进行科学计算和数据操作的最基本的也是最强大的包。

目录

目录:

1. Numpy简介

2. 如何创建一个数组

3. 如何查看一个数组的大小(size)和形状(shape)

4. 如何从数组同提取特定元素

4.1 如何反转行和整个数组

4.2 如何表示缺失值和极限值

4.3 如何计算数组的最大值,最小值和平均值

5. 如何基于已有数组创建新数组

6. 改变多维数组的形状或者将多维数组拍平

6.1 flatten()和ravel()的差别

7. 如何使用numpy创建顺序,重复和随机数字

7.1 如何创建重复的顺序序列

7.2 如何创建重复数字

7.3 如何获取所有唯一值和计数

1. Numpy简介

Numpy是python中处理数据最基本最强大的包。

如果您要进行数据分析或者机器学习项目,那么对numpy有一个深入的认识就几乎是必须的了。

因为其他数据分析的包都是基于numpy的,如pandas。用scikit-learn包进行机器学习也是非常依赖于numpy的。

那么numpy都提供什么功能呐?

一句话,numpy提供了一个非常出色的ndarry对象。 n-dimensional arrays的简称。

你可以在一个'ndarray'或者说'array'中,保存同一数据类型的多个数字。围绕数组的一系列方法使得numpy在进行数据计算和数据操作上非常的便捷。

你可能会说,我可以在python自带的对象里保存这些数据,比如列表对象等。而且也可以通过这些对象操作这些数据,那为什么我还要使用numpy呐?

其实,numpy中的数组比python中的列表有明显的优势。为了理解这一点,我们先创建一个数组。

2. 如何创建一个数组

创建数组的方法有很多,本文后面也都会讲到,但是最基本的方法是通过将一个列表传入np.array函数中来创建。

# 通过一个列表创建一维数组
import numpy as np
list1=[0,1,2,3,4]
arr1d=np.array(list1)

print(type(arr1d))
arr1d

#> class 'numpy.ndarray'
#> array([0, 1, 2, 3, 4])

数组和列表的关键区别在于,数组是用来处理向量运算而列表不是。

也就是说如果你运行一个函数,这个函数是作用在数组中的每一个元素上的,而不是整个数组的对象上。

例如,如果你想对列表中的每一个元素加2,直观的方式是如下操作

list1 + 2 #error

上面这样对列表的操作是错误的,但是对数组就可以这样操作。

# 对数组arr1d中每一个元素加2
arr1d +2

#> array([2,3,4,5,6])

数组的另一个特性是,数组一旦创建好之后就不能再修改大小。如果要修改就只能重建一个新的数组。但是列表却可以在创建好以后再修改大小。

上面是关于1维数组的,你同样可以通过传入列表的列表来创建二维数组。

# 通过列表的列表创建二维数组
list2 = [[0,1,2], [3,4,5], [6,7,8]]
arr2d = np.array(list2)
arr2d

#> array([[0, 1, 2],
#>        [3, 4, 5],
#>        [6, 7, 8]])

你还可以通过设置dtype参数的值,来设置数组的数据类型。常用的数据类型有 'float','int','bool','str'和'object'。

为了控制内存的分配,你还可以将dtype的参数设置为:'float32','float64','int8',int16' 或者'int3e2'。

#创建浮点数类型的数组
arr2d_f = np.array(list2, dtype='float')
arr2d_f

#> array([[ 0.,  1.,  2.],
#>        [ 3.,  4.,  5.],
#>        [ 6.,  7.,  8.]])

数字后面的小数点表示是浮点数的数据类型。你也可以通过astype函数转换数组的数据类型。

#转换为'int'类型
arr2d_f.astype('int')

#> array([[0, 1, 2],
#>        [3, 4, 5],
#>        [6, 7, 8]])
#转换成'int'后再转成'str'
arr2d_f.astype('int').astype('str')

#> array([['0', '1', '2'],
#>        ['3', '4', '5'],
#>        ['6', '7', '8']],
#>       dtype='U21')

一个数组中所有元素的数据类型必须是相同的,但列表就可以不同。这是列表和元素的另一个显著的不同。

但是,如果你不确定数组中要传入什么类型的数据,或者你想在一个数组中传入字母和数组,你可以将dtype设置为'object'。

# 创建布尔数组
arr2d_b = np.array([1, 0, 10], dtype='bool')
arr2d_b

#> array([ True, False,  True], dtype=bool)
# 创建一个可以传入数字和字符串的数组
arr1d_obj = np.array([1, 'a'], dtype='object')
arr1d_obj

#> array([1, 'a'], dtype=object)

最后,你总能通过.tolist()函数将数组转换成列表。

# 将一个数组转换回列表
arr1d_obj.tolist()

#> [1, 'a']

总结一下数组和列表的主要不同点:

1. 数组支持向量运算,列表不支持

2.数组创建后就不能修改大小,只能新建一个或者重写当前数组

3.一个数组只能包含一种数据类型的元素

4.同样数量的元素,数组占用的内存空间远小于列表

3. 如何查看一个数组的大小(size)和形状(shape)

为了认识数组,每一个数组都有一些我们想要知道的属性。

例如上面的数组arr2d,它通过一个列表的列表创建的,所以它有两个维度。可以显示为行和列,就像一个矩阵。

如果我基于一个列表的列表的列表创建的数组,则它就是3维度的,就像一个立方体。以此类推。

假如你有一个别人创建的数组,你会想知道这个数组的那些属性呐?例如:

它是一维,两维还是多维的?(ndim)

每一个维度中有多少元素?(shape)

数组的数据类型是什么?(dtype)

数组中元素的总数是多少?(size)

数组中一些样例数据(通过索引)

# 创建一个3行4列的两维数组
list2 = [[1, 2, 3, 4],[3, 4, 5, 6], [5, 6, 7, 8]]
arr2 = np.array(list2, dtype='float')
arr2

#> array([[ 1.,  2.,  3.,  4.],
#>        [ 3.,  4.,  5.,  6.],
#>        [ 5.,  6.,  7.,  8.]])
# shape
print('Shape: ', arr2.shape)

# dtype
print('Datatype: ', arr2.dtype)

# size
print('Size: ', arr2.size)

# ndim
print('Num Dimensions: ', arr2.ndim)

#> Shape:  (3, 4)
#> Datatype:  float64
#> Size:  12
#> Num Dimensions:  2

4. 如何从数组同提取特定元素

arr2

#> array([[ 1.,  2.,  3.,  4.],
#>          [ 3.,  4.,  5.,  6.],
#>          [ 5.,  6.,  7.,  8.]])

在数组中可以使用从0开始的索引提取特定元素,这一点有点类似python 的列表。但是和列表不同的是,数组可以在括号中使用多个索引,因为数组本身也是多维的。

# 提取前两行前两列
arr2[:2, :2]
list2[:2, :2]  # error

#> array([[ 1.,  2.],
#>        [ 3.,  4.]])

另外,数组还支持布尔索引。

布尔索引是指和被查询数组相同形状的索引数组,这个索引数组中只有True和False,被查询数据汇总所有True对应位置的元素都会被查询到。

# 可以通过对数组中所有元素进行判断获得一个布尔数组
b = arr2 > 4
b

#> array([[False, False, False, False],
#>        [False, False,  True,  True],
#>        [ True,  True,  True,  True]], dtype=bool)
arr2[b]

#> array([ 5.,  6.,  5.,  6.,  7.,  8.])

4.1 如何反转行和整个数组

反转数组和反转列表有点相似,但是如果要反转整个数组,就需要对所有维度反转。

# 只反转行
arr2[::-1, ]

#> array([[ 5.,  6.,  7.,  8.],
#>        [ 3.,  4.,  5.,  6.],
#>        [ 1.,  2.,  3.,  4.]])
# 反转行和列
arr2[::-1, ::-1]

#> array([[ 8.,  7.,  6.,  5.],
#>        [ 6.,  5.,  4.,  3.],
#>        [ 4.,  3.,  2.,  1.]])

4.2 如何表示缺失值和极限值

缺失值和极限值可以分别用np.nan和np.inf表示。

# 在数组中插入一个空值和极限值
arr2[1,1] = np.nan  # not a number
arr2[1,2] = np.inf  # infinite
arr2

#> array([[  1.,   2.,   3.,   4.],
#>        [  3.,  nan,  inf,   6.],
#>        [  5.,   6.,   7.,   8.]])
# 用-1 置换nan和infR. 这里不要使用 arr2 == np.nan
missing_bool = np.isnan(arr2) | np.isinf(arr2)
arr2[missing_bool] = -1  
arr2

#> array([[ 1.,  2.,  3.,  4.],
#>        [ 3., -1., -1.,  6.],
#>        [ 5.,  6.,  7.,  8.]])

4.3 如何计算数组的最大值,最小值和平均值

数据中有各自的方法来计算这些聚类值。

# mean(平均值), max(最大值) and min(最小值)
print("Mean value is: ", arr2.mean())
print("Max value is: ", arr2.max())
print("Min value is: ", arr2.min())

#> Mean value is:  3.58333333333
#> Max value is:  8.0
#> Min value is:  -1.0

如何要计算各行各列,使用np.amin函数。

# 行和列的平均值 min
print("Column wise minimum: ", np.amin(arr2, axis=0))
print("Row wise minimum: ", np.amin(arr2, axis=1))

#> Column wise minimum:  [ 1. -1. -1.  4.]
#> Row wise minimum:  [ 1. -1.  5.]

计算行的最小值还好,但是如果在行上做其他计算呐?这个就需要使用np.apply_over_axix函数。

# 累积加和 第1个元素,第1个元素+第2个元素,第2个元素+第3个元素 ...
np.cumsum(arr2)

#> array([  1.,   3.,   6.,  10.,  13.,  12.,  11.,  17.,  22.,  28.,  35., 43.])

5. 如何基于已有数组创建新数组

如果我们只是将现有数组的一部分分配给另一个数组,那么我们刚刚新建的这个数组其实在内存中是指向原有数组的。

也就是说,对新数组的任何修改都是对原有数组的修改。

为了避免原有数组被修改,我们就需要将原有数据复制一份copy().所有的numpy数组方法都来源于复制。

# 将arr2的一部分分配给arr2a. 并不是新建了一个数组.
arr2a = arr2[:2,:2]  
arr2a[:1, :1] = 100  # 100 也会显示在 arr2 中
arr2

#> array([[ 100.,    2.,    3.,    4.],
#>        [   3.,   -1.,   -1.,    6.],
#>        [   5.,    6.,    7.,    8.]])
# 将arr2 的一部分复制到 arr2b
arr2b = arr2[:2, :2].copy()
arr2b[:1, :1] = 101  # 101 就不会出现在 arr2 中
arr2

#> array([[ 100.,    2.,    3.,    4.],
#>        [   3.,   -1.,   -1.,    6.],
#>        [   5.,    6.,    7.,    8.]])

6. 改变多维数组的形状或者将多维数组拍平

reshape函数是修改数组的元素排列方式来修改数组的形状,会保持数组的元素数不变。

flattening拍平是会将多维的数组变换成一维数组,并且是只会转成一维数组。

首先,我们将arr2从 3X4 转换成4X3

# 将arr2 从3X4 转换成 4X3
arr2.reshap(4,3)
#> array([[ 100.,    2.,    3.],
#>        [   4.,    3.,   -1.],
#>        [  -1.,    6.,    5.],
#>        [   6.,    7.,    8.]])

6.1 flatten()和ravel()的差别

有两个常用的将数组拍平的方法:flatten()和ravel().

两者的区别是,ravel()创建的新数组在内存中指向原有父数组。所以对新的数组的任何修改,都会修改原有父数组。但是ravel()的一个优点是因为它没有复制新的数组,所有会节省内存空间。

# 将arr2拍平成一维数组
arr2.flatten()

#> array([ 100.,    2.,    3.,    4.,    3.,   -1.,   -1.,    6.,    5., 6.,    7.,    8.])
# 对拍平后的数组的修改不会影响父数组
b1 = arr2.flatten()  
b1[0] = 101  # changing b1 does not affect arr2
arr2

#> array([[ 100.,    2.,    3.,    4.],
#>        [   3.,   -1.,   -1.,    6.],
#>        [   5.,    6.,    7.,    8.]])
# 修改ravel创建的新数组也会修改父数组.
b2 = arr2.ravel()  
b2[0] = 101  # changing b2 changes arr2 also
arr2

#> array([[ 101.,    2.,    3.,    4.],
#>        [   3.,   -1.,   -1.,    6.],
#>        [   5.,    6.,    7.,    8.]])

7. 如何使用numpy创建顺序,重复和随机数字

要创建一个顺序的数组,np.arange函数是随手就能用到的。

# 最小值默认是0
print(np.arange(5))  

# 0 to 9
print(np.arange(0, 10))  

# 从0到9,步长是2
print(np.arange(0, 10, 2))  

# 10到1的递减数列
print(np.arange(10, 0, -1))

#> [0 1 2 3 4]
#> [0 1 2 3 4 5 6 7 8 9]
#> [0 2 4 6 8]
#> [10  9  8  7  6  5  4  3  2  1]

在np.arange函数中可以设置起止数值。但是如果你想指定数组中元素的个数的话,你就必须得手动计算步长了。

比如,你想创建一个数组包含1到50间等距的10个数字,你能计算出步长吗?

我们用np.linspace就可以实现这一点。

# 从1开始,在50结束
np.linspace(start=1, stop=50, num=10, dtype=int)

#> array([ 1,  6, 11, 17, 22, 28, 33, 39, 44, 50])

请注意,因为我们将dtype设置为'int',所有数字都是取了整数的。

与linspace相似的函数还有一个logspace。logspace是基于对数的。在np.logspace中,开始值和结束值是已固定值为底数给定的起止值为真数的对数。默认的底数是10.举个例子方便理解:

# 精确到小数点后两位
np.set_printoptions(precision=2)  

# 以 10^1 开始,以 10^50结束
np.logspace(start=1, stop=50, num=10, base=10) 

#> array([  1.00e+01,   2.78e+06,   7.74e+11,   2.15e+17,   5.99e+22,
#>          1.67e+28,   4.64e+33,   1.29e+39,   3.59e+44,   1.00e+50])

np.zeros和np.ones函数可以以任意形状创建数组,数组中的值都是0或1.

np.zeros([2,2])
#> array([[ 0.,  0.],
#>        [ 0.,  0.]])
np.ones([2,2])
#> array([[ 1.,  1.],
#>        [ 1.,  1.]])

7.1 如何创建重复的顺序序列

np.tile会重复整个列表或者数组,np.repeat或重复每一个元素。

a = [1,2,3] 

# 重复整个'a'两次
print('Tile:   ', np.tile(a, 2))

# 重复两次'a'中的每一个元素
print('Repeat: ', np.repeat(a, 2))

#> Tile:    [1 2 3 1 2 3]
#> Repeat:  [1 1 2 2 3 3]

7.2 如何创建重复数字

random模块可以提供非常好用的创建任意形状的随机数的函数(也包括统计分布)。

# [0,1) 形状为 2,2 的随机数字
print(np.random.rand(2,2))

# 服从均值为1,方差为0的正态分布的形状为 2,2 的随机数字
print(np.random.randn(2,2))

# [0, 10) 间形状为 2,2 的随机整数
print(np.random.randint(0, 10, size=[2,2]))

# [0,1)一个随机数字
print(np.random.random())

# [0,1)间形状为2,2的随机数字
print(np.random.random(size=[2,2]))

# 在给定的列表中挑出10个元素,每一个元素出现概率相同
print(np.random.choice(['a', 'e', 'i', 'o', 'u'], size=10))  

# 在给定的列表中挑出10个元素,,每个元素出现概率是给定的
print(np.random.choice(['a', 'e', 'i', 'o', 'u'], size=10, p=[0.3, .1, 0.1, 0.4, 0.1]))  # picks more o's

#> [[ 0.84  0.7 ]
#>  [ 0.52  0.8 ]]

#> [[-0.06 -1.55]
#>  [ 0.47 -0.04]]

#> [[4 0]
#>  [8 7]]

#> 0.08737272424956832

#> [[ 0.45  0.78]
#>  [ 0.03  0.74]]

#> ['i' 'a' 'e' 'e' 'a' 'u' 'o' 'e' 'i' 'u']
#> ['o' 'a' 'e' 'a' 'a' 'o' 'o' 'o' 'a' 'o']

每次运行上面的函数时,都会得到不懂的随机数字。

那如果我们想让每次的随机数字都相同呐?这是就需要设定随机种子(random seed)或者随机状态(random state)。seed可以是任意值。唯一需要注意的就是每一次都将seed设定为同一个值,那么每次都能得到相同的随机值。

一旦创建了np.random.RandomState 所有np.random模块中的函数都可以用来创建randomstate对象。

# 创建random state
rn = np.random.RandomState(100)

# 创建[0,1) 间形状为 2,2 的随机值
print(rn.rand(2,2))

#> [[ 0.54  0.28]
#>  [ 0.42  0.84]]
# 设定 random seed
np.random.seed(100)

# 创建[0,1) 间形状为2,2的随机值
print(np.random.rand(2,2))

#> [[ 0.54  0.28]
#>  [ 0.42  0.84]]

7.3 如何获取所有唯一值和计数

np.unique函数可以获取数组中的非重复值,如何你还想得到每一个唯一值得重复次数,只要将 return_counts参数设置为'True'.

# 创建 [0,10)间大小为10的数组
np.random.seed(100)
arr_rand = np.random.randint(0, 10, size=10)
print(arr_rand)

#> [8 8 3 7 7 0 4 2 5 2]
# 获得唯一值和各个唯一值的重复次数
uniqs, counts = np.unique(arr_rand, return_counts=True)
print("Unique items : ", uniqs)
print("Counts       : ", counts)

#> Unique items :  [0 2 3 4 5 7 8]
#> Counts       :  [1 2 1 1 1 2 2]

完结。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值