具体原文见连接:https://github.com/charleson98/internlm_python_tutorial/blob/main/internlm_summer_camp_python_tutorial.ipynb
一、Python基础
1.运算符
算数运算符://(整除且只保留整数),**(幂运算)
逻辑运算符:and,or,not(different from c++)
Python中基本数据类型:
可以修改的是:列表list,集合set,字典Dictionary
不可以修改的是:数字Number(分为int,float,complex),布尔型bool,元组tuple(应该还有字符串)
2.列表
(1)Def:一个有索引的序列,索引从0开始。
一个有序的可重复元素序列。
列表是可变的,列表中的元素可以重复,可以是不同的类型。
(2)创建方法: 1.alist = [1,2,3,4,5,6] #列表使用[]表示,每个元素之间用,隔开
2.blist = list("hello world!") #列表也可以使用list()函数将其他可迭代的对象转换为列表,比如字符串
(3)访问元素: 1.索引:正向从0-len(alist)~1,反向从-len(alist)~-1(注意range(a,b)函数是从a~b-1)
2.切片:list_name[start_index:end_index:step](注意step缺省为1,start默认第一个元素,end默认最后一个)
同时需要注意,截取的部分索引范围为:start_index~end_index-1,即不包括end_index
eg:print('获取所有索引为偶数的元素')
print('alist[::2]: ',alist[::2])
(4)运算符:+:拼接两个列表,eg:alist+blist
*:列表*整数,将列表重复,eg:alist*3
in:用于判断某元素是否在列表内,eg:3 in alist
(5)函数:len(alist),max(alist),min(alist) (函数参数为列表)
(6)方法:(有点类似c++结构体/类的内部函数调用)
方法名 描述 返回值
list.append(obj) 在列表末尾添加新元素 无,原地操作
list.count(obj) 统计一个元素在列表中出现的次数 返回该元素出现的次数
list.extend(seq) 将一个序列(eg.[11,12])中的所有元素添加到列表末尾 无,原地操作
list.index(obj) 从列表中找出某个值第一个匹配项的索引位置 返回索引
list.insert(index, obj) 将元素插入列表中的指定位置 无,原地操作
list.pop([index=-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 返回移除的元素值
list.remove(obj) 移除列表中某个值第一个匹配项 无,原地操作
list.reverse() 逆向排列列表中的所有元素 无,原地操作
list.sort(key=None,reverse=False) 对列表内元素进行排序,默认为升序 无,原地操作
list.clear() 清空列表 无,原地操作
list.copy() 复制列表 复制后的列表
其中需要注意copy(),比如alist_copy=alist,其实是将alist的地址赋给alist_copy,对其中任一操作都相当于对两个操作,而使用alist_copy=alist.copy()才是真正新建了一个新的对象,两者相互独立
3.元组(感觉和列表基本一样,除了创建方式以及不可修改)
(1)Def:元组和列表很相似,但是元组创建后不可修改,若尝试修改内部元素则报错。
(2)创建方法:1.用()表示,eg:atuple = (1,2,3)
(3)访问方式:也是索引和切片,和列表一致
(4)运算符:和列表完全一致
(5)函数:和列表完全一致
4.集合
(1)Def:集合是无序的不重复的元素序列,支持交集、并集、差集等常见的集合操作。
(2)创建方法:集合的创建使用{}表示,并用,隔开,eg:aset = {1,2,3,4,5}。
注意如果需要创建一个空集合需要使用set(),eg:aset = set()。
还可以用set()将其他序列转化为集合eg:alist = [1,1,1,1,2,2,2,2,3,3,3] aset = set(alist)
(3)常用方法:
方法名称 描述 返回值
add() 为集合添加元素 无返回值,原地操作
clear() 移除集合中的所有元素 无返回值,原地操作
copy() 拷贝一个集合 返回拷贝后新创建的集合
difference() 返回多个集合的差集 返回差集结果
intersection() 返回集合的交集 返回交集结果
union() 返回两个集合的并集 返回并集结果
symmetric_difference() 返回两个集合中不重复的元素集合 返回两个集合中不重复的元素集合
isdisjoint() 判断两个集合是否包含相同的元素 bool,如果没有返回 True,否则返回 False
issubset() 判断指定集合是否为该方法参数集合的子集(eg.a.issubset(b),如果a是b的子集,则返回true) bool,如果没有返回 True,否则返回 False
issuperset() 判断该方法的参数集合是否为指定集合的子集 bool,如果没有返回 True,否则返回 False
update() 合并两个集合,传入的参数必须是一个集合 无返回值,原地操作
pop() 随机移除元素 返回被移除的元素
remove() 移除指定元素 无返回值,原地操作
discard() 删除集合中指定的元素 无返回值,原地操作
其中remove():如果元素不存在,会抛出 KeyError;discard():如果元素不存在,不会有任何错误,也不会改变集合。
5.字典
(1)Def:字典是一个无序的可以修改的序列,每一个元素都由一对key与value组成,key为对应value的索引。
key不可重复,且需要是不可变对象(可hash,即可通过hash()计算相应哈希值),可以是数字,字符串,元组等,但不能是列表。value可以重复
(2)创建方法:可以用dict()(用来创建空字典)或者{key1:value1,key2:value2,...}来创建。还记得在集合中我们提过{}能用于创建空集合(?似乎是不能),是因为{}创建的是一个空字典
eg.adict = {"list" : [1,2,3],'list2':[1,2,3],'interLM': 'LLM', 1:'summer camp',2:'internLM'}
(3)访问方式:eg.adict['list'] = [3](修改key为list的元素值,其中[3]表示创建字典)
del adict['list2'](表示删除字典中的元素)
(4)常用方法:
方法名 描述
dict.clear() 删除字典内所有元素
dict.copy() 返回一个字典的浅复制
dict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值
dict.get(key, default=None) 返回指定键的值,如果键不在字典中返回 default 设置的默认值
dict.items() 返回字典内所有的key value对
dict.keys() 返回所有的key
dict.values() 返回所有的values
dict.update(dict2) 把字典dict2的键/值对更新到dict里
pop(key[,default]) 删除字典 key(键)所对应的值,返回被删除的值。
其中fromkeys()用法举例:dict.fromkeys([1,2,3,4],0) ,则生成字典{1:0,2:0,3:,4:0}
6.字符串
(1)Def:本质上是一个不可变的元素可重复的有序序列
(2)创建方法:使用"或者'来创建,两者等价,但是"会高于'。此外,'''可以用来创建包含多行的字符串,
eg.s = '''这是第一行
这是第二行
这是第三行'''。
若字符串中有'',则可使用""创建
(3)访问方式:由于字符串本质是由字符组成的序列,所以除了不能修改,其索引和切片操作与列表一模一样。
(4)运算符:+:字符串连接
*:重复输出字符串
in:成员运算符 如果字符串中包含给定的字符返回 True
not in:成员运算符如果字符串中不包含给定的字符返回 True 'M' not in a 输出结果 True
(与列表基本一样)
(5)方法:(有点多,用的时候查)
方法名 功能描述
capitalize() 将字符串的第一个字符转换为大写
center(width, fillchar) 返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格
count(str, beg= 0,end=len(string)) 返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内str 出现的次数
endswith(suffix, beg=0, end=len(string)) 检查字符串是否以 suffix 结束,如果 beg 或者 end 指定则检查指定的范围内是否以 suffix 结束,如果是,返回 True,否则返回 False。
expandtabs(tabsize=8) 把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8
find(str, beg=0, end=len(string)) 检测 str 是否包含在字符串中,如果指定范围 beg 和 end ,则检查是否包含在指定范围内,如果包含返回开始的索引值,否则返回-1
index(str, beg=0, end=len(string)) 跟find()方法一样,只不过如果str不在字符串中会报一个异常
isalnum() 如果字符串至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False
isalpha() 如果字符串至少有一个字符并且所有字符都是字母或中文字则返回 True, 否则返回 False
isdigit() 如果字符串只包含数字则返回 True 否则返回 False..
islower() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False
isnumeric() 如果字符串中只包含数字字符,则返回 True,否则返回 False
isspace() 如果字符串中只包含空白,则返回 True,否则返回 False.
istitle() 如果字符串是标题化的(见 title())则返回 True,否则返回 False
isupper() 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False
join(seq) 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
ljust(width[, fillchar]) 返回一个原字符串左对齐,并使用 fillchar 填充至长度 width 的新字符串,fillchar 默认为空格。
lower() 转换字符串中所有大写字符为小写
lstrip() 截掉字符串左边的空格或指定字符
maketrans() 创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。
max(str) 返回字符串 str 中最大的字母
min(str) 返回字符串 str 中最小的字母
replace(old, new [, max]) 将字符串中的 old 替换成 new,如果 max 指定,则替换不超过 max 次,eg.text = text.replace(','," ").replace(':'," ").replace('.'," ")用于去点标点符号
rfind(str, beg=0,end=len(string)) 类似于 find()函数,不过是从右边开始查找.
rindex( str, beg=0, end=len(string)) 类似于 index(),不过是从右边开始
rjust(width,[, fillchar]) 返回一个原字符串右对齐,并使用fillchar(默认空格)填充至长度 width 的新字符串
rstrip() 删除字符串末尾的空格或指定字符。
split(str="", num=string.count(str)) 以 str 为分隔符截取字符串,如果 num 有指定值,则仅截取 num+1 个子字符串,eg.使用""分割,提取一句中每个单词(先将标点replace为空格)
splitlines([keepends]) 按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
startswith(substr, beg=0,end=len(string)) 检查字符串是否是以指定子字符串 substr 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查。
strip([chars]) 在字符串上执行 lstrip()和 rstrip()
swapcase() 将字符串中大写转换为小写,小写转换为大写
title() 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写
translate(table, deletechars="") 根据 table 给出的表(包含 256 个字符)转换 string 的字符, 要过滤掉的字符放到 deletechars 参数中
zfill (width) 返回长度为 width 的字符串,原字符串右对齐,前面填充0
isdecimal() 检查字符串是否只包含十进制字符,如果是返回 true,否则返回 false
要注意的是,因为字符串是不可修改的对象,所以每个修改字符串的方法都是将修改后的字符串作为一个新对象返回。
(6)格式化输出:1.使用字符串的.format()方法,并在在字符串中需要插入值的地方用{}代替,{}也可以加入变量名,方便赋值,若没有加入变量名,则按顺序填入。
2.使用python在3.6推出的f-sting功能,只需在字符串开头加上f,该字符串中的{}中的python代码就会被评估。
eg1:student = {'name':'小明','age':12,'class':"书生浦语实战营第二期",'grade':'优秀学员'}
string_templet = '{}在{}岁的时候参加了{},获得了{}。'#做一个模板
print(string_templet.format(student['name'],student['age'],student['class'],student['grade']))
#在模板中没有指定变量名时, .format方法就按照顺序来填入值下面来演示一下加入变量名后会有什么不同
string_templet2 = "{name}在{age}岁的时候参加了{course},获得了{grade}。"#做一个模板
print(string_templet2.format(grade=student['grade'],name=student['name'],age=student['age'],course=student['class']))
#使用这种变量方法命名时, format就可以忽略format参数中的顺序了,对于一些特别长变量特变多的模板来说更清晰。
eg2:student = {'name':'小明','age':12,'class':"书生浦语实战营第二期",'grade':'优秀学员'}
string_out = f"{student['name']}在{student['age']}岁的时候参加了{student['class']},获得了{student['grade']}。"
print(string_out)
print(f"{1+2}")
感觉法1更易泛化,每次往模板里“填词”就行,法2更灵活一点。
7.控制结构
if-else语句:(相比c++ if(){},看起来更简洁,且c++中无elif,要注意elif在python中的使用)
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3
8.循环
(1)while:
while condition:
statement
(2)for:(for循环可以遍历任何可迭代对象比如一个列表,eg.for st in ['InternLM','LLM','transformer','Shanghai']:print(st))
for <variable> in <sequence>:
<statements>
else:
<statements>
注意for循环经常和range函数搭配,其使用方法:
range(start,stop,step)函数,会生成一个可迭代的对象,以step步长生成[start,stop)。可以只写一个stop,默认从0开始,eg.range(5),对应范围为0~5。
(python的for循环不同于c++中for(循环变量;变量范围;循环条件){})
(3)列表推导式
一种方便的写法,eg:
#找出1-100内能被3整除的数
print([i for i in range(1,101) if i%3==0])
9.函数
(1)定义方法:
def 函数名(参数列表):
函数体
eg:
def hello(name):
out = 'Hello '+name
print(out)
(注意其中out为函数内部的局部变量,函数执行结束后消亡,无法再访问)
(2)参数传递
参数是可变对象(列表,集合,字典)时,传参时传递的是索引,在函数中修改该参数会作用于原对象
参数是不可变对象(数字,元组,布尔型)时,传参时会自动复制,在函数中修改该参数不会作用于原对象
类似于如果传递的地址,那么内部修改影响原来,否则内部修改不影响原来。
python中id()函数可以获取对象在内存中地址,eg.id(a)
二、Numpy基础
1.什么是Numpy?
NumPy是Python中一个强大的科学计算库,它提供了高性能的多维数组对象及这些数组的操作工具。使用NumPy,你可以轻松地进行数学和科学计算,比如线性代数、矩阵运算以及统计分布等,是数据分析和机器学习等领域的基石。Numpy array的操作与Pytorch的Tensor十分相似,了解了array对以后学习pytorch帮助很大。
简而言之就是一个计算能力很强的工具。
2.numpy Ndarry和创建数组的方式
(1)Def:
NumPy数组(ndarray)是NumPy库的核心数据结构,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray本质上是一个存放同类型元素的多维数组,其中的每个元素在内存中都有相同存储大小的区域。
(对比列表中可以含有不同类型的元素,而ndarray中元素必须同种类型)
(2)特点:
高效的内存使用:ndarray对象在内存中连续存储,这使得对数组的元素进行切片和迭代等操作非常快速,而不需要额外的内存开销。
快速执行:NumPy数组的操作是在编译后的代码中执行的,这使得NumPy操作比纯Python代码快得多。
方便易用:NumPy提供了大量数学和数值计算函数,使得数组操作非常方便。
灵活性:NumPy数组可以在不同的数据类型之间灵活转换,支持整数、浮点数、复数等多种数据类型。
(3)创建方法:
1-创建numpy数组最常见的方法就是将一个列表使用np.array()函数转成ndarray。
eg.array1 = np.array([1,2,3]) (注意要先import numpy as np导入numpy库)
array2 = np.array([[1,2],[3,4]])(此为二维数组,[]内为每行的元素)
其中np.array()函数的具体参数为np.array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0,like=None),其中dtype为array中元素类型
array的常用属性:数据类型dtype,数组维度ndim,array形状shape(比如两行两列矩阵则为(2,2)),array元素个数size
2-一些很方便创建数组的numpy内的函数(dtype均为可选参数):
np.empty(shape,dtype)创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组
np.zeros(shape,dtype)创建指定形状(shape),数组元素以 0 来填充
np.ones(shape,dtype)创建指定形状(shape),数组元素以 1 来填充
np.zeros_like(array,dtype)创建一个与给定数组具有相同形状的数组,数组元素以 0 来填充
np.ones_like(array,dtype)创建一个与给定数组具有相同形状的数组,数组元素以 1 来填充
形状的维度解释:
一维数组:形状为 (N,),其中 N 是数组中的元素数量。
二维数组:形状为 (M, N),其中 M 是行数,N 是每行的列数。
多维数组:形状为 (D1, D2, ..., Dn),其中 D1, D2, ..., Dn 分别是每个维度的大小。
3-从数值范围创建数组
类似于python的range()函数,numpy中也有类似函数生成数组:
np.arange(start, stop, step, dtype),他的使用方法与range()一模一样。
此外,numpy还提供一个构建等差数列的函数,只需要设定start和stop,以及要生成的等步长样本数量Num。
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
其中:
start 序列的起始值
stop 序列的终止值,如果endpoint为true,该值包含于数列中
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中包含stop值,反之不包含,默认是True。
retstep 如果为 True 时,生成的数组中会显示间距,反之不显示。
dtype ndarray 的数据类
(4)数组操作:
1-数组运算与广播机制
numpy array之前的运算均为元素位置一一对应进行计算,需要两个数组维数相同,且各维度的长度也相同。
此外,numpy的广播机制还可以把该条件放宽到两个数组在某个维度上的长度相同即。
2-广播机制
NumPy的广播机制是NumPy库中一个非常强大的功能,它允许我们对形状不完全相同的数组进行算术运算。
在广播过程中,NumPy会自动调整数组的形状,以便它们可以在元素级别上进行运算。
这种机制使得NumPy在进行数组操作时更加灵活和高效。
简而言之就是一种可以对形状不同的数组运算的机制。
其基本规则:
规则一:维度对齐
如果两个数组的维度数不同,较小的数组会在其前面补1,直到两个数组的维度数相同。
维度对齐后,从最后一个维度(也称为“后缘维度”)开始比较两个数组的形状。
规则二:兼容维度
如果两个数组在某个维度上的大小相同,或者其中一个数组在该维度上的大小为1,则这两个数组在该维度上是兼容的。
如果两个数组在所有维度上都是兼容的,那么它们就可以进行广播。
规则三:输出形状
广播后的输出数组的形状是输入数组形状在各个维度上的最大值。
3-修改数组形状
*ndarray.reshape(newshape, order='C')不改变数据的条件下修改形状:
newshape:整数或者整数数组,新的形状应当兼容原有形状
order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。
返回修改好形状的数组,并不直接对原数组进行修改
*ndarray.flatten(order='C')将数组展平成一维数组
4-翻转数组
对于二维数组就是转置,但对于更高维的数组可以指定axes列表来确定维度的变化。
原始数组的维度[0,1,2],可以指定axes为[0,2,1]从而将最后一维放到中间。
eg:
array1 = np.array([[1,2,3],[4,5,6]])
print('array1.traspose() 等价于array1.transpose([1,0]) \n'\
,array1.transpose())
5-修改数组维度
numpy有两个常用的修改数组维度的函数,一个用于增加维度一个用于减少维度。
修改数组维度经常会在进行高维tensor计算时用于对其维数用到,经过增加一维或者减少一维数来实现。
*增加维度:
numpy.expand_dims(arr, axis)通过在指定位置插入新的轴来扩展数组形状
其中:arr:输入数组
axis:新轴插入的位置
*减少维度:
numpy.squeeze(arr, axis)从给定数组的形状中删除一维的条目
6-拼接数组
共四个函数:
numpy.concatenate(arrays,axis)沿指定轴连接相同形状的两个或多个数组
arrays:(a1,a2,a3...)相同类型的数组
axis:沿着它连接数组的轴,默认为 0
numpy.stack(arrays, axis)沿新轴连接数组序列
arrays相同形状的数组序列
axis:返回数组中的轴,输入数组沿着它来堆叠
numpy.hstack(arrays) np.concatenate的特殊情况,相当于axis=1,通过水平堆叠来生成数组
numpy.vstack(arrays) np.concatenate的特殊情况,相当于axis=0,通过垂直堆叠来生成数组
所有用于拼接的数组在拼接的轴上长度必须相同
7-索引和切片
numpy数据一样有索引与切片,只是其索引的写法与嵌套列表可能会有一点点不一样。
numpy的索引用[]表示,用,隔开每个轴上的索引,比如对于一个二位数组要取第i行第j列的元素的索引就为[i,j]
在索引切片上numpy数组依旧遵循start:stop:step格式,在每个轴上的切片用,隔开。:或者...可以表示取整个轴上的全部元素
eg.print("取array1每一行前两个元素,array1[0,:2]=\n",array1[...,:2])
(5)排序条件筛选
*ndarray.sort(axis=-1, kind=None, order=None)
axis: 沿着它排序数组的轴,如果没有数组会被展开,沿着最后的轴排序, axis=0 按列排序,axis=1 按行排序
kind: 默认为'quicksort'(快速排序)
order: 如果数组包含字段,则是要排序的字
*ndarray.argmax(axis)与ndarray.argmin(axis)是求数组对应轴上最大或者最小的元素的索引。
*numpy数组也支持比较运算,运算结果为bool numpy数组。可以使用np.where()获取其中为true的元素的索引,比如二维数组,那么每个维度的索引分别存在一个array中返回。
eg.array1 = np.random.randint(1,10,(3,4))
np.where(array1>1)
(6)数学函数
numpy内置了非常多的数学函数,可以直接应用于numpy数组对每一个元素做映射。
常见的函数有np.sin(),np.cos(),np.tan(),np.log()等。
此外,还有np.mean(),np.median(),np.std()等统计函数。
对于取整函数,numpy有np.round()按小数位数四舍五入,np.ceil()向上取整,np.floor()向下取整
(7)线性代数
Numpy的核心就是高性能的矩阵运算,它还提供了线性代数计算包linalg。
ndarray.dot():array1.dot(array2.transpose()) 实现矩阵点乘(其中取array1为(3,4),array2为(4,3))
常用线性代数计算函数(其中参数均为某array):
np.linalg.det() 数组的行列式
np.linalg.inv() 计算矩阵的乘法逆矩阵
np.linalg.solve() 求解线性方程
其中求解方程举例:
A = np.array([[1, 1],
[2, -1]])
b = np.array([5, 1])
x = np.linalg.solve(A, b)