基本语法 注释 单行:#
多行:'''或"""
1 2 3 4 a = b + c + \ d + e + \ f
变量类型 查看类型 type()查看变量类型
isinstance(a, (类型1, ...))判断是否是其中一种类型或子类
数字
int
bool(True/False)
float
complex(复数)
/返回浮点数,//返回整数的部分
字符串 单行字符串可用''或"",多行字符串可用''' '''或""" """
转义符号\
不让\生效,在引号前加r
可用+连接字符串,*重复字符串
字符串是不可改变量
切片
左闭右开
-1为末尾位置
还可加上步长,步长-1表示逆向
格式化
1 2 3 4 5 6 7 8 print ("我叫 %s 今年 %d 岁!" % ('小明' , 10 )) name = 'aaa' print (f'Hello {name} ' ) w = {'name' : 'baidu' , 'url' : 'www.baidu.com' }print (f'{w["name" ]} : {w["url" ]} ' )
列表 列表的元素是可改变的
1 2 3 4 5 6 a = [1 , 2 , 3 , 4 , 5 , 6 ]print (a[1 : 2 ]) print (a[1 :]) a[1 ] = 0 print (a)
列表操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 list1 = [1 , 2 , 3 ] list1.append(4 )print (list1) del list1[0 ]print (list1) import operator list1 = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] list2 = [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ]print (operator.eq(list1, list2))
元组 元组的元素不可以改变
可以把字符串看成特殊的元组
1 2 3 4 5 tup = (1 , ) a = (1 ) b = () print (type (tup)) print (type (a))
集合 集合的元素可变,唯一
创建可用{}或set(),空集合要用set
1 2 3 4 5 6 7 8 9 10 11 12 a = set ('abracadabra' ) b = set ('alacazam' )print (a)print (a - b) print (a | b) print (a & b) print (a ^ b)
字典 创建可用{}或dict,空字典可用{}创建
key必须为不可变类型(数字、字符串、元组、布尔等)
1 2 3 4 a = {'a' : 1 , 'b' : 2 , 'c' : 3 , 4 : 'd' }print (a) print (a['a' ]) print (a[4 ])
字典操作
1 2 3 4 5 6 7 8 d = {1 : 1 , 2 : 2 , 3 : 3 }del d[1 ]print (d) d.clear()print (d)
输入输出 1 2 3 4 5 6 price = input ("Enter price: " )print (price)print (price, end = '' )
format格式化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 print ("Hello, {}!" .format ("Alice" ))print ("Hello, {0}, you are {1} years old." .format ("Bob" , 25 ))print ("Site name: {name}, Rank: {rank}" .format (name="Google" , rank=1 )) user = {"name" : "Alice" , "age" : 18 }print ("Name: {0[name]}, Age: {0[age]}" .format (user)) data = {"site" : "Google" , "rank" : 1 }print ("Site: {site}, Rank: {rank}" .format (**data))
格式化控制符
格式符
含义
示例值
示例结果
d
十进制整数
{0:d}
42
f
浮点数(默认 6 位)
{0:f}
3.141593
.2f
保留 2 位小数
{0:.2f}
3.14
>10
右对齐,占 10 宽度
{0:>10}
text
<10
左对齐,占 10 宽度
{0:<10}
text
^10
居中,占 10 宽度
{0:^10}
text
,
千位分隔符
{0:,}
1,000,000
%
百分比(乘以 100)
{0:.2%}
25.00%
条件/循环
导入模块 导入模块的搜索路径:
当前目录
环境变量 PYTHONPATH 指定的目录
Python 标准库目录
.pth 文件中指定的目录
1 2 3 4 5 6 7 8 import sysfrom sys import argv, pathfrom sys import *
每个模块都有一个__name__属性
如果模块是被直接运行,__name__ 的值为 __main__。
如果模块是被导入的,__name__ 的值为模块名。
数学函数
abs(): 绝对值
ceil()/floor(): 向上/向下取整
round(): 四舍五入
cmp(): 比较两个数
max()/min(): 取最大/最小值
pow(): 开方
sqrt(): 平方根
错误异常 处理异常
1 2 3 4 5 6 7 8 9 10 11 try : except ExceptionType1: except ExceptionType2 as e: else : finally :
抛出异常
1 2 3 4 def sqrt (x ): if x < 0 : raise ValueError("不能对负数开平方" ) return x ** 0.5
常见异常类型
异常名
说明
ValueError
参数类型/值不合法
ZeroDivisionError
除以 0
IndexError
索引超出范围
KeyError
字典中键不存在
FileNotFoundError
打开的文件不存在
TypeError
操作/函数类型不对
NameError
使用了未定义的变量
自定义异常
1 2 3 4 5 6 7 8 9 10 class MyError (Exception ): def __init__ (self, message ): self.message = message def __str__ (self ): return self.messagetry : raise MyError("MyError" )except MyError as e: print (e)
文件 打开文件
1 f = open (file, mode='r' , encoding=None )
打开模式
模式
含义
文件不存在时行为
可读
可写
是否清空原文件
r
只读
❌ 报错
✅
❌
否
w
只写
✅ 创建新文件
❌
✅
✅ 清空
a
追加写入
✅ 创建新文件
❌
✅
❌(在末尾写)
r+
读写
❌ 报错
✅
✅
❌
w+
写读(先清空)
✅ 创建新文件
✅
✅
✅ 清空
a+
读写(追加写入)
✅ 创建新文件
✅
✅
❌(只追加)
rb/wb 等
二进制读写
适合图片、音频等
看上面
看上面
看上面
写入文件
使用with open() as f会自动关闭文件,不然要手动f.close()
1 2 3 4 5 6 7 8 with open ("test.txt" , "w" , encoding="utf-8" ) as f: f.write("Hello, world!\n" ) f.write("Second line.\n" )with open ("test.txt" , "a" , encoding="utf-8" ) as f: f.write("Appended line.\n" )
读取文件
1 2 3 4 5 6 7 8 9 10 11 12 13 with open ("test.txt" , "r" , encoding="utf-8" ) as f: content = f.read() print (content)with open ("test.txt" , "r" , encoding="utf-8" ) as f: lines = f.readlines() for line in lines: print (line.strip()) f.readline()
迭代器 访问集合元素的一种方式
可以记住遍历的位置的对象,只能往前不会后退
使用 1 2 3 4 5 6 7 8 9 10 11 a = [1 , 2 , 3 ] b = iter (a)print (next (b)) print (next (b)) print (next (b)) print (next (b)) for i in iter (a): print (i)
创建迭代器 实现__iter__()和__next__()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyNum : def __iter__ (self ): self.num = 0 return self def __next__ (self ): tmp = self.num if tmp < 20 : self.num += 1 return tmp else : raise StopIteration myclass = MyNum() it = iter (myclass)for i in it: print (i)
生成器 使用了yield的函数 被称为生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def countdown (n ): while n > 0 : yield n n -= 1 generator = countdown(5 ) print (next (generator)) print (next (generator)) print (next (generator)) for value in generator: print (value)
函数 不定长参数
1 2 3 4 5 6 7 def method (var1, *var2 ): print (var1, " " ,var2) method(1 ) method(1 , 2 ) method(1 , 2 , 3 )
1 2 3 4 5 6 7 8 9 10 11 12 def method (var1, *var2, **var3 ): print (var1) print (var2) print (var3) method(1 ,2 ,3 ,4 ,5 , a = 1 , b = 2 )''' 1 (2, 3, 4, 5) {'a': 1, 'b': 2} '''
匿名函数
作用是为了简洁,性能上和普通函数没差
1 2 3 4 5 sum = lambda arg1, arg2: arg1 + arg2print ("相加后的值为 : " , sum (10 , 20 )) print ("相加后的值为 : " , sum (20 , 20 ))
函数装饰器 函数装饰器是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数
用于不修改原函数的基础上动态地增加或修改函数的功能
类似java的注解+AOP
基本语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def decorator_function (original_function ): def wrapper (*args, **kwargs ): before_call_code() result = original_function(*args, **kwargs) after_call_code() return result return wrapper@decorator_function def target_function (arg1, arg2 ): pass
实例 :函数执行时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import timedef time_logger (func ): def wrapper (*args, **kwargs ): start_time = time.time() res = func(*args, **kwargs) end_time = time.time() print ("参数: " , args) print ("执行时间: " , end_time - start_time) return res return wrapper@time_logger def say_hello (name ): print ("Hello! " , name) time.sleep(0.5 ) say_hello("Alice" )
实例 :带参数的装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 def repeat (n ): def decorator (func ): def wrapper (*args, **kwargs ): for i in range (n): func(*args, **kwargs) return wrapper return decorator@repeat(3 ) def say_hello (): print ("Hello World!" ) say_hello()
类装饰器 类装饰器用于动态修改类行为
实例 :实现类的单例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class SingletonDecorator : """类装饰器,使目标类变成单例模式""" def __init__ (self, cls ): self.cls = cls self.instance = None def __call__ (self, *args, **kwargs ): """拦截实例化过程,确保只创建一个实例""" if self.instance is None : self.instance = self.cls(*args, **kwargs) return self.instance@SingletonDecorator class Database : def __init__ (self ): print ("Database 初始化" ) db1 = Database() db2 = Database()print (db1 is db2)
面向对象 构造方法 __init()__,创建对象时自动调用
不写默认是个空的构造方法
1 2 3 4 5 6 7 8 class Person : def __init__ (self, name, age ): self.name = name self.age = age p = Person("John" , 22 )print (p.age)print (p.name)
类方法 类方法用def定义,且第一个参数要为self
继承 子类继承父类的属性和方法
子类里可用super().来调用父类的方法
1 2 3 4 5 6 7 8 9 10 11 class Animal : def speak (self ): print ("动物在叫" )class Dog (Animal ): def bark (self ): print ("汪汪汪" ) d = Dog() d.speak() d.bark()
多继承 时决定调用哪个类的方法,按从左到右的优先级
即先找自己,在从左到右找父类(如果父类也有父类,则会顺着它的父类找上去)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class A : def hello (self ): print ("A" )class B (A ): def hello (self ): print ("B" )class C (A ): def hello (self ): print ("C" )class D (B, C): pass D().hello()
私有属性和方法 定义:在属性或方法前加__
私有属性和方法只能在本类中访问
python的私有并不是真的私有,只是改了其名字,变为_类型__属性名
1 2 3 4 5 6 7 8 9 10 11 12 13 class Person : def __init__ (self, name, age ): self.__name = name self.__age = age def __say_secret (self ): print ("这是一个秘密" ) def show (self ): print (f"{self.__name} , {self.__age} " ) self.__say_secret()print (Person("Tom" , 20 ).show())
魔法方法 魔法方法是 Python 自动调用的一些特殊方法
方法
作用
__init__(self, ...)
构造函数,创建对象时调用
__new__(cls, ...)
真正创建对象的方法,__init__ 前执行(用于元类)
__del__(self)
析构函数,删除对象时调用
__str__()
print(obj) 时调用
__repr__()
解释器或 repr(obj) 时调用
运算符重载
方法
对应操作
__add__
+ 加法
__sub__
- 减法
__mul__
* 乘法
__eq__
== 比较
__lt__
< 小于
多线程 Python的多线程是并发 的,而非真正的并行
CPython使用全局解释器锁(GIL)来保证线程安全,即同一时刻只有一个线程可以执行Python字节码。即使有多核CPU,GIL也会阻止多线程的并行 执行
通过threading模块来使用多线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import threadingimport timedef say_hello (): for i in range (3 ): print (f"线程 {threading.current_thread().name} 打招呼" ) time.sleep(1 ) t1 = threading.Thread(target=say_hello, name='T1' ) t2 = threading.Thread(target=say_hello, name='T2' ) t1.start() t2.start() t1.join() t2.join()print ("主线程结束" )
功能
说明
Thread(target=...)
创建线程并指定要执行的函数
start()
启动线程
join()
阻塞,直到被调用线程终止
current_thread()
获取当前线程信息
Lock()
创建互斥锁,防止多线程同时修改共享数据
enumerate()
返回一个包含正在运行的线程的列表
active_count()
返回正在运行的线程数量
守护线程
主线程会等待普通线程结束后才结束,而不会等待守护线程
要在start()前设置t.daemon = True才为守护线程
适合做后台服务或辅助任务
线程同步 互斥锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import threading count = 0 lock = threading.Lock()def add (): global count for _ in range (100000 ): with lock: count += 1 t1 = threading.Thread(target=add) t2 = threading.Thread(target=add) t1.start() t2.start() t1.join() t2.join()print ("count:" , count)
可重入锁
threading.RLock()
支持一个线程加多次锁,适合递归或多个函数都加锁时
信号量
1 2 3 4 5 6 7 8 9 import threadingimport time sem = threading.Semaphore(3 ) def task (): with sem: print (threading.current_thread().name, "进入" ) time.sleep(2 )
线程通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import threadingimport time event = threading.Event()def worker (): print ("等待事件触发..." ) event.wait() print ("事件已触发,开始工作" ) t = threading.Thread(target=worker) t.start() time.sleep(3 )print ("触发事件!" ) event.set ()
JSON 通过dump()转换为json格式,load()读取json
1 2 3 4 5 6 7 8 9 10 11 import json data = {'name' : 'Bob' , 'age' : 30 , 'is_student' : True }with open ('data.json' , 'w' ) as f: json.dump(data, f, indent=4 , ensure_ascii=False )with open ('data.json' , 'r' ) as f: data = json.load(f) print (data)
Numpy
NumPy 是一个用于处理数组的 Python 库。
创建数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import numpy as np ar1 = np.array([1 , 2 , 3 ])print (ar1) ar2 = np.array([1.0 , 2 , 3 ])print (ar2) arr1 = np.ones((3 , 3 )) print (arr1)print (arr1.shape) print (arr1.reshape((1 , -1 ))) print (arr1.reshape(-1 )) arr1 = np.arange(1 , 10 )print (arr1) arr1 = np.random.random(3 )print (arr1) arr1 = np.random.normal(0 , 1 , 100 )print (arr1)
访问数组 1 2 3 4 5 6 7 arr1 = np.array( [[1 , 2 , 3 ], [4 , 5 , 6 ]])print (arr1[0 , 1 ])print (arr1[ [0 , 1 ], [1 , 2 ] ])
数组操作 切片
numpy的切片仅是原数组的视图,原python的是拷贝。要拷贝用数组.copy()
1 2 3 4 5 6 7 8 9 10 arr1 = np.arange(1 , 21 ).reshape(4 , 5 )print (arr1)print (arr1[1 :3 , 1 :-1 ])
翻转 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import numpy as np arr1 = np.arange(10 ) arr1 = np.flipud(arr1)print (arr1) arr1 = np.arange(1 , 21 ).reshape(4 , 5 ) arr1 = np.fliplr(arr1)print (arr1) arr1 = np.flipud(arr1)print (arr1)
转置
重塑 1 2 arr2 = arr1.reshape((3 , 4 ))
拼接 1 2 3 4 5 6 7 8 9 10 arr1 = np.array([1 , 2 , 3 ]) arr2 = np.array([4 , 5 , 6 ])print (np.concatenate((arr1, arr2))) arr1 = np.array([[1 , 2 , 3 ], [4 , 5 , 6 ]]) arr2 = np.array([[7 , 8 , 9 ]])print (np.concatenate((arr1, arr2)))
截断 1 2 3 4 5 6 7 8 9 10 11 arr1 = np.array([1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ])print (np.split(arr1, (2 , 4 ))) arr1 = np.arange(8 ).reshape(2 , -1 )print (np.split(arr1, (1 , ), axis=1 ))
矩阵运算 相乘 1 2 3 4 5 6 7 8 9 10 arr1 = np.arange(5 ) arr2 = np.arange(5 )print (np.dot(arr1, arr2)) arr1 = np.arange(5 ) arr2 = np.arange(15 ).reshape(5 , 3 )print (np.dot(arr1, arr2))
数学函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 arr1 = np.array((-10 , 0 , 10 ))print (np.abs (arr1)) np.sin(arr1) np.cos(arr1) np.tan(arr1) np.exp() print ("2^x = " , 2 ** arr1) np.log(arr1)print ("log2(x) = " , np.log(arr1) / np.log(2 )) arr1 = np.array(((2 , 4 , 6 ), (1 , 2 , 3 )))print (np.max (arr1, axis=0 ))
布尔 1 2 3 4 5 6 7 8 9 10 11 12 arr1 = np.array((False , False , True ))print (np.any (arr1)) print (np.all (arr1)) arr1 = np.array((1 , 2 , 3 ))print (arr1[ arr1 > 1 ]) arr1 = np.array((1 , 2 , 3 ))print (np.where(arr1 > 1 ))
Pandas
Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据。可以看做是numpy的扩展
创建数据结构 Series
和字典有点像,但这个是有序的,且key可重复
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pd dict_v = {'a' : 0 , 'b' : 0.25 , 'c' : 0.75 , 'd' : 1 } sr = pd.Series(dict_v)print (sr) k = ['a' , 'b' , 'c' , 'd' ] v = [0 , 0.25 , 0.75 , 1 ] sr = pd.Series(data=v, index=k)print (sr)
DataFrame
类似二维表格
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 v1 = [53 , 64 , 72 , 82 ] v2 = ['女' , '男' , '女' , '男' ] i = ['1号' , '2号' , '3号' , '4号' ] sr1 = pd.Series(v1, index=i) i[3 ] = '6号' sr2 = pd.Series(v2, index=i) df = pd.DataFrame({'年龄' : sr1, '性别' : sr2})print (df) v = np.array([ [53 , '女' ], [64 , '男' ], [72 , '女' ], [82 , '男' ] ]) i = ['1号' , '2号' , '3号' , '4号' ] c = ['年龄' , '性别' ] df = pd.DataFrame(v, index=i, columns=c)print (df)
访问 Series 如果key是数字的话,会和下标混淆,所有可以用loc显示索引(key),iloc隐式索引(下标)
1 2 3 4 5 6 7 8 9 10 11 k = ['a' , 'b' , 'c' , 'd' ] v = [0 , 0.25 , 0.75 , 1 ] sr = pd.Series(data=v, index=k)print (sr['c' ])print (sr.loc['c' ])print (sr['a' :'c' ])print (sr[0 :2 ])
DataFrame 必须使用索引器
1 2 3 4 5 6 7 8 9 10 11 12 v = np.array([ [53 , '女' ], [64 , '男' ], [72 , '女' ], [82 , '男' ] ]) i = ['1号' , '2号' , '3号' , '4号' ] c = ['年龄' , '性别' ] df = pd.DataFrame(v, index=i, columns=c)print (df.iloc[0 ][0 ])print (df.loc['1号' ]['年龄' ])print (df.loc['1号' :'3号' , '年龄' ])
对象变形 转置 1 2 3 4 5 6 7 v = [[53 , 64 , 72 , 82 ], ['女' , '男' , '女' , '男' ]] i = ['年龄' , '性别' ] c = ['1号' , '2号' , '3号' , '4号' ] df = pd.DataFrame(v, index=i, columns=c)print (df.T)
翻转 1 2 3 4 print (df.T.iloc[: : -1 , :])print (df.T.iloc[:, : : -1 ])
重塑 1 2 3 4 5 6 7 8 9 10 11 12 i = ['1号' , '2号' , '3号' , '4号' ] v1 = [10 , 20 , 30 , 40 ] v2 = ['女' , '男' , '女' , '男' ] v3 = [1 , 2 , 3 , 4 ] sr1 = pd.Series(v1, index=i) sr2 = pd.Series(v2, index=i) sr3 = pd.Series(v3, index=i) df = pd.DataFrame({'年龄' : sr1, '性别' : sr2}) df['拍照' ] = sr3print (df)
合并 1 2 3 4 pd.concat({sr1, sr2}, axis = 0 ) pd.concat({sr1, sr2}, axis = 1 )
缺失值 找缺失值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import pandas as pd k = [1 , 2 , 3 , 4 ] v = [1 , 2 , 3 , None ] sr = pd.Series(v, index=k)print (sr.isnull()) v = [ [None , 1 ], [64 , None ], [72 , 3 ], [82 , 1 ]] i = [ '1号' , '2号' , '3号' , '4号' ] c = [ '年龄' , '牌照' ] df = pd.DataFrame(v, index=i, columns=c)print (df.isnull())
剔除缺失值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 k = [1 , 2 , 3 , 4 ] v = [1 , 2 , 3 , None ] sr = pd.Series(v, index=k)print (sr.dropna()) v = [ [None , 1 ], [64 , None ], [72 , 3 ], [82 , 1 ]] i = [ '1号' , '2号' , '3号' , '4号' ] c = [ '年龄' , '牌照' ] df = pd.DataFrame(v, index=i, columns=c)print (df.dropna()) print (df.dropna(how='all' ))
填充缺失值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 k = [1 , 2 , 3 , 4 ] v = [1 , 2 , 3 , None ] sr = pd.Series(v, index=k)print (sr.fillna(0 )) v = [ [None , 1 ], [64 , None ], [72 , 3 ], [82 , 1 ]] i = [ '1号' , '2号' , '3号' , '4号' ] c = [ '年龄' , '牌照' ] df = pd.DataFrame(v, index=i, columns=c)print (df.fillna(0 ))
Excel 导入Excel 1 2 3 4 5 import pandas as pd df = pd.read_csv('test.csv' , index_col=0 , encoding='gbk' )
读取数据 1 2 3 4 5 6 7 8 9 print (df.head()) df.max () df.min () df.mean() df.std() df.sum () df.describe()
数据透视 1 2 3 4 5 6 7 8 9 10 11 df.pivot_table(列名1 , index=列名2 ) df.pivot_table(列名1 , index=列名2 , columns=列名3 ) pd.cut( df['年龄' ], [0 , 25 , 125 ]) pd.qcut( df['费用' ], 2 )
Matplotlib 绘图基础 绘制图像 绘制一条线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import matplotlib.pyplot as plt x = [1 , 2 , 3 , 4 , 5 ] y = [1 , 8 , 27 , 64 , 125 ] Fig1 = plt.figure() plt.plot(x, y) Fig2 = plt.figure() ax2 = plt.axes() ax2.plot(x, y) Fig2.show()
绘制多条线
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import matplotlib.pyplot as plt x = [1 , 2 , 3 , 4 , 5 ] y1 = [1 , 2 , 3 , 4 , 5 ] y2 = [0 , 0 , 0 , 0 , 0 ] y3 = [-1 , -2 , -3 , -4 , -5 ] Fig1 = plt.figure() plt.plot(x, y1) plt.plot(x, y2) plt.plot(x, y3) Fig1.show()
绘制多子图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import matplotlib.pyplot as plt x = [1 , 2 , 3 , 4 , 5 ] y1 = [1 , 2 , 3 , 4 , 5 ] y2 = [0 , 0 , 0 , 0 , 0 ] y3 = [-1 , -2 , -3 , -4 , -5 ] Fig1 = plt.figure() plt.subplot(3 , 1 , 1 ) plt.plot(x, y1) plt.subplot(3 , 1 , 2 ) plt.plot(x, y2) plt.subplot(3 , 1 , 3 ) plt.plot(x, y3) Fig1.show()
保存图像
图标类型 要画什么类型的图时去官网找样例改
https://matplotlib.org/stable/plot_types/index
二维图
只需要两个向量
类型
方法
线型图
plot()
散点图
scatter()
条形图
bar()
杆图
stem()
阶梯图
step()
误差图
fill_between()
堆叠图
stackplot()
网格图
需要一个矩阵
类型
方法
图像展示
imshow()
等高线
contour()
填充等高线
contourf()
统计图
需要一个矩阵
类型
方法
直方图
hist()
箱型图
boxplot()
二维直方图
hist2d()
饼图
pie()
PyTorch
DNN:Deep Neural Network,深度神经网络
张量
张量是一个 数学对象 ,可以看作是 坐标系无关的多维数据结构 ,它能在不同坐标系下转换但仍然保持物理意义。可以把张量理解为多维数组
用GPU存储张量 1 2 3 4 5 6 7 8 9 10 import torch ts1 = torch.randn(3 , 4 )print (ts1) ts2 = ts1.to('cuda:0' )print (ts2)
DNN大致原理 神经网络通过学习大量样本的输入与输出特征之间的关系,以拟合出输入与输出之间的方程。
神经网络可以分为这几步:
划分数据集
按一定比例划分为训练集和测试集。数据集的特征决定了输入层和输出层的神经元
训练网络
通过多次的前向传播和反向传播,不断调整内部参数,以拟合任意复杂函数的过程
内部参数称为参数,外部参数称为超参数
前向传播:
将输入特征通过神经网络逐层计算,最终得到输出特征
神经元节点的计算过程:
y = w1 x1 + w2 x2 + w3 x3
由于方程是线性的,因此必须在外面套一个非线性的函数σ,称为激活函数
反向传播:
经过前向传播得到预测值后,通过损失函数计算差距,通过调整参数使得损失函数变小
测试网络
使用测试集正向传播来测试准确率
使用网络
DNN的实现 查看损失函数、激活函数、层、优化算法等的文档,记得选择自己的版本:http://pytorch.org/docs/1.12/nn.html
批量梯度下降
一次性用 整个训练集 计算梯度,再更新权重
优点:
缺点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 import torchimport torch.nn as nnimport matplotlib.pyplot as pltclass DNN (nn.Module): def __init__ (self ): """ 搭建神经网络各层 """ super (DNN, self).__init__() self.net = nn.Sequential( nn.Linear(3 , 5 , ), nn.ReLU(), nn.Linear(5 , 5 , ), nn.ReLU(), nn.Linear(5 , 5 , ), nn.ReLU(), nn.Linear(5 , 3 , ), nn.ReLU() ) def forward (self, x ): """ 前向传播 """ """ 张量会自动计算梯度,不需要反向传播方法 """ y = self.net(x) return y X1 = torch.rand(10000 , 1 ) X2 = torch.rand(10000 , 1 ) X3 = torch.rand(10000 , 1 ) Y1 = ( (X1 + X2 + X3) < 1 ).float () Y2 = ( ((X1 + X2 + X3) > 1 ) & ((X1 + X2 + X3) < 2 ) ).float () Y3 = ( (X1 + X2 + X3) > 2 ).float () Data = torch.cat([X1, X2, X3, Y1, Y2, Y3], axis = 1 ) Data = Data.to('cuda:0' ) train_size = int (len (Data) * 0.7 ) tes_size = len (Data) - train_size Data = Data[torch.randperm(Data.size(0 )), :] train_Data = Data[:train_size, :] test_Data = Data[train_size:, :] model = DNN().to('cuda:0' ) loss_fn = nn.MSELoss() learning_rate = 0.01 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) epochs = 1000 losses = [] X = train_Data[:, :3 ] Y = train_Data[:, -3 :]for epoch in range (epochs): Pred = model(X) loss = loss_fn(Pred, Y) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() Fig = plt.figure() plt.plot(range (epochs), losses) plt.xlabel('epoch' ) plt.ylabel('loss' ) plt.show() X = test_Data[:, :3 ] Y = test_Data[:, -3 :]with torch.no_grad(): Pred = model(X) Pred[:, torch.argmax(Pred, axis=1 )] = 1 Pred[Pred != 1 ] = 0 correct = torch.sum ( (Pred == Y).all (1 ) ) total = Y.size(0 ) print (f'测试集精准度: {100 * correct / total} %' )
保存/导出神经网络
1 torch.save(model, 'model.pth' )
导入神经网络
1 new_model = torch.load('model.pth' )
从csv文件里导入数据
1 2 3 4 5 6 df = pd.read_csv('Data.csv' , index_col=0 ) arr = df.values arr = arr.astype(np.float32) ts = torch.tensor(arr) ts = ts.to('cuda' )
小批量梯度下降
把训练集划分成若干 小批量(mini-batch) ,每次只用一个批量计算梯度再更新。
优点:
计算效率高,比批量梯度下降快
梯度有随机性,能跳出局部最优
适合 GPU 并行计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 import numpy as npimport pandas as pdimport torchfrom torch.utils.data import Dataset, random_split, DataLoaderimport torch.nn as nnimport matplotlib.pyplot as pltclass DNN (nn.Module): def __init__ (self ): """ 搭建神经网络各层 """ super (DNN, self).__init__() self.net = nn.Sequential( nn.Linear(8 , 32 , ), nn.Sigmoid(), nn.Linear(32 , 8 , ), nn.Sigmoid(), nn.Linear(8 , 4 , ), nn.Sigmoid(), nn.Linear(4 , 1 , ), nn.Sigmoid() ) def forward (self, x ): """ 前向传播 """ """ 张量会自动计算梯度,不需要反向传播方法 """ y = self.net(x) return y model = DNN().to('cuda' )class MyData (Dataset ): def __init__ (self, filepath ): df = pd.read_csv(filepath, index_col=0 ) arr = df.values arr = arr.astype(np.float32) ts = torch.tensor(arr) ts = ts.to('cuda' ) self.X = ts[:, :-1 ] self.Y = ts[:, -1 ].reshape((-1 , 1 )) self.len = ts.shape[0 ] def __getitem__ (self, index ): return self.X[index], self.Y[index] def __len__ (self ): return self.len Data = MyData('Data.csv' ) train_size = int (0.7 * len (Data)) test_size = len (Data) - train_size train_Data, test_Data = random_split(Data, [train_size, test_size]) train_loader = DataLoader(dataset=train_Data, batch_size=128 , shuffle=True ) test_loader = DataLoader(dataset=test_Data, batch_size=64 , shuffle=False ) epochs = 500 losses = [] loss_fn = nn.BCELoss(reduction='mean' ) learning_rate = 0.005 optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)for epoch in range (epochs): for (x, y) in train_loader: Pred = model(x) loss = loss_fn(Pred, y) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() Fig = plt.figure() plt.plot(range (len (losses)), losses) plt.show()
MNIST数据集
一个0-9数字识别的数据集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 import torchfrom torch.utils.data import Dataset, random_split, DataLoaderimport torch.nn as nnimport matplotlib.pyplot as pltfrom torchvision import transforms from torchvision import datasets transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(0.1307 , 0.3081 ) ]) train_Data = datasets.MNIST( root='./dataset/mnist/' , train=True , transform=transform, download=True ) test_Data = datasets.MNIST( root='./dataset/mnist/' , train=False , transform=transform, download=True )class DNN (nn.Module): def __init__ (self ): """ 搭建神经网络各层 """ super (DNN, self).__init__() self.net = nn.Sequential( nn.Flatten(), nn.Linear(784 , 512 , ), nn.ReLU(), nn.Linear(512 , 256 , ), nn.ReLU(), nn.Linear(256 , 128 , ), nn.ReLU(), nn.Linear(128 , 64 , ), nn.ReLU(), nn.Linear(64 , 10 , ), nn.ReLU(), ) def forward (self, x ): """ 前向传播 """ """ 张量会自动计算梯度,不需要反向传播方法 """ y = self.net(x) return y model = DNN().to('cuda:0' ) train_loader = DataLoader(dataset=train_Data, batch_size=64 , shuffle=True ) test_loader = DataLoader(dataset=test_Data, batch_size=64 , shuffle=False ) loss_fn = nn.CrossEntropyLoss() learning_rate = 0.01 optimizer = torch.optim.SGD( model.parameters(), lr=learning_rate, momentum=0.5 ) epochs = 5 losses = []for epoch in range (epochs): for (x, y) in train_loader: x, y = x.to('cuda:0' ), y.to('cuda:0' ) Pred = model(x) loss = loss_fn(Pred, y) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() Fig = plt.figure() plt.plot(range (len (losses)), losses) plt.show()
CNN和DNN的区别
CNN: Convolutional Neural Network,卷积神经网络
特性
DNN(深度神经网络)
CNN(卷积神经网络)
基本单元
全连接层(每个神经元都与前一层所有神经元相连)
卷积层 + 池化层
参数量
参数多(因为全连接)
参数少(卷积核共享权重)
特征提取
人工设计特征,输入通常是向量
自动提取局部特征,适合图像/时序
输入格式
一维向量
二维/三维张量(图像:高×宽×通道)
适用场景
简单分类、回归、推荐系统
图像识别、目标检测、语音识别、NLP(部分场景)
CNN的大致原理 内部参数:卷积核
当输入数据进入卷积层后,会与卷积核(类似DNN的权重)进行卷积运算
当输入数据是二维时被称为卷积核,三维及以上时称为滤波器
内部参数:偏置
将卷积运算结果加上偏置的值
外部参数:填充
为了防止经过多个卷积层后图像越来越小,向图像的周围填充固定的数据(如0)
外部参数:步幅
使用卷积核的位置,每次往右移动1格就是步幅为1
输入和输出尺寸的关系
可通过调节步幅和尺寸来控制某层输出尺寸
多通道输出
让三维的特征多经过几个卷积层,每层都有单独的偏置
汇聚(池化)
从一个范围内提取一个特征值,不会改变通道数
平均汇聚
最大值汇聚
尺寸变换总结
汇聚只要高和宽除以步长就行
CNN模型 LeNet-5
LeNet-5 是卷积神经网络(CNN)发展史上的一个里程碑模型,1998 年提出,第一个真正成功应用在图像识别上的 CNN 架构,为后来的 AlexNet、VGG、ResNet 奠定了基础
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 import torchfrom torch.utils.data import Dataset, random_split, DataLoaderimport torch.nn as nnimport matplotlib.pyplot as pltfrom torchvision import transforms from torchvision import datasets transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(0.1307 , 0.3081 ) ]) train_Data = datasets.MNIST( root='./dataset/mnist/' , train=True , transform=transform, download=True ) test_Data = datasets.MNIST( root='./dataset/mnist/' , train=False , transform=transform, download=True ) train_loader = DataLoader(dataset=train_Data, batch_size=256 , shuffle=True ) test_loader = DataLoader(dataset=test_Data, batch_size=256 , shuffle=False )class CNN (nn.Module): def __init__ (self ): super ().__init__() self.net = nn.Sequential( nn.Conv2d(1 , 6 , kernel_size=5 , padding=2 ), nn.Tanh(), nn.AvgPool2d(kernel_size=2 , stride=2 ), nn.Conv2d(6 , 16 , kernel_size=5 ), nn.Tanh(), nn.AvgPool2d(kernel_size=2 , stride=2 ), nn.Tanh(), nn.Conv2d(16 , 120 , kernel_size=5 ), nn.Tanh(), nn.Flatten(), nn.Linear(120 , 84 ), nn.Tanh(), nn.Linear(84 , 10 ) ) def forward (self, x ): return self.net(x) model = CNN().to('cuda:0' ) loss_fn = nn.CrossEntropyLoss() learning_rate = 0.9 optimizer = torch.optim.SGD( model.parameters(), lr=learning_rate ) epochs = 5 loss_list = []for epoch in range (epochs): for (x, y) in train_loader: x, y = x.to('cuda:0' ), y.to('cuda:0' ) Pred = model(x) loss = loss_fn(Pred, y) loss_list.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() Fig = plt.figure() plt.plot(range (len (loss_list)), loss_list) plt.show() correct = 0 total = 0 with torch.no_grad(): for x, y in test_loader: x, y = x.to('cuda:0' ), y.to('cuda:0' ) Pred = model(x) _, predicted = torch.max (Pred.data, 1 ) correct += torch.sum ((predicted == y)) total += y.size(0 )print (f'精度:{100 * correct / total} %' )
AlexNet
AlexNet 是一个经典的 卷积神经网络(CNN)结构 ,由 Alex Krizhevsky 在 2012 年提出,用于图像分类。它在 ImageNet 图像识别竞赛 (ILSVRC 2012)上夺冠,把前一年的错误率从 26% 一下子降到 15% 左右 ,震惊了整个计算机视觉领域,也标志着 深度学习在视觉任务上的崛起 。
GoogLeNet
最特别的地方是 Inception 模块 (也叫“Google Inception”), 主要解决 怎么在同一层里兼顾不同大小的卷积核 的问题。
ResNet
ResNet,全称 Residual Network(残差网络) ,是 微软研究院 在 2015 年提出的 CNN 架构。 它在 ImageNet 2015 比赛里直接拿了冠军,把网络层数推到了 152 层 ,但依然能很好训练,性能远超前辈。
是一种解决深层网络退化问题的 CNN,通过“残差连接”让信息和梯度能顺畅流动,从而能训练几十甚至上百层的网络。