python基础
基本数据类型
Python3的六个标准数据类型中:
- 不可变数据:Number(数字)、String(字符串)、Tuple(元组)
- 可变数据:List(列表)、Dictionary(字典)、Set(集合)
不可变指的是创建后内存内容不能再被修改,只能创建新的对象来修改
数字Number
Python 支持三种不同的数值类型:
- 整型(int),Python3整型是没有限制大小的,可以当作 Long 类型使用,布尔(bool)是整型的子类型
- 浮点型(float)
- 复数(complex),可以用
a+bj
,或者complex(a,b)
表示,复数的实部a和虚部b都是浮点型
数据类型的转换只需要将数据类型作为函数名即可
在混合计算时会把整型转换成为浮点数,+
,-
,*
和/
和其它语言里一样
数值的除法包含两个运算符:/
返回一个浮点数,//
返回一个整数(但不一定是int,和分子分母的数据类型有关)
数学常量:pi
and e
字符串String
用单引号'
或双引号"
括起来,同时使用反斜杠\
转义特殊字符,注意字符串不可变
字符串的切片:变量[头下标:尾下标],索引值以0为开始值,-1为从末尾的开始位置
可以用+
运算符连接在一起,用*
运算符重复
格式化推荐用f-string
(python3.6之后)
以f开头,后面跟着字符串,字符串中的表达式用大括号 {} 包起来,它会将变量或表达式计算后的值替换进去
用这种方式就不用再去判断使用%s
还是%d
列表List
列表是Python中使用最频繁的数据类型,写在方括号[]
之间,元素用逗号隔开
和字符串一样有索引和切片,不同的是列表中的元素是可以改变的
常用方法:(部分和c++类似)
方法 | 描述 |
---|---|
len(list) |
列表元素个数 |
list.count(obj) |
统计某个元素在列表中出现的次数 |
list.index(obj) |
从列表中找出某个值第一个匹配项的索引位置 |
list.append(obj) |
在列表末尾添加新的对象 |
list.insert(index, obj) |
将对象插入列表 |
list.extend(seq) |
在列表末尾一次性追加另一个序列中的多个值 |
list.pop([index=-1]) |
移除列表中的一个元素(默认最后一个),并且返回该元素的值 |
list.remove(obj) |
移除列表中某个值的第一个匹配项 |
list.sort(reverse=False) |
对原列表进行排序 |
list.reverse() |
反向列表中元素 |
输出小技巧:
1 | matrix = [ |
元组Tuple
与列表类似,不同之处在于元组的元素不能修改,写在小括号()
里,元素之间用逗号隔开
和列表一样有索引和切片,不同之处在于元组的元素不能修改,且数据类型可以不同
元组中的元素值不允许删除,但可以使用del
语句来删除整个元组
常用方法:(方法极少)
方法 | 描述 |
---|---|
len(tuple) |
计算元组元素个数 |
max(tuple) /min(tuple) |
返回元组中元素最大/最小值 |
集合Set
集合(Set)是一个无序、可变、不重复的元素集合,使用大括号{}
表示,元素之间用逗号分隔
3.7+中含存储顺序,但逻辑仍无序
可以进行交集、并集、差集等常见的集合操作(&
,|
,-
)
创建一个空集合必须用set()
而不是{ }
,因为{ }
是用来创建一个空字典
常用方法:(类比c++ set)
方法 | 描述 |
---|---|
set.add(x) |
为集合添加元素 |
set.remove(x) |
从集合移除元素 |
set.pop() |
随机移除元素 |
set.clear() |
移除集合中的所有元素 |
len(set) |
计算集合元素个数 |
适合用于去重、快速查找、集合关系运算
字典Dictionary
字典是一种映射类型,用{ }
标识,是一个无序的键(key):值(value)的集合
3.7+默认保持插入顺序
键(key)必须使用不可变类型,且在同一个字典中,键(key)必须是唯一的
常用方法:
方法 | 描述 |
---|---|
dict.keys() |
返回键的视图对象 |
dict.values() |
返回值的视图对象 |
dict.items() |
以列表返回视图对象 |
dict.update(dict2) |
把字典dict2的键/值对更新到dict里 |
dict.pop(key) |
删除字典key所对应的值,返回被删除的值 |
dict.get(key, default=None) |
返回指定键的值,如果不存在返回default设置的值 |
四大容器对比
特性 | 列表 list | 元组 tuple | 集合 set | 字典 dict |
---|---|---|---|---|
定义方式 | [] 或 list() |
() 或 tuple() |
{} 或 set() |
{key: value} 或 dict() |
是否有序 | 有序 | 有序 | 无序 | 有序 |
是否可变 | 可变 | 不可变 | 可变 | 可变 |
元素是否可重复 | 允许重复 | 允许重复 | 自动去重 | 键(key)唯一,值(value)可重复 |
索引访问 | 支持 | 支持 | 不支持 | 通过 key 访问 value |
适用场景 | 存放有序数据,可修改 | 固定数据,保护不被修改 | 去重、集合运算、快速查找 | 存放键值对,快速查找映射关系 |
文件操作
1 | import os |
pathlib是对os的一个改进库,建议从os慢慢转变为pathlib
在MacOS和Linux系统下,路径默认使用的都是正斜杠/
,在Windows系统下,正反斜杠都可以表示路径分隔符,默认的是反斜杠\
,由于反斜杠本身属于转义符,这可能会导致使用反斜杠表示的路径在编码时无法被正确识别。最好就是全部用正斜杆/
,避免出问题
目录
功能 | os /os.path 写法 |
pathlib 写法 |
---|---|---|
获取当前工作目录 | os.getcwd() |
Path.cwd() |
递归创建单层目录 | os.makedirs(path, exist_ok=True) |
Path(path).mkdir(parents=True, exist_ok=True) |
删除空目录 | os.rmdir(path) |
Path(path).rmdir() |
os.removedirs(path)
:递归删除空目录,从最深层的子目录开始删除,直到遇到一个非空目录或者抛出错误为止;
路径
功能 | os / os.path 写法 |
pathlib 写法 |
---|---|---|
拼接路径 | os.path.join(path1,path2) |
Path(path1) / path2 |
文件名(不含扩展名) | (很麻烦) | Path(path).stem |
文件名(含扩展名) | os.path.basename(path) |
Path(path).name |
取扩展名 | os.path.splitext(path)[1] |
Path(path).suffix |
取目录名 | os.path.dirname(path) |
Path(path).parent |
检查是否存在 | os.path.exists(path) |
Path(path).exists() |
删除文件 | os.remove(path) |
Path(path).unlink() |
遍历目录
os.listdir
列出某个目录下的文件和文件夹名(不递归),只返回名字(不带路径),需要os.path.join
拼接绝对/相对路径
Path.iterdir()
结合了os.listdir
+ os.path.join
计算文件夹下所有csv文件的平均值:(两种写法的区别只在循环开始部分)
1 | import os |
递归遍历
递归式的遍历,遍历指定目录及其子目录中的所有文件和目录
1 | os.walk(top, topdown=True, onerror=None, followlinks=False) |
1 | import os |
numpy
1 | import numpy as np |
创建和生成
array函数
1 | np.array(object, dtype = None, copy = True, order = None, ndmin = 0) |
名称 | 描述 |
---|---|
object |
数组或嵌套的数列list |
dtype |
数组元素的数据类型,可选,一般不用自己指定 |
copy |
对象是否需要复制,可选 |
order |
创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
ndmin |
指定生成数组的最小维度 |
传入复数数组:
1 | arr = np.array([[1+2j,2+3j],[3+4j,4+5j]], dtype= np.complex64) |
arange函数
1 | np.arange(start, stop, step, dtype) |
参数 | 描述 |
---|---|
start |
起始值,默认为0 |
stop |
终止值(不包含) |
step |
步长,默认为1 |
linspace函数
1 | np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) |
参数 | 描述 |
---|---|
start |
序列的起始值 |
stop |
序列的终止值,如果endpoint 为True ,该值包含于数列中 |
num |
要生成的等步长的样本数量,默认为50 |
endpoint |
该值为True 时,数列中包含stop 值,默认True |
retstep |
该值为True 时,生成的数组中会显示间距,反之不显示 |
logspace函数
1 | np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None) |
参数 | 描述 |
---|---|
start |
起始值:base ** start |
stop |
终止值:base ** stop ,如果endpoint 为True ,该值包含于数列中 |
num |
要生成的等步长的样本数量,默认为50 |
endpoint |
该值为True 时,数列中中包含stop 值,默认是True |
base |
对数log 的底数 |
ones/zeros函数
创建出来的 array 默认是 float 类型
1 | np.ones(shape, dtype = None, order = 'C') |
1 | np.zeros(shape, dtype = None, order = 'C') |
参数 | 描述 |
---|---|
shape |
数组形状 |
order |
‘C’行数组,或者’F’用于 FORTRAN 的列数组 |
random函数
最重要的API,经常用于随机生成训练或测试数据,神经网路初始化等
推荐使用新的方式生成,rng 是个 Generator,可用于生成各种分布
1 | rng = np.random.default_rng(42) # Generator(PCG64) at 0x27C7981F900 |
rng的size都有()
,np.random的不是
np.random |
rng |
|
---|---|---|
0-1 连续均匀分布 | np.random.rand(3,4) np.random.random((3,4)) |
rng.random((3,4)) |
指定上下界连续均匀分布 | np.random.uniform(-1,1,(2,3)) |
rng.uniform(-1,1,(2,3)) |
指定上下界随机整数 | np.random.randint(0,10,(2,3)) |
rng.integers(0,10,(2,3)) |
标准正态分布(0,1) | np.random.randn(2,4) |
rng.standard_normal((2,4)) |
正态分布 | np.random.normal(0,1,(3,5)) |
rng.normal(0,1,(3,5)) |
常用用的就是2个分布:均匀分布和正态(高斯)分布
数组属性
一维数组的秩为1,二维数组的秩为2
属性 | 说明 |
---|---|
arr.ndim |
数组的秩(rank),即数组的维度数量或轴的数量 |
arr.shape |
数组的维度,表示数组在每个轴上的大小 |
arr.size |
数组中元素的总个数,等于 np.shape 中各个轴上大小的乘积 |
arr.dtype |
数组中元素的数据类型 |
arr.itemsize |
数组中每个元素的大小,以字节为单位 |
arr.real |
数组中每个元素的实部(如果元素类型为复数) |
arr.imag |
数组中每个元素的虚部(如果元素类型为复数) |
统计函数
最值:
1 | arr.max(axis=0, keepdims=True) # min同理 |
参数 | 描述 |
---|---|
axis |
0为列,1为行,默认为全部 |
keepdims |
是否保持原有维度,默认False |
这个需要特别注意下,很多深度学习模型中都需要保持原有的维度进行后续计算
在统计函数这块axis
,keepdims
用法都是一样的
另一种写法(少用):
1 | np.amax(arr) |
分位数:
1 | np.median(arr) # 中位数 |
1 | np.quantile(arr, q, axis) |
1 | a = np.array([[10, 7, 4], [3, 2, 1]]) |
平均求和标准差
使用最多的是「平均值」
1 | np.average(arr) # 平均值 |
1 | np.cumsum(arr) # 累加 |
元素出现次数
1 | np.bincount(arr) |
返回不同元素出现的次数
数组操作
这小节里面的API使用非常高频,尤其是扩展1维度的 expand_dims
和去除1维度的 squeeze
,在很多神经网络架构常见
修改数组形状
reshape会生成一个新的array,但resize不会
函数 | 描述 |
---|---|
reshape() |
原数组形状不变 |
resize() |
会改变原数组形状 |
ravel() |
将多维数组展平 |
1 | arr.reshape(2,2,3) |
reshape元素数量必须与原array一致
1 | # arr1.resize(3,2) # 报错,数组内元素数量多 |
1 | # 将 refcheck 设为 False ,可以让resize超出部分设为0 |
修改数组维度
注意:无论是扩展还是缩减,无论是扩展还是缩减,多或少的 shape 都是 1
扩充维度不能跳跃
1 | rng = np.random.default_rng(42) |
squeeze
时如果指定维度,则该维度shape
必须是 1
1 | # np.squeeze(expanded, axis=0) # 报错 |
反序
如果对一个字符串或数组进行反序,一般会利用reversed
,或者利用list
的索引,这就是numpy中array的反序方式
1 | arr |
1 | arr[::-1] # 默认行反序 |
1 | # 按行反转(上下翻转) |
1 | # 按列反转(左右翻转) |
1 | # 同时行列反转 |
转置
通俗理解就是把数组放倒,shape反转,行变成列,列成为行
建议二维矩阵用 arr.T
(会快很多),超过二维的张量可以用 np.transpose
,会更加灵活些
注意:一维数组转置还是自己,不会反转
1 | arr.T |
1 | # np.transpose可以指定 axes,不指定时和T一样 |
拼接
本小节严格来说只有两个API:np.concatenate
和 np.stack
前者是拼接,后者是堆叠(会增加一个维度),都可以指定维度
vstack
和hstack
虽然看起来是stack
,但他俩本质还是concatenate
vstack
等价于 axis=0,hstack
等价于axis=1,建议只用concatenate
1 | rng = np.random.default_rng(42) |
1 | # 堆叠,默认根据 axis=0 进行 |
1 | # 堆叠,根据 axis=2 |
切片和索引
切片和索引是通过对已有 array 进行操作而得到想要的「部分」元素的行为过程
把处理按维度分开,不处理的维度统一用:
替代,也有用...
表示的,但是:
更多
索引支持负数,即从后往前索引
1 | arr[:3, 1:3] # 0-3行,1-3列 |
筛选和过滤
主要包括以下内容:
- 条件筛选
- 提取(按条件)
- 抽样(按分布)
- 最大最小 index(特殊值)
这几个内容都很重要,使用的也非常高频,条件筛选经常用于 Mask
或异常值处理,提取则常用于结果过滤,抽样常用在数据生成(比如负样本抽样),最大最小 index
则常见于机器学习模型预测结果判定中(根据最大概率所在的 index 决定结果属于哪一类)
条件筛选
核心 API 是 np.where
,返回输入数组中满足给定条件的元素的索引(元组)
需要注意的是:where
分别返回各维度的index
,赋值的是「不满足」条件的,类似三元表达式
1 | np.where(arr>50, arr, -1) # 将<=50的赋值为-1 |
提取
np.extract()
函数根据某个条件从数组中抽取元素,返回满条件的元素
1 | np.extract(condition, arr) |
提取和唯一值返回的都是一维向量
1 | np.unique(arr) # 提取唯一值,也是一种提取 |
抽样
1 | np.random.choice(a, size=None, replace=True, p=None) |
参数 | 描述 |
---|---|
a |
如果是整数表示从np.arange(a) 里抽取元素如果是一维数组直接从数组里抽取 |
size |
抽取结果的形状(默认是返回一个数),也可以是元组 |
replace |
True (默认)有放回抽样,元素可重复False 则不放回,元素不重复 |
p |
每个元素被选中的概率,和必须为1,默认均匀分布 |
如果replace=False
,那么 size
不能大于元素总数
1 | np.random.choice(1000,50,replace=False) |
最值索引
主要是np.argmax/argmin
这两个函数
1 | np.argmax(arr, axis=None) |
None
(默认)把数组展平成一维,再找最大/最小值的位置,axis=0
沿列方向,axis=1
沿行方向
np.argsort()
函数返回的是数组值从小到大的索引值
1 | np.argsort(arr, axis=-1,kind=None) |
axis
默认-1,即最后一个轴,如果设置为None则会先展平为一维再排序
kind
是排序算法,可选
种类 | 速度 | 最坏情况 | 工作空间 | 稳定性 |
---|---|---|---|---|
'quicksort' (快速排序)(默认) |
1 | O(n^2) |
0 | 否 |
'mergesort' (归并排序) |
2 | O(n*log(n)) |
~n/2 | 是 |
'heapsort' (堆排序) |
3 | O(n*log(n)) |
0 | 否 |
矩阵运算
算术
所有的算术函数均可直接运用于array,+-*/
四则运算,**
平方以及开方
功能 | numpy模块 |
---|---|
绝对值 | np.abs(x) / np.fabs(x) |
四舍五入 | np.round(x, n) |
取整 | np.ceil(x) (向上)/np.floor(x) (向下) |
对数 | np.log(x) np.log10(x) np.log2(x) |
取余 | np.mod(x, y) y 可以是数组,不同被除数 |
1 | np.minimum(arr, num) # 超过num的都置为num |
广播
广播(Broadcast)是numpy对不同形状(shape)的数组进行数值计算的方式
当运算中的2个数组的形状不同时,将自动触发广播机制
广播规则:
- 如果两个数组的维度不相同,那么小维度数组的形状将会在最左边补1
- 如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度为1的维度拓展以匹配另外一个数组形状
- 如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常
1 | a = np.array([[1, 2, 3]]) # shape (1,3) → shape(2,3) |
不能广播的情况:
1 | a = np.array([1, 2, 3]) # shape (3,) |
矩阵
dot
和 matmul
在高维度时表现不同
1 | np.dot(a, b) |
1 | np.matmul(a, b) # 等价于 a @ b |
情况 | np.dot |
np.matmul (或 @ ) |
---|---|---|
1D·1D | 向量内积(标量) | 向量内积(标量) |
2D·2D | 矩阵乘法 | 矩阵乘法 |
2D·1D | 矩阵 × 向量 → 1D | 矩阵 × 向量 → 1D |
1D·2D | 向量 × 矩阵 → 1D | 向量 × 矩阵 → 1D |
高维数组 | 只在最后两维做点积 | 支持批量矩阵乘法 |
Hadamard乘积(逐元素相乘):直接使用*
常用线性代数方法:
方法 | 描述 |
---|---|
np.linalg.det(arr) |
计算行列式 |
np.linalg.inv(arr) |
求逆矩阵(前提行列式>0) |
np.linalg.eig(arr) |
求特征值和特征向量 |
np.linalg.solve(A,b) |
求方程Ax=b |
从文件读取
加载常用数据格式 | 保存数据 |
---|---|
np.loadtxt() |
np.savetxt() |
np.fromstring() |
np.save() , np.savez() , np.savez_compressed() |
1 | np.loadtxt(fname, dtype=None, delimiter=",", comments="#", skiprows=1) |
参数 | 描述 |
---|---|
fname |
文件的路径 |
delimiter |
指定数据在文件中的分隔符,在CSV文件中通常是逗号 |
skiprows |
指示 loadtxt 函数跳过文件前n行 |
comment |
如果行的开头为"#" 则跳过 |
1 | np.fromstring(s, dtype, count=-1, sep=',') # 把字符串转换成一维数组 |
参数 | 描述 |
---|---|
s |
输入的字符串 |
delimiter |
指定数据在文件中的分隔符,在CSV文件中通常是逗号 |
count |
需要读取的元素数量,默认为-1,表示读取字符串中的所有元素 |
sep |
字符串中元素之间的分隔符,在CSV文件中通常是逗号 |
保存为文件
1 | np.savetxt(fname, arr, fmt='%s', delimiter=',', newline='\n', header='', footer='', comments='# ') |
参数 | 描述 |
---|---|
fname |
文件的路径 |
arr |
要存储的阵列数据 |
fmt |
要存储的数据格式,默认%.18e (科学记数法) |
delimiter |
加载分隔符,默认是空格 |
newline |
行分隔符,默认换行符 |
header |
开头字符串(存储为csv文件时可以生成标题) |
footer |
结尾字符串 |
comments |
文中的注释 |
1 | row_string = "20131, 10, 67, 20132, 11, 88, 20133, 12, 98, 20134, 8, 100, 20135, 9, 75, 20136, 12, 78" |
np.save()
保存一个array → .npy
np.savez()
保存多个array(同np.savez_compressed()
) → .npz
1 | np.savez(file,kwd1=arr1, kwd2=arr2) |
1 | train_data = np.array([1, 2, 3]) |
matplotlib
1 | import matplotlib.pyplot as plt |
其用法和matlab极其相似
一个完整的matplotlib图像通常会包括以下四个部分:
Figure
:用来容纳所有绘图元素,可以包含多个Axes
,可以设置画布大小、分辨率等Axes
:实际绘制数据的区域,一个Figure
可以包含多个Axes
,包含坐标轴、标题、标签等Axis
:Axes的下属层级,用于处理坐标轴、刻度、标签范围Artist
:图表中的元素:线条、点、文字、图例等
matplotlib提供了两种最常用的绘图接口:
显式创建figure和axes,直接操作Figure和Axes对象,更灵活可控,也被称为OO模式
依赖pyplot自动创建figure和axes,写法和matlab完全一致
1
2
3
4
5
6plt.plot()
plt.title()
plt.xlabel()
plt.ylabel()
plt.legend([])
plt.suptitle() # 加大标题
常见属性 | 设置 |
---|---|
颜色color |
r g b c m y k w |
线型linestyle |
'-' , '--' , '-.' , '' (只画点) |
线宽linewidth |
一般2 |
标记marker |
'o' , 's' , 'D' , '*' , '+' , 'x' |
透明度alpha |
看情况 |
文本字号、粗细、字体 | fontsize 、fontweight 、family |
字体族主要有:
- serif:Times New Roman,主要论文
- sans-serif:Arial
- monospace:Courier New,主要代码
- cursive(手写体/花体)
- fantasy(装饰体)
解决中文乱码问题:
1 | import matplotlib as mpl |
OO模式
进入OO模式的方法:
1 | fig, ax = plt.subplots() # OO 接口,创建 Figure 和 Axes |
Axes(子图)常用操作:
1 | ax.set_title("Title") # 设置标题 |
Axis(坐标轴)常用操作:
1 | ax.set_xlim(low, high) # x 轴范围 |
Artist有两种类型:primitives
和containers
primitive
是最基础的绘图对象,用于具体显示数据和形状
Artist 类型 | 描述 |
---|---|
Line2D | 折线、曲线、散点图 |
Text | 文字、标签、标题 |
Patch | 各种二维形状:矩形、圆、多边形、柱状、扇形(饼图)等 |
Collection | 一组类似元素,如散点图点集合、柱状图柱子集合等 |
Line2D
线绘制
1 | x = np.linspace(0, 2*np.pi, 100) |
多子图subplot
1 | x = np.linspace(0, 10, 100) |
散点图scatter
1 | rng = np.random.default_rng(42) |
Patch
在实际中最常见的矩形图是hist直方图
和bar条形图
二者的区别:
hist
:输入一堆数据,Matplotlib 自动分箱并统计bar
:自己提供类别 + 数值,Matplotlib 直接画出来
直方图hist
1 | import numpy as np |
条形图bar
1 | import matplotlib.pyplot as plt |
饼图pie
1 | import matplotlib.pyplot as plt |