跳转至

数组运算

数组运算,极大地拓展了我们使用数组来解决实际问题的能力,不需要学习复杂的数学知识,在日常的使用中,跟普通的运算并无太大差别。

1 数组与标量之间的运算

通常我们把**单独的数叫做标量**,数组可以直接与标量进行计算,计算逻辑会自动传播到数组的全部元素中。我们举几个简单的例子:

# 数组与标量的加法运算
import numpy as np
arr = np.array([[1,2,3], [4,5,6]])
arr + 5
Out: 
    array([[ 6,  7,  8],
           [ 9, 10, 11]])
# 数组与标量的乘法运算
arr * 2
Out: 
    array([[ 2,  4,  6],
           [ 8, 10, 12]])

# 数组与标量的除法运算,求数组中每个元素的倒数
1 / arr
Out: 
    array([[1.        , 0.5       , 0.33333333],
       [0.25      , 0.2       , 0.16666667]])

# 数组与标量的乘方运算,求数组中每个元素的平方
arr ** 2
Out: 
    array([[ 1,  4,  9],
           [16, 25, 36]], dtype=int32)
# 求数组中每个元素的算术平方根
arr ** 0.5
Out: 
    array([[1.        , 1.41421356, 1.73205081],
           [2.        , 2.23606798, 2.44948974]])

2 数组的通用函数运算

所谓的通用函数ufunc,就是能够对数组中的每个元素进行微操,也就是元素级的函数运算。

2.1 四则运算

最简单的通用函数就是数组与数组的四则运算。但是在进行数组的四则运算的时候,我们需要保证二者的维数一样:

# 数组的减法:
arr - arr
Out:
    array([[0, 0, 0],
           [0, 0, 0]])

# 数组的乘法:
arr * arr
Out: 
    array([[ 1,  4,  9],
           [16, 25, 36]])

需要注意的是,这里的乘法是表示数组对应位置的元素相乘,并不是高等数学上的矩阵的乘法。当然了数组的加法和除法规则都类似,这里不一一举例了。总的来讲,Numpy针对常见的数组之间的运算,做了一些函数封装,一起看一下:

函数 说明
add, subtract, multiply, divide 算术四则运算,分别对应加、减、乘、除

2.2 一元函数

对数组求三角函数、求平均、求幂运算等均输入一元函数的范畴,我们把常用的一元函数列举如下,供大家查阅:

函数 说明
absfabs 计算绝对值,对于非负数值,可以使用更快的fass
sqrtsquareexp 求个元素的平方根、平方、指数ex
loglog10log2log1p 分别计算自然对数(底数为e)、底数为10的log、底数为2的log、log(1+x)
sign 计算各元素的正负号:1(整数)、0(零)、-1(负数)
ceil 计算各元素的、大于等于该值的最小整数
floor 计算各元素的、大于等于该值的最大整数
rint 将各元素值四舍五入到最接近的整数,并保留dtype
modf 把数组的小数和整数部分以两个独立的数组分别返回
isnan 判断各元素是否为空NaN,返回布尔型
coscoshsinsinhtantanh 普通型和双曲型三角函数
# 创建一个符合均值为5标准差为10的正态分布数组
arr_rnd = np.random.normal(5, 10, (3, 4))
arr_rnd
Out:
    array([[19.03116154, 13.58954268, 11.93818701,  4.85006153],
           [ 0.57122874,  4.33719914,  8.67773155, 10.15552974],
           [ 7.04757778,  6.98288594, 10.60656035, 17.95555988]])
# 对数组进行四舍五入运算。需要注意的是,结果数组仍然保留了输入数组的dtype属性
np.rint(arr_rnd)
Out:
    array([[19., 14., 12.,  5.],
           [ 1.,  4.,  9., 10.],
           [ 7.,  7., 11., 18.]])

2.3 二元函数

把常用的二元函数列举如下,供大家查阅:

函数 说明
maximumfmax 计算元素级的最大值,fmax自动忽略空值NaN
minimumfmin 计算元素级的最小值,fmin自动忽略空值NaN
greatergreater_equal 执行元素级的比较,生产布尔型数组。效果相当于>
lessless_equal 执行元素级的比较,生产布尔型数组。效果相当于
equalnot_equal 执行元素级的比较,生产布尔型数组。效果相当于==!=
logical_andlogical_orlogic_xor 执行元素级的逻辑运算,相当于执行运算符&|^

这里要提醒的是,数组运算本身并不复杂,只是套用公式的过程。但是在使用之前,大家千万要注意数组中是否有空值,空值的存在可能会导致运算结果错误甚至是报错。判断数组是否存在空值,需要使用isnan函数。

# 利用随机函数,产生2个数组
x = np.random.normal(5, 10, (3,1))
y = np.random.normal(5, 10, (3,1))
x
Out: array([ 9.5336068 ,  8.31969942, 15.20601081])
y
Out: array([22.52827938,  3.01609475,  9.03514098])
# 计算,比较元素级的最大值
np.maximum(x,y)
Out: array([22.52827938,  8.31969942, 15.20601081])
# 计算,比较元素级的最小值
np.minimum(x,y)
Out: array([9.5336068 , 3.01609475, 9.03514098])
# 计算,执行元素级的比较
np.greater(x,y)
Out: array([False,  True,  True])

3 数组的聚合函数运算

聚合函数是指对一组值(比如一个数组)进行操作,返回一个单一值作为结果的函数,比如求数组所有元素之和就是聚合函数。常见的聚合函数有:求和,求最大最小,求平均,求标准差,求中位数等。

常用的聚合函数一览表:

函数 说明
sum 求和运算
cumsum 累积求和运算
min 求最小值
max 求最大值
mean 求均值
median 求中位数
var 求方差
std 求标准差

在实际工程中,我们通常把若干个样本组成一个数组进行运算。二维数组的垂直方向定义为**axis 0****轴,水平方向为****axis 1****轴**。当我们在对Numpy进行运算时,我们把axis=0指定为垂直方向的计算,axis=1指定为水平方向的运算。

# 利用自带的随机数生成函数生成5位选手的评委打分结果,一共有7位评委。打分结果用5×7大小的数组表示
votes = np.random.randint(1, 10, (5, 7))
votes
Out: array([[8, 6, 4, 1, 6, 1, 5],
           [7, 6, 1, 9, 2, 1, 5],
           [9, 6, 8, 9, 3, 5, 4],
           [8, 5, 8, 4, 7, 9, 7],
           [6, 2, 1, 2, 1, 8, 3]])

# 总分-最高分-最低分,再求平均,即可求得最终结果
(np.sum(votes, axis=1)-np.max(votes, axis=1)-np.min(votes, axis=1))/5

Out: array([4.4, 4.2, 6.4, 7. , 2.8])

3.1 利用Numpy实现条件判断

条件判断是在计算领域非常常见的一种场景。例如我希望对上面产生的arr_rnd的数据网格进行判断,如果数据元素小于等于5,则替换成NaN。其实利用np.where函数轻松实现:

# where 函数中输入3个参数,分别是判断条件、为真时的值,为假时的值
# 在Numpy中,空值是一种新的数据格式,我们用np.nan产生空值
np.where(arr_rnd<5, np.nan, arr_rnd)
Out: array([[19.03116154, 13.58954268, 11.93818701,         nan],
           [        nan,         nan,  8.67773155, 10.15552974],
           [ 7.04757778,  6.98288594, 10.60656035, 17.95555988]])

如果还是找不到合适的函数来实现自己的目的,那不妨自己写一个,也很简单。我们只需要利用frompyfunc函数,将计算单元素的函数转换成,能对数组的每个元素进行操作的函数即可。

假设某淘宝店做批发生意,店里的人气产品A原价为20元。购买100件及以上,打6折;购买50件及以上,不到100件,打8折;购买10件及以上,不满50件,打9折;不满10件不打折。已知某天5位客户的具体购买量,求当天的营业额。方法有很多,那么今天这里给大家推荐一种基于数组的计算方法:

# 定义函数,购买x件订单,返回订单金额
def order(x):
    if x>=100:
        return 20*0.6*x
    if x>=50:
        return 20*0.8*x
    if x>=10:
        return 20*0.9*x
    return 20*x


# frompyfunc函数有三个输入参数,分别是待转化的函数、函数的输入参数的个数、函数的返回值的个数
income = np.frompyfunc(order, 1, 1)
# order_lst 为5位顾客的下单量
order_lst = [600, 300, 5, 2, 85]
# 计算当天的营业额
np.sum(income(order_lst))
Out: 12300.0

本节涉及的函数较多,在学习中大家切勿以死记硬背的心态介入学习。在数据分析学习阶段,应该是以理解加实践为主,至于函数太多记不住,那就交给时间去解决吧,用多了自然就记住了。对于偏门的函数,在应用的时候查阅即可。


最后更新: 2022年10月15日 01:02:48
创建日期: 2021年9月12日 05:55:32
Contributers: yangjh