前言
为什么在 Python 已有 list 基础类型的状况下,还要用 NumPy 处理数据?
关于 NumPy 的优势有以下几点:
- 列表 list 的元素在系统内存中分散存储,NumPy 数组存储在一个均匀连续的内存块中;
- 缓存会直接把字节块从 RAM 加载到 CPU 寄存器中;
- NumPy中的矩阵计算可以采用多线程方式,充分利用多核 CPU 计算资源。
如果对上述内容用一个字做总结,那就是:NumPy ,快。
NumPy中的两个重要对象:ndarray(解决多维数组问题),ufunc(对数组进行处理的函数)。
ndarray
创建数组
方法:array()
。
import numpy as np
# 创建一个一维数组
arrOne = np.array([1, 2, 3, 4])
# 创建一个三维数组
arrTwo = np.array([[1, "x", 3], [2, 3, 5], [3, "y", "z"]])
print(arrOne) # 输出:[1 2 3 4]
print(arrTwo) # 输出:[['1' 'x' '3']
# ['2' '3' '5']
# ['3' 'y' 'z']]
需要注意打印arrTwo的结果,当元素中存在str类型时,int型会被转换成str型。符合“一个数组中只能存放相同类型的元素”这个概念。
创建连续数据的数组
方法:arange()
,linspace()
。
arrOne = np.arange(10, 50, 10)
print(arrOne) # 输出:[10 20 30 40]
arrTwo = np.linspace(10, 40, 4)
print(arrTwo) # 输出:[ 10. 20. 30. 40.]
arange()
的使用类似range(),即三个参数分别是:初始值,终值,步长(不包含终值)。linspace()
则表示线性等分向量,三个参数分别是:初始值,终值,元素个数(包含终值)。也就是说,linspace()的作用是在[初始值, 终值]这个区间范围内,等分出n个元素。
创建结构体数组
方法:dtype()
,array()
。(感觉还是C语言实现更自然,也许是用习惯之故)
# 可以认为是在创建一个结构体,在C语言中类似这样:
# typedef struct {
# char* name;
# int id;
# int age;
# float score;
# } structType;
structType = np.dtype({"names": ["name", "id", "age", "score"],
"formats": ["S10", "i", "i", "f"]})
# 利用 structType 结构创建结构体数据,并初始化值
students = np.array([("lily", 10271122, 18, 468.5),
("bobby", 10271123, 18, 521.0),
("joe", 10271124, 19, 472.5)], dtype=structType)
print(students) # 输出:[(b'lily', 10271122, 18, 468.5)
# (b'bobby', 10271123, 18, 521.0)
# (b'joe', 10271124, 19, 472.5)]
创建结构体数组的时候,每个完整的结构体是一个元组类型,这样做主要是为了跟多维数组区分。
访问元素
普通数组:普通数组通过下标访问即可,也可以切片的方式
arrayCommon = np.array(["z", "t", "y"]) print(arrayCommon[2]) # 输出:y print(arrayCommon[1:]) # 输出:['t' 'y'] arrayTwoDimen = np.array([[512, 1024], ["zty", "dkh"]]) print(arrayTwoDimen[1][0]) # 输出:zty
结构体数组:结构体数组则需要搭配关键字来访问元素(拿前边的 students 作为示例)
print(students[1]) # 输出:(b'bobby', 10271123, 18, 521.0) print(students[1]["name"]) # 输出:b'bobby' # 获取所有人的成绩 print(students[:]["score"]) # 输出:[ 468.5 521. 472.5]
rank、axes、axis
秩与轴是 NumPy 中一个重要概念。在 NumPy 数组中,维数称为秩(rank),一维数组的秩为 1,二维数组的秩为 2,以此类推。而每一个线性的数组称为一个轴(axes),其实秩就是描述轴的数量。
axis 是 ufunc 中的一个重要参数,有了它可以更灵活的使用 ufunc。关于它的解释知乎上有一文说得通俗易懂,推荐去看:Python · numpy · axis 。
ufunc 运算
算术运算
方法:add()
,subtract()
,multiply()
,divide()
,power()
,remainder()
,mod()
arr1 = np.array([1, 2, 3, 4])
arr2 = np.array([1, 2, 3, 4])
print(np.add(arr1, arr2)) # 对应元素相加 # 输出:[2 4 6 8]
print(np.subtract(arr1, arr2)) # 对应元素相减 # 输出:[0 0 0 0]
print(np.multiply(arr1, arr2)) # 对应元素相乘 # 输出:[ 1 4 9 16]
print(np.divide(arr1, arr2)) # 对应元素相除 # 输出:[ 1. 1. 1. 1.]
print(np.power(arr1, arr2))
# 右边数组中的元素 作为 左边数组中元素的次方 # 输出:[ 1 4 27 256]
print(np.remainder(arr1, arr2))
# 左边元素对右边元素取余,也可以用np.mod(),结果一样 # 输出:[0 0 0 0]
计算最大最小
方法:amax()
,amin()
arr1 = np.array([1, 4, 3, 2])
print(np.amax(arr1)) # 数组中最大值 # 输出:4
print(np.amin(arr1)) # 数组中最小值 # 输出:1
arr2 = np.array([
[1, 2, 10, 1],
[3, 11, 1, 2],
])
print(np.amax(arr2)) # 输出:11
print(np.amax(arr2, 0)) # 输出:[ 3 11 10 2]
# axis = 0, 将[1, 3] [2, 11] [10, 1] [1, 2] 看作4个元素
print(np.amax(arr2, 1)) # 输出:[10 11]
# axis = 1, 将[1, 2, 10, 1] [3, 11, 1, 2] 看作2个元素
统计最大最小值的差
方法:ptp()
arr1 = np.array([1, 4, 3, 2])
arr2 = np.array([
[1, 2, 10, 1],
[3, 11, 1, 2],
])
print(np.ptp(arr1)) # 输出:3
print(np.ptp(arr2)) # 输出:10
print(np.ptp(arr2, 0)) # 输出:[2 9 9 1]
print(np.ptp(arr2, 1)) # 输出:[ 9 10]
统计数组的百分位数
方法:percentile()
arr1 = np.array([1, 4, 3, 2])
print(np.percentile(arr1, 20)) # 输出:1.6
公式:$(最大 - 最小)* 占比 + 最小 $ 。这里的占比是20%。
中位数与平均数
方法:median()
,mean()
arr1 = np.array([1, 4, 3, 2])
arr2 = np.array([
[1, 2, 10, 1],
[3, 11, 1, 2],
])
print(np.median(arr1)) # 输出: 2.5
print(np.median(arr2, 0)) # 输出:[ 2. 6.5 5.5 1.5]
# 说明
mean()表示平均数,用法与median()相似
加权平均值
方法:average()
arr1 = np.array([1, 2, 3, 4])
wts = [1, 2, 3, 4] # 迭代类型即可
print(np.average(arr1, weights=wts)) # 输出:3.0
# 为每个元素设置权重,如果不设置,默认每个元素的权重相同
print(np.average(arr1)) # 输出:2.5
方差与标准差
var(),std()
arr1 = np.array([1, 2, 3, 4])
print(np.std(arr1)) # 输出:1.11803398875
print(np.var(arr1)) # 输出:1.25
方差公式:$((x1 - avg)^2 + (x2 - avg)^2 + (x3 - avg)^2 + ...) / n$
NumPy 排序
sort() 函数,sort(a, axis=-1, kind=‘quicksort’, order=None)
,默认情况下使用快速排序:
- kind,可指定排序类型: quicksort、mergesort、heapsort 分别表示快速排序、合并排序、堆排序;
- axis 默认 -1,即沿着数组的最后一个轴进行排序,也可以取不同的 axis 轴,或者 axis=None 代表采用扁平化的方式作为一个向量进行排序;
order 字段,对于结构化的数组可以指定按照某个字段进行排序。
arr2 = np.array([ [1, 11, 9], [2, 1, 5], [5, 1, 1], ]) print(np.sort(arr2, axis=None)) # 全部元素参与排序 # 输出:[ 1 1 1 1 2 5 5 9 11] print(np.sort(arr2, axis=-1)) # 沿数组最后一个轴排序 # 输出: # [[ 1 9 11] # [ 1 2 5] # [ 1 1 5]] print(np.sort(arr2, axis=0)) # 输出: # [[ 1 1 1] # [ 2 1 5] # [ 5 11 9]] print(np.sort(arr2, axis=1)) # 输出: # [[ 1 9 11] # [ 1 2 5] # [ 1 1 5]]
由于上述二维数组 axis 最大 = 1,因此 axis = 1与 axis = -1 具有相同效果。
总结
感谢
- 参考极客时间数据分析实战45讲 - 用NumPy快速处理数据
- 参考知乎专栏Python · numpy · axis
还不快抢沙发