闯关任务:Python实现WordCount
闯关任务:Vscode连接InternStudio debug笔记
VScode 连接服务器
安装 python
创建debug文件
def count_words(text):
text = text.lower()
text = text.replace(','," ").replace('!'," ").replace('.'," ").replace('\n'," ").replace('?'," ")
word_list = text.split(" ")
word_count = {}
for word in word_list:
if(word in word_count.keys()):
word_count[word] += 1
else:
word_count[word]=1
del word_count['']
print(word_count)
if __name__ =='__main__':
text = "Hello world! This is an example. Word count is fun.Is it fun to count words? Yes, it is fun!"
count_words(text)
启动debug
Python基础语法
Python基础语法
基本数据类型
运算符
算数运算符
比较运算符
赋值运算符
逻辑运算符
列表
列表是一个有索引的序列,索引从0开始。
列表式一个有序的可重复元素序列。列表是可变的,列表中的元素可以重复,可以是不同的类型。
列表非常重要,他不仅是python开发中最常用的数据结构,同时也是python序列中最具代表性的一个。 当能够理解列表以后,剩下的其他序列学起来就没有那么困难。
列表的创建方法
访问元素的方法,索引与切片
python中的序列均有正向索引与反向索引,正向索引从0开始表示序列第一个元素,反向索引从-1开始表示
以alist为例子,我们打印出alist中每个元素对于的正向索引与反向索引。
列表支持切片操作,即截取列表中的一部分长度的操作。
具体语法为 list_name[start_index:end_index:step]。
start_index为起点索引,end_index为终点索引,step为步长。
要注意截取的部分为[start_index,end_index),也就是不包括end_index。
其中step缺省时默认步长为1,start_index缺省时默认为第一个元素,
end_index缺省时默认为最后一个元素。
列表运算符
列表函数与方法
alist_copy = alist时并没有新建一个对象,而只是单纯赋值了alist的地址给alist_copy。
这会导致我们对变量alist_copy的所有操作本质上都是在操作alist。
而当我们使用.copy()方法进行赋值时,会复制alist为一个新的对象,此时对新对象的修改不会影响到alist。
元组
元组和列表很相似,但是元组创建后不可修改。
元组使用()来表示,创建元组和列表一样,只要在()内添加元素并用逗号隔开就行。
元组的运算符
同列表
元组的函数
同列表
集合
集合是无序的不重复的元素序列,支持交集、并集、差集等常见的集合操作。
集合的创建使用{}表示,并用,隔开。注意如果需要创建一个空集合需要使用set()。
集合的常用方法
字典
字典是一个无序的可以修改的序列,每一个元素都由一对key与value组成,key为对应value的索引。
key不可重复,且需要是不可变对象(可hash),可以是数字,字符串,元组等,但不能是列表。value可以重复
字典的创建可以用dict()或者{key1:value1,key2:value2,...}来创建。
还记得在集合中我们提过{}能用于创建空集合,是因为{}创建的是一个空字典
字典的常用方法
字符串
学习LLM,必然逃不过对字符串的处理。
Python中的字符串使用"或者'来创建,两者等价,但是"会高于'。
此外,'''可以用来创建包含多行的字符串。
字符串本质上是一个不可变的元素可重复的有序序列,这也是为什么本教程会把字符串放在序列内容的最后一节。
字符串,本质上就是由字符组成的序列,将其转换为list就能看到他的原始数据结构,所以除了不能修改外,他的索引与切片操作跟列表一模一样。
字符串的运算符
字符串的方法
要注意的是,因为字符串是不可修改的对象,所以每个修改字符串的方法都是将修改后的字符串作为一个新对象返回。
字符串的格式化输出
在做LLM开发时避不开对字符串做格式化输出,即指定一个模板把变量放入模板中。
接下来我们介绍两种常见的易于实现复杂格式化输出的方法。
第一种为使用字符串的.format()方法,并在在字符串中需要插入值的地方用{}代替,{}也可以加入变量名,方便赋值。
第二种方法我们使用python在3.6推出的f-sting功能,只需在字符串开头加上f,该字符串中的{}中的python代码就会被评估。
控制结构
python中的if语句为:
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3
接下来我们用if语句完成一个成绩等级判定的功能:
- [90,100] A
- [80,90) B
- [70,80) C
- [60,70) D
- [0,60) F
循环
while语句
Python while循环语句语法
while condition:
statement
以上是while语句的形式,当condition为True时,while会执行statement然后再判断condition,直至condition变为False才会结束循环
for 语句
Python中for语句的语法为
for <variable> in <sequence>:
<statements>
else:
<statements>
for循环可以遍历任何可迭代的对象,比如一个列表。
提到for循环就不能不提经常与它一起出现的range(start,stop,step)函数,他会生成一个可迭代的对象,以step步长生成[start,stop)。可以只写一个stop,默认从0开始。
列表推导式
函数
函数的定义方式
python定义函数的关键字为def
def 函数名(参数列表):
函数体
函数的参数传递
- 参数是可变对象时,传参时传递的是索引,在函数中修改该参数会作用于原对象
- 参数是不可变对象时,传参时会自动复制,在函数中修改该参数不会作用于原对象
可以看到在update函数内修改了number和alist,函数外面的整数a没有被修改,但是列表b被修改了。 这就是python函数在传参时候的特征导致的。
通过使用id()函数可以获取对象在内存中的地址可以看到number与a的id不同,他们是两个对象了。但是alist与b的id相同,说明他们两在内存中指向的是同一个对象。
Numpy基础
NumPy是Python中一个强大的科学计算库,它提供了高性能的多维数组对象及这些数组的操作工具。使用NumPy,你可以轻松地进行数学和科学计算,比如线性代数、矩阵运算以及统计分布等,是数据分析和机器学习等领域的基石。Numpy array的操作与Pytorch的Tensor十分相似,了解了array对以后学习pytorch帮助很大。
numpy的安装可以在终端中输入:
pip install numpy
或者直接在notebook中运行
!pip install numpy
TIPS: notebook中加上!可以直接在终端中运行终端命令
numpy Ndarry和创建数组的方式
NumPy数组(ndarray)是NumPy库的核心数据结构,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray本质上是一个存放同类型元素的多维数组,其中的每个元素在内存中都有相同存储大小的区域。
NumPy数组(ndarray)的特点:
- 高效的内存使用:ndarray对象在内存中连续存储,这使得对数组的元素进行切片和迭代等操作非常快速,而不需要额外的内存开销。
- 快速执行:NumPy数组的操作是在编译后的代码中执行的,这使得NumPy操作比纯Python代码快得多。
- 方便易用:NumPy提供了大量数学和数值计算函数,使得数组操作非常方便。
- 灵活性:NumPy数组可以在不同的数据类型之间灵活转换,支持整数、浮点数、复数等多种数据类型。
python中导入第三方包的关键词为 import, 可以用as给包取别名。导入numpy的语句如下所示,numpy的简称一般为np。
import numpy as np
创建numpy数组最常见的方法就是将一个列表使用np.array()函数转成ndarray。
TIPS:在notebook中将光标移动到函数的括号中间,按下shift+tab可以看到函数的提示
Numpy还有其他很方便的创建元素值相同的数组的函数:
- 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 来填充
TIPS: 所有dtypes都是可选参数
从数值范围创建数组
也许你还记得在python for循环中我们提到的range(start,stop,step)函数,他能生成一个迭代器。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 的数据类型
数组操作
数组运算与广播机制
numpy array之前的运算均为元素位置一一对应进行计算,需要两个数组维数相同,且各维度的长度也相同。此外,numpy的广播机制还可以把该条件放宽到两个数组在某个维度上的长度相同即可。
广播机制
NumPy的广播机制是NumPy库中一个非常强大的功能,它允许我们对形状不完全相同的数组进行算术运算。在广播过程中,NumPy会自动调整数组的形状,以便它们可以在元素级别上进行运算。这种机制使得NumPy在进行数组操作时更加灵活和高效。
广播的基本规则
规则一:维度对齐
- 如果两个数组的维度数不同,较小的数组会在其前面补1,直到两个数组的维度数相同。
- 维度对齐后,从最后一个维度(也称为“后缘维度”)开始比较两个数组的形状。
规则二:兼容维度
- 如果两个数组在某个维度上的大小相同,或者其中一个数组在该维度上的大小为1,则这两个数组在该维度上是兼容的。
- 如果两个数组在所有维度上都是兼容的,那么它们就可以进行广播。
规则三:输出形状
- 广播后的输出数组的形状是输入数组形状在各个维度上的最大值。
假设我们有两个数组a和b,我们想要对它们进行加法运算。
- 在这个例子中,
a
的形状是(3,)
,而b
的形状是(3, 1)
。 - 根据广播规则一,
a
的形状在逻辑上被扩展为(1, 3)
,以便与b
的形状(3, 1)
对齐。 - 然后,根据规则二,两个数组在所有维度上都是兼容的,因为
a
在第一个维度上的大小为1(逻辑上扩展的),而b
在该维度上的大小为3;同时,在第二个维度上,两者的大小都是3(或1,对于a
来说)。 - 因此,可以进行广播,加法运算在元素级别上进行。
- 结果数组
result
的形状是(3, 3)
,这是两个输入数组形状在各个维度上的最大值。
如果我们不使用NumPy的广播机制,而是手动模拟这一过程,我们可以这样做:
修改数组形状
ndarray.reshape(newshape, order='C')不改变数据的条件下修改形状
- newshape:整数或者整数数组,新的形状应当兼容原有形状
- order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序。
返回修改好形状的数组,并不直接对原数组进行修改
ndarray.flatten(order='C')将数组展平成一维数组
- order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。
翻转数组
对于二维数组就是转置,但对于更高维的数组可以指定axes列表来确定维度的变化。原始数组的维度[0,1,2],可以指定axes为[0,2,1]从而将最后一维放到中间。
修改数组的维度
numpy有两个常用的修改数组维度的函数,一个用于增加维度一个用于减少维度。修改数组维度经常会在进行高维tesnor计算时用于对其维数用到,经过增加一维或者减少一维数来实现。 numpy.expand_dims(arr, axis)通过在指定位置插入新的轴来扩展数组形状
- arr:输入数组
- axis:新轴插入的位置
numpy.squeeze(arr, axis)从给定数组的形状中删除一维的条目
- arr:输入数组
- axis:整数或整数元组,用于选择形状中一维条目的子集
拼接数组
numpy有四种拼接数组的函数:
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,通过垂直堆叠来生成数组
所有用于拼接的数组在拼接的轴上长度必须相同
索引与切片
numpy数据一样有索引与切片,只是其索引的写法与嵌套列表可能会有一点点不一样。
numpy的索引用[]表示,用,隔开每个轴上的索引,比如对于一个二位数组要取第i行第j列的元素的索引就为[i,j]
在索引切片上numpy数组依旧遵循start:stop:step格式,在每个轴上的切片用,隔开。:或者...可以表示取整个轴上的全部元素。
排序条件筛选
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()获取其中为ture的元素的索引。
数学函数
numpy内置了非常多的数学函数,可以直接应用于numpy数组对每一个元素做映射。
常见的函数有np.sin(),np.cos(),np.tan(),np.log()等。
此外,还有np.mean(),np.median(),np.std()等统计函数。
对于取整函数,numpy有np.round()按小数位数四舍五入,np.ceil()向上取整,np.floor()向下取整
线性代数
Numpy的核心就是高性能的矩阵运算,它还提供了线性代数计算包linalg。这里只展示二维数组常用的方法,numpy能做的远远不止这些。
常用线性代数计算函数
- np.linalg.det() 数组的行列式
- np.linalg.inv() 计算矩阵的乘法逆矩阵
- np.linalg.solve() 求解线性方程
求解方程组: