目录
使用zeros,ones,empty函数实例化ndarray对象
第1关:ndarray对象
相关知识
怎样安装NumPy
什么是ndarray对象
NumPy
为什么能够受到各个数据科学从业人员的青睐与追捧,其实很大程度上是因为NumPy
在向量计算方面做了很多优化,接口也非常友好(总之就是用起来很爽)。而这些其实都是在围绕着NumPy
的一个 核心数据结构 ndarray
。
ndarray
对象实例化好了之后,包含了一些基本的属性。比如shape
,ndim
,size
,dtype
。其中:
来看个例子,假设现在有一个3
行5
列的矩阵(ndarray
)如下:
那么该ndarray有
示例代码如下:
如何实例化ndarray对象
使用array函数实例化ndarray对象
如果你手头上有一个python
的list
,想要将这个list
转成ndarray
,此时可以使用NumPy
中的array
函数将list
中的值作为初始值,来实例化一个ndarray
对象。代码如下:
使用zeros,ones,empty函数实例化ndarray对象
通常在写代码的时候,数组中元素的值一般都喜欢先初始化成0
,如果使用array
的方式实例化ndarray
对象的话,虽然能实现功能,但显得很麻烦( 首先要有一个全是0
的list
)。那有没有简单粗暴的方式呢,有!那就是zeros
函数,你只需要把ndarray
的shape
作为参数传进去即可。代码如下:
如果想把数组中的元素全部初始化成1
,聪明的你应该能想到就是用ones
函数,ones
的用法与zeros
一致。代码如下:
如果01大法
满足不了你,想要用随机值作为初始值来实例化ndarray
对象,empty
函数能够满足你。empty
的使用方式与zeros
和ones
如出一辙,代码如下:
代码文件
import numpy as np
def print_ndarray(input_data):
'''
实例化ndarray对象并打印
:param input_data: 测试用例,类型为字典类型
:return: None
'''
#********* Begin *********#
a = np.array(input_data['data'])
print(a)
#********* End *********#
第2关:形状操作
相关知识
怎样改变ndarray
对象的形状
上一关介绍了怎样实例化ndarray
对象,比如想实例化一个3
行4
列的二维数组,并且数组中的值全为0
。就可能会写如下代码:
那如果想把a
变成4
行3
列的二维数组,怎么办呢?比较聪明的同学可能会想到这样的代码:
最后你会发现,这样的代码可以完成功能,但是这种直接改属性的方式太粗暴了,不符合良好的编程规范。更加优雅的解决方式是使用NumPy
为我们提供了一个用来改变ndarray
对象的shape
的函数,叫 reshape
。
如果你更偏向于面向对象,那么你可以想象成ndarray
对象中提供好了一个叫reshape
成员函数。代码如下:
如果你更偏向于面向过程,NumPy
在它的作用域内实现了reshape
函数。代码如下:
PS
:不管是哪种方式的reshape
,都不会改变原ndarray
的形状,而是将源ndarray
进行深拷贝并进行变形操作,最后再将变形后的数组返回出去。也就是说如果代码是np.reshape(a, (4, 3))
那么a
的形状不会被修改!
如果想优雅的直接改变源ndarray
的形状,可以使用resize
函数。代码如下:
有的时候懒得去算每个维度上的长度是多少,比如现在有一个6
行8
列的ndarray
,然后想把它变形成有2
列的ndarray
(行的数量我懒得去想),此时我们可以在行的维度上传个-1
即可,代码如下:
也在变形操作时,如果某个维度上的值为-1
,那么该维度上的值会根据其他维度上的值自动推算。
PS
:-1
虽好,可不能贪杯!如果代码改成a = a.reshape((-1, -1))
,NumPy
会认为你是在刁难他,并向你抛出异常ValueError: can only specify one unknown dimension
。
代码文件
import numpy as np
def reshape_ndarray(input_data):
'''
将ipnut_data转换成ndarray后将其变形成一位数组并打印
:param input_data: 测试用例,类型为list
:return: None
'''
#********* Begin *********#
a = np.array(input_data)
a = a.reshape(-1)
print(a)
#********* End *********#
第3关:基础操作
相关知识
算术运算
如果想要对ndarray
对象中的元素做elementwise
(逐个元素地)的算术运算非常简单,加减乘除即可。代码如下:
矩阵运算
相同shape
的矩阵A
与矩阵B
之间想要做elementwise
运算也很简单,加减乘除即可。代码如下:
细心的同学应该发现了,*
只能做elementwise
运算,如果想做真正的矩阵乘法运算显然不能用*
。NumPy
提供了@
和dot
函数来实现矩阵乘法。代码如下:
简单统计
有的时候想要知道ndarray
对象中元素的和是多少,最小值是多少,最小值在什么位置,最大值是多少,最大值在什么位置等信息。这个时候可能会想着写一个循环去遍历ndarray
对象中的所有元素来进行统计。NumPy
为了解放我们的双手,提供了sum
,min
,max
,argmin
,argmax
等函数来实现简单的统计功能,代码如下:
有的时候,我们在统计时需要根据轴来统计。举个例子,公司员工的基本工资,绩效工资,年终奖的信息如下:
工号 | 基本工资 | 绩效工资 | 年终奖 |
---|---|---|---|
1 | 3000 | 4000 | 20000 |
2 | 2700 | 5500 | 25000 |
3 | 2800 | 3000 | 15000 |
这样一个表格很明显,可以用ndarray
来存储。代码如下:
info
实例化之后就有了维度和轴的概念,很明显info
是个二维数组,所以它的维度是2
。维度为2
换句话来说就是info
有两个轴:0
号轴与1
号轴(轴的编号从0
开始算)。轴所指的方向如图所示:
如果想要统计下这3
位员工中基本工资、绩效工资与年终奖的最小值与最大值(也就是说分别统计出每一列中的最小与最大值)。我们可以沿着0
号轴来统计。想要实现沿着哪个轴来统计,只需要修改axis
即可,代码如下:
PS
:当没有修改axis
时,axis
的值默认为None
。意思是在统计时会把ndarray
对象中所有的元素都考虑在内。
代码文件
import numpy as np
def get_answer(input_data):
'''
将input_data转换成ndarray后统计每一行中最大值的位置并打印
:param input_data: 测试用例,类型为list
:return: None
'''
#********* Begin *********#
a = np.array(input_data)
b = a.argmax(axis=1)
print(b)
#********* End *********#
第4关:随机数生成
相关知识
简单随机数生成
NumPy
的random
模块下提供了许多生成随机数的函数,如果对于随机数的概率分布没有什么要求,则通常可以使用random_sample
、choice
、randint
等函数来实现生成随机数的功能。
random_sample
random_sample
用于生成区间为[0, 1]
的随机数,需要填写的参数size
表示生成的随机数的形状,比如size=[2, 3]
那么则会生成一个2
行3
列的ndarray
,并用随机值填充。示例代码如下:
choice
如果想模拟像掷骰子、扔硬币等这种随机值是离散值,而且知道范围的可以使用choice
实现。choice
的主要参数是a
、size
和replace
。
代码如下:
randint
randint
的功能和choice
差不多,只不过randint
只能生成整数,而choice
生成的数与a
有关,如果a
中有浮点数,那么choice
会有概率挑选到浮点数。
randint
的参数有3
个,分别为low
,high
和size
。其中:
假如模拟5
次掷骰子,代码如下:
概率分布随机数生成
如果对于产生的随机数的概率分布有特别要求,NumPy
同样提供了从指定的概率分布中采样得到的随机值的接口。在这里主要介绍高斯分布。
高斯分布又称为正态分布,其分布图形如下:
上图中横轴为随机变量的值(在这里可以看成是产生的随机值),纵轴表示随机变量对应的概率(在这里可以看成是随机值被挑选到的概率)。
其实在日常生活中有很多现象或多或少都符合高斯分布。比如某个地方的高考分数,一般来说高考分数非常低和高考分数非常高的学生都比较少,而分数中规中矩的学生比较多,如果所统计的数据足够大,那么高考分数的概率分布也会和上图一样,中间高,两边低。
想要实现根据高斯分布来产生随机值,可以使用normal
函数。示例代码如下:
其中normal
函数除了size
参数外,还有两个比较重要的参数就是loc
和scale
,它们分别代表高斯分布的均值和方差。loc
影响的分布中概率最高的点的位置,假设loc=2
,那么分布中概率最高的点的位置就是2
。下图体现了loc
对分布的影响,其中蓝色f
分布的loc=0
,红色分布的loc=5
。
scale
影响的是分布图形的胖瘦,scale
越小,分布就越又高又瘦,scale
越大,分布就越又矮又胖。下图体现了scale
对分布的影响,其中蓝色分布的scale=0.5
,红色分布的scale=1.0
。
所以,想要根据均值为1
,方差为10
的高斯分布来生成5
个随机值,代码如下:
随机种子
前面说了这么多随机数生成的方法,那么随机数是怎样生成的呢?其实计算机产生的随机数是由随机种子根据一定的计算方法计算出来的数值。所以只要计算方法固定,随机种子固定,那么产生的随机数就不会变!
如果想要让每次生成的随机数不变,那么就需要设置随机种子(随机种子其实就是一个0
到2^32−1
的整数)。设置随机种子很长简单,调用seed
函数并设置随机种子即可,代码如下:
代码文件
import numpy as np
def shuffle(input_data):
'''
打乱input_data并返回打乱结果
:param input_data: 测试用例输入,类型为list
:return: result,类型为list
'''
# 保存打乱的结果
result = []
#********* Begin *********#
data = input_data
a = np.random.choice(data,len(data),replace=False)
for i in a:
result.append(i) #向列表末尾添加元素
#********* End *********#
return result
第5关:索引与切片
相关知识
索引
ndarray
的索引其实和python
的list
的索引极为相似。元素的索引从0
开始。代码如下:
遍历
ndarray
的遍历方式与python
的list
的遍历方式也极为相似,示例代码如下:
切片
ndarray
的切片方式与python
的list
的遍历方式也极为相似,对切片不熟的同学也不用慌,套路很简单,就是用索引。
假设想要将下图中紫色部分切片出来,就需要确定行的范围和列的范围。由于紫色部分行的范围是0
到2
,所以切片时行的索引范围是0:3
(索引范围是左闭右开);又由于紫色部分列的范围也是0
到2
,所以切片时列的索引范围也是0:3
(索引范围是左闭右开)。最后把行和列的索引范围整合起来就是[0:3, 0:3]
(,
左边是行的索引范围)。当然有时为了方便,0
可以省略,也就是[:3, :3]
。
切片示例代码如下:
代码文件
import numpy as np
def get_roi(data, x, y, w, h):
'''
提取data中左上角顶点坐标为(x, y)宽为w高为h的ROI
:param data: 二维数组,类型为ndarray
:param x: ROI左上角顶点的行索引,类型为int
:param y: ROI左上角顶点的列索引,类型为int
:param w: ROI的宽,类型为int
:param h: ROI的高,类型为int
:return: ROI,类型为ndarray
'''
#********* Begin *********#
x1 = x
y1 = y
x2 = x+h+1
y2 = y+w+1
ROI = data[x1:x2,y1:y2]
return ROI
#********* End *********#