【Python数据分析】NumPy基础,看这一篇就够了!
NumPy的简介与意义
NumPy是Python的一种开源的数值计算扩展库,包含很多功能,如创建n维数组(矩阵)、对数组进行函数计算、数学计算等等。
使用
import numpt as np
进行导入。
标准的Python用List(列表)保存值,可以当作数组使用,但是因为列表中元素可以是任何对象,就导致了CPU运算时间和内存会大大增长。NumPy的出现弥补了这一缺点,它提供了两种基本的对象:
ndarray
:存储单一数据类型的多维数组ufunc
:一种能够对数组进行处理的函数
这两种对象完美解决了由于任何对象带来的时间和空间的问题,大大提高了运行效率。
NumPy多维数组
创建数组对象
1.使用array创建数组对象
使用array
函数进行数组对象的创建。
array(object,dtype,ndmin)
object
:想要创建的数组名
dtype
:所需的数据类型,未给定则选择保存对象所需的最小类型,默认为None
ndmin
:接收int,指定最小维度n,默认为None
# 创建数组对象
data1 = [1,2,3,4] # 列表
w1=np.array(data1)
print(w1)
data2 = (1,2,3,4) # 元组
w2=np.array(data2)
print(w2)
data3 = [[1,2,3,4],[5,6,7,8]] # 多维数组
w3=np.array(data3)
print(w3)
NumPy是自动判断最合适的数据类型,并保存在dtype
中。
w4=np.array([1,2.1,3,4.5])
print(w4.dtype)
# 结果是:float64
2.专门创建数组的函数
上述效率也太慢了,每次都要自己先建个已有序列。NumPy中由专门的函数来创建数组
-
arange
类似于
range
,可指定起始值、终止值、步长,创建的数组不包含终止值warray1 = np.arange(1,2,0.2) print(warray1) # [1. 1.2 1.4 1.6 1.8] warray2 = np.arange(10) print(warray2) # [0,1,2,3,4,5,6,7,8,9]
-
linspace
若数据类型是浮点型,则由于精度原因不太可能区预测获得元素的数量,所以会选择
linspace
。指定起始值,终止值,元素个数(这里和arange不一样),并且默认是包含终止值的。
warray3 = np.linspace(0,1,5) print(warray3) # [0. 0.25 0.5 0.75 1. ]
-
logspace
它与
linspace
类似,但是是创建等比数列warray4 = np.logspace(0,1,5) print(warray4) # [ 1. 1.77827941 3.16227766 5.62341325 10. ]
-
zeros
创建指定长度或形状的全0数组
warray5 = np.zeros(4) print(warray5) # [0. 0. 0. 0.]
-
ones
创建指定长度或形状的全1数组
warray6 = np.ones(4) print(warray6) # [1. 1. 1. 1.]
-
diag
创建对角矩阵,即对角线元素为指定值或者0,其他元素为0
warray7 = np.diag([1,2,3,4]) print(warray7) # [[1 0 0 0] # [0 2 0 0] # [0 0 3 0] # [0 0 0 4]]
ndarray对象属性和数据转换
属性
主要包括以下属性:
属性 | 说明 |
---|---|
ndim | 数据轴的个数 |
shape | 数组的维度/形状 |
size | 元素个数 |
dtype | 数据类型 |
itemsize | 每个元素的字节大小 |
warray = np.array([[1,2,3],[4,5,6]])
print('秩为:',warray.ndim)
print('形状为:',warray.shape)
print('元素个数为:',warray.size)
数组的shape等属性可以自己设置。
warray.shape = 3,2
print(warray)
# [[1 2]
# [3 4]
# [5 6]]
生成随机数
格式:np.random
通常根据数据类型来进行随机数的生成。例如:
np.random.randint(low,high = None,size = None) # 生成指定范围内的随机整数
suijishu = np.random.randint(100,200,size = (2,4)) # 生成指定范围内的随机整数
print(suijishu)
# [[160 147 112 147]
# [126 168 156 138]]
因为是随机数生成,所以可能每次生成都不一样,可以使用seed
来确定一个种子。
数组变换
1.数组重塑
使用reshape
改变维度,传入的参数为新维度的元组。
其中有一个参数可以设置为-1,表是数组的维度可以通过数据本身进行自动推断。
arr1 = np.arange(8)
print(arr1)
# [0 1 2 3 4 5 6 7]
arr2 = arr1.reshape(4,2)
print(arr2)
# [[0 1]
# [2 3]
# [4 5]
# [6 7]]
arr3 = arr1.reshape(2,-1)
print(arr3)
# [[0 1 2 3]
# [4 5 6 7]]
# 数据展开
arr4 = arr3.ravel()
print(arr4)
# [0 1 2 3 4 5 6 7]
2.数组合并
合并是多个数组之间的操作,分为横向合并hstack
,纵向合并vstack
,concatenate
函数自定义合并
arr1 = np.arange(8)
print(arr1)
arr2 = arr1*2
print(arr2)
# 使用hstack
arr5 = np.hstack((arr1,arr2))
print(arr5)
# 使用vstack
arr6 = np.vstack((arr1,arr2))
print(arr6)
# concatenate的参数axis=1是横向合并,axis=0是纵向合并
arr7 = np.concatenate((arr1,arr2),axis = 1) # 横向合并
arr8 = np.concatenate((arr1,arr2),axis = 0) # 纵向合并
3.数组分割、转置和轴兑换
分割:hsplit
横向、vsplit
纵向,split
指定方向(与concatenate一样的规则)
转置:transpose
需要传入轴编号组成的元组、T属性直接进行转置
轴变换:swapaxes
数组的索引和切片
数据分析经常会选取符合条件的数据,NumPy通过数组的索引和切片进行数组元素的选取。
索引和切片操作不会影响原来的数组。
一维数组
# 索引
arr = np.arange(10)
print(arr) # [0 1 2 3 4 5 6 7 8 9]
print(arr[2]) # 2
print(arr[-1]) # 9
# 切片
print(arr[1:4]) # [1,2,3]
# 数组元素的复制
arr1 = arr[-4:-1].copy()
print(arr1) # [6 7 8]
多维数组
对于多维数组,每个维度都会有一个索引,各个维度的索引之间使用逗号分隔。
# 多维数组的索引
arr = np.arange(12).reshape(3,4)
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(arr[1,1:3]) # [5 6]
print(arr[:,2]) # [2 6 10]
print(arr[:1,:1]) # [[0]]
数组的运算
数组运算支持向量化运算。将本来需要在Python级别进行的运算放到C语言运算中,会显著提高运算速度。
数组和标量间的运算
相同维度的数组的算术运算可以直接运用到元素中。
ufunc函数
全称为通用函数,是一种能够针对数组中的所有元素进行操作的函数。
ufunc
函数以NumPy数组作为输出。
常用的ufunc函数运算
- 四则运算:加减乘除。形状必须相同,否则无法进行运算。
# 四则运算
x = np.array([1,2,3])
y = np.array([4,5,6])
z = np.array([7,8,9,10])
print(x+y) # [5 7 9]
print(x+z) # 出错
- 比较运算:返回的结果是一个布尔数组,每个元素都是每个数组对应元素的比较结果。
x = np.array([1,2,3])
y = np.array([4,5,6])
print(x<y)
# [ True True True]
- 逻辑运算:
np.any
表示逻辑“or”,np.all
表示逻辑“and”,运算结果返回布尔值。
ufunc函数的广播机制
鉴于可能会有不同形状的数组进行算术运算,有以下四条广播机制原则:
- 所有输入数组向shape最长的数组看齐,shape中不足的部分通过在前面加1进行补齐
- 输出数组的shape是输入数组shape的各个轴上的最大值
- 若输入数组的某个轴和输出数组的对应轴的长度相同或者其长度为1时,这个数组能够用来计算,否则出错
- 输入数组的某个轴长度为1时,沿着此轴运算时都用此轴上的第一组值
逻辑运算
可以使用基本逻辑运算来进行实现,但效率不高;
使用where
方法来克服:
np.where(condition,x,y)
若满足条件condition则输出x,否则输出y。
若没有x和y,则默认输出满足条件元素的坐标。
数组读/写
读/写二进制文件
NumPy提供了多种文件操作函数存取数组内容。存取格式分为两类:二进制和文本。
二进制格式又分为NumPy专用的格式化二进制类型和无格式类型。
以下是二进制文件读/写的两种方法:
NumPy.load("文件名.npy")
:从二进制文件中读取数据NumPy.save("文件名[.npy]",arr)
:以二进制格式保存数据
a = np.arange(1,13).reshape(3,4)
print(a)
np.save("arr.npy",a)
c = np.load("arr.npy")
print(c)
读/写文本文件
有以下几种主要方法:
NumPy.loadtxt(".txt",delimiter=",")
:把文件加载到一个二维数组中。NumPy.savetxt(".txt",arr,fmt="%d",delimiter=",")
:把数组写到某种分隔符隔开的文本文件中NumPy.genfromtxt(".txt",delimiter=",")
:结构化数组和缺失数据
读取CSV文件
读取CSV文件格式:
loadtxt(fname ,dtype =, comments = '#', delimiter = None, skiprows = 0, usecols = None, unpack = False, ndmin = 0, encoding = 'bytes')
主要参数及其说明见下表:
参数 | 说明 |
---|---|
fname | str,读取的CSV文件名 |
delimiter | str,数据的分隔符 |
usecols | tuple(元组),执行加载数据文件中的哪些列 |
unpack | bool,是否将加载的数据拆分为多个组,Ture表示拆,False表示不拆 |
skiprows | int,跳过多少行,一般用于跳过描述性文字 |
encoding | bytes,编码格式 |
NumPy中的数据统计和分析
由于比Python直接进行数组运算要快得多,NumPy
通常作为Python数据统计与分析的首选。
排序
排序方式分为直接排序和间接排序。
- 直接排序:对数据直接进行排序,通常使用
sort
函数进行实现 - 间接排序:根据一个或多个键值对数据集进行排序,通常使用
argsort
、lexsort
函数进行实现
直接排序
numpy.sort(a,axis,kind,order)
参数 | 说明 |
---|---|
a | 要排序的数组 |
axis | =1时是沿横轴进行排序;=0时是沿纵轴进行排序;=None时是将数组平坦化后进行排序 |
kind | 排序的算法类型,默认是快速排序(这里主要是针对不同的数组进行效率的匹配) |
order | 若数组包含字段,这里就是要排序的字段 |
# 数组的排序
# 直接排序
arr1 = np.array([1,2,5,3,7,5,3,45])
arr1.sort()
print(arr1)
# [ 1 2 3 3 5 5 7 45]
arr2 = np.array([[1,3,5,6],[5,2,3,77],[4,3,6,7]])
arr2.sort(axis = 1)
print(arr2)
# [[ 1 3 5 6]
# [ 2 3 5 77]
# [ 3 4 6 7]]
arr3 = np.array([[1,3,5,6],[5,2,3,77],[4,3,6,7]])
arr3.sort(axis = 0)
print(arr3)
# [[ 1 2 3 6]
# [ 4 3 5 7]
# [ 5 3 6 77]]
间接排序
使用argsort
、lexsort
可以在给定一个或多个键的时候得到一个由整数构成的索引数组。
也就是说可以返回原先数组元素在排序后数组的具体位置。
argsort
# 一维数组排序
a = np.array([3, 1, 4, 1, 5, 9, 2, 6])
idx = np.argsort(a)
print("一维数组排序后的索引:", idx)
print("排序后的数组:", a[idx])
# 二维数组按列排序
b = np.array([[3, 1, 4], [1, 5, 9], [2, 6, 5]])
idx2 = np.argsort(b, axis=1) # 按行排序
print("\n二维数组每行排序后的索引:\n", idx2)
一维数组排序后的索引: [1 3 6 0 2 4 7 5]
排序后的数组: [1 1 2 3 4 5 6 9]
二维数组每行排序后的索引:
[[1 0 2]
[0 1 2]
[0 2 1]]
lexsort(keys,axis)
-
keys
:排序的键数组或元组,按最后一个键优先排序,先对前面的键排序 -
axis
:指定排序的轴,默认是最后一个轴
# 按两组键排序
names = np.array(['Alice', 'Bob', 'Alice', 'Bob', 'Alice'])
ages = np.array([25, 20, 30, 25, 20])
# 按名字先排序,再按年龄排序
idx = np.lexsort((ages, names))
print("\n按名字和年龄排序后的索引:", idx)
print("排序结果:")
print("名字:", names[idx])
print("年龄:", ages[idx])
按名字和年龄排序后的索引: [4 0 2 1 3]
排序结果:
名字: ['Alice' 'Alice' 'Alice' 'Bob' 'Bob']
年龄: [20 25 30 20 25]
最终排序如下:
(Alice, 20)、(Alice, 25)、(Alice, 30)、(Bob, 20)、(Bob, 25)
重复数据与去重
在数据统计与分析中,数据去重是一个很重要的事情。在NumPy中,使用unique
(中文翻译过来也就是独一无二)来进行去重。
numpy.unique(arr, return_index=False, return_inverse=False, return_counts=False, axis=None)
参数 | 说明 |
---|---|
arr | 输入数组 |
return_index | 是否返回去重后元素的首次出现位置 |
return_inverse | 是否返回对应位置索引 |
return_counts | 是否返回每个唯一元素的出现次数 |
axis | 指定轴 |
a = np.array([3, 3, 4, 2, 2, 1, 5, 5, 5, 1])
# 基本去重
unique_elements = np.unique(a)
print("去重后的元素:", unique_elements)
# 返回元素出现位置和出现次数
unique_elements, indices, inverse, counts = np.unique(a, return_index=True, return_inverse=True, return_counts=True)
print("\n唯一元素:", unique_elements)
print("首次出现的位置:", indices)
print("在唯一数组中的对应位置:", inverse)
print("出现次数:", counts)
np.tile(A,reps)
A指的是待扩展的数组;
reps指的是扩展次数。
# 一维数组
a = np.array([1, 2, 3])
tiled_1d = np.tile(a, 3)
print("\n一维数组扩展:", tiled_1d)
# [1 2 3 1 2 3 1 2 3]
# 二维数组
b = np.array([[1, 2], [3, 4]])
tiled_2d = np.tile(b, (2, 3))
print("\n二维数组扩展:\n", tiled_2d)
# [[1 2 1 2 1 2]
# [3 4 3 4 3 4]
# [1 2 1 2 1 2]
# [3 4 3 4 3 4]]
np.repeat(a,reps,axis = None)
# 一维数组
c = np.array([1, 2, 3])
repeated_1d = np.repeat(c, 3)
print("\n一维数组重复:", repeated_1d)
# [1 1 1 2 2 2 3 3 3]
# 二维数组
d = np.array([[1, 2], [3, 4]])
repeated_2d = np.repeat(d, 2, axis=0)
print("\n二维数组按行重复:\n", repeated_2d)
# [[1 2]
# [1 2]
# [3 4]
# [3 4]]
repeated_2d_col = np.repeat(d, 2, axis=1)
print("\n二维数组按列重复:\n", repeated_2d_col)
# [[1 1 2 2]
# [3 3 4 4]]
常用统计函数
常用的统计分析函数有以下这些,可自行查看用法。
函数 | 功能 | 示例 |
---|---|---|
np.sum | 计算数组元素的总和 | np.sum(arr) |
np.mean | 计算均值 | np.mean(arr) |
np.median | 计算中位数 | np.median(arr) |
np.var | 计算方差 | np.var(arr) |
np.std | 计算标准差 | np.std(arr) |
np.min | 计算最小值 | np.min(arr) |
np.max | 计算最大值 | np.max(arr) |
np.ptp | 计算极差(最大值 - 最小值) | np.ptp(arr) |
----------- | --------------------------- | ---------------- |
np.sum | 计算数组元素的总和 | np.sum(arr) |
np.mean | 计算均值 | np.mean(arr) |
np.median | 计算中位数 | np.median(arr) |
np.var | 计算方差 | np.var(arr) |
np.std | 计算标准差 | np.std(arr) |
np.min | 计算最小值 | np.min(arr) |
np.max | 计算最大值 | np.max(arr) |
np.ptp | 计算极差(最大值 - 最小值) | np.ptp(arr) |