目录
0 整体思路
本文侧重讲解python程序设计(而不针对于机器学习相关内容).
1 程序设计
程序是一组指令的集合,这些指令告诉计算机或其他电子设备如何执行特定的任务。程序可以用于各种目的,包括数据处理、自动化、游戏、模拟、计算等。程序通常用编程语言编写,如Python、Java、C++、C#、JavaScript 等高级语言,它们更接近人类语言,易于理解和编写,此外还有汇编语言、机器语言(二进制代码,可由硬件直接执行)等。
高级语言通常分为解释型语言和编译型语言(还有将他们结合的一种,这种分类本身是不严格的)。
解释型语言,例如,Python、JavaScript 等解释型语言在运行程序时,解释器会读取代码并即时执行,不需要事先将整个程序编译成机器码。解释器逐行解释并执行源代码。解释器读取源代码,将其转换为中间代码或直接解释执行机器指令,每次执行一行或一小段代码。
编译型语言,例如,C、C++、Java(先编译成字节码再由 JVM 解释或即时编译执行)等编译型语言在运行前需要经过编译阶段。编译器将源代码一次性编译成机器码。编译器会对整个程序进行分析,生成可执行的机器码文件,这个文件可以直接在特定的操作系统和硬件平台上运行。Java是先编译成“.class”字节码文件,然后再利用JVM虚拟机进行解释执行的,所以Java即可以说成编译型,也可以说成解释型,C#语言也是类似的情况。
通常认为,“程序 = 算法 + 数据(结构)”。更上一层的概念,计算机软件是计算机系统中的程序及其文档。根据《计算机科学技术百科全书》,程序定义为计算任务的处理对象和处理规则的描述(也就是数据和算法)。利用python编写数据处理、机器学习的程序同样如此,只是处理方法和使用目的与传统意义的软件有一定区别。
2 Python基础
在根据上文内容
本文将从以下几点介绍python语言基础。本文代码使用python交互式解释器练习即可。将python添加到环境变量的在命令行中使用python指令进入,安装了conda的在conda prompt中进入任意环境后,使用python指令进入。
2-1 打印
利用python内置函数print完成
#python内置函数 print
print("asd")
2-2 注释
不被执行的语句便于理解代码含义
#print("asd")
print("asd")
2-3 变量
变量是用于存储数据值,python中可以直接通过赋值语句来创建变量。但应注意变量的名字(等号左侧)有一定的要求,比如你不能把变量起名叫print,这类python保留字,虽然并不会报错但在接下来的程序中将不能使用print()进行打印,在此如果这样尝试了,只能关闭该交互解释器,重新进入。变量命名规则还有:
- 变量名只能包含字母、数字和下划线。
- 变量名不能以数字开头。
- 区分大小写。
Python 是一种动态类型语言,其变量的数据类型可以在运行时改变。以下是一些常见的数据类型:
a=123
a="asd"
print(a)
- 整数(int):用于存储整数值,例如
x = 123
。 - 浮点数(float):用于存储小数,例如
y = 3.14
。 - 字符串(str):用于存储文本,例如
name = "Alice"
。可以使用单引号或双引号来定义字符串。 - 布尔值(bool):用于存储真(True)或假(False)值。例如
is_valid = True
。 - 列表(list):用于存储一组有序的数据,可以包含不同类型的元素。例如
my_list = [1, "two", 3.0]
。 - 元组(tuple):与列表类似,但元组是不可变的,即一旦创建就不能修改。(但是可以重新赋值和变换类型)例如
my_tuple = (1, 2, 3)
。 - 字典(dict):用于存储键值对。例如
my_dict = {"name": "Alice", "age": 30}
。
2-4 字符串
字符串是用一对单引号或一对双引号引出的文本。但单双引号不能混用,其开始和结尾必须是同一种。字符串中可以有转义字符用于表示一些特殊的字符或者控制字符序列。(比如你会发现不能直接在字符串内使用回车换行,即使在其他非交互的编辑器中,由单双引号引出的字符串同样不能使用回车换行)。
\n
:换行符,将光标移动到下一行的开头。
print("Hello\nWorld")
\t
:制表符,用于在输出中进行缩进或对齐。
\\
:表示一个反斜杠字符。
\'
:表示一个单引号字符。在使用单引号定义字符串时,如果字符串中包含单引号,可以使用这个转义字符。
\"
:表示一个双引号字符。在使用双引号定义字符串时,如果字符串中包含双引号,可以使用这个转义字符。
\r
:回车符,将光标移动到当前行的开头,覆盖现有内容。
2-5 计算
python中数值变量可进行数值计算,值得注意的有:
- //整数除法,返回商
- %取余运算
在最后一个例子中进行了格式的转换,将float格式的2.5变换为int格式的2,转换原理为向下取整。类似的还有:
# 注释为预计输出
float("1.23")
#1.23
str(10)
#'10'
bool(0)
#True
bool(5)
#False
2-6 循环和条件语句
循环用于需要重复的任务。python中有for,while两种循环语句。
2-6-1 for循环
# for循环基本格式:
#for i in range(n):
# 操作
#注意在冒号之后的循环体内,代码应缩进一级
for i in range(10):
print(i)
range()与print()类似,同样为内置函数,用于生成一个整数序列,返回的是一个可迭代的对象。“返回” 指的是一个函数向调用它的地方传递一个值或结果,结合上述变量内容,可尝试如下代码,便于理解。
在交互器中执行时,输入冒号后回车,代码不会像之前一样立即执行,此时光标移到了下一行上,按一次Table键,缩进一级,输入代码,后续如果多行同样需要缩进,最后回车进入空白行后,再回车一次执行代码。
多层循环嵌套时,应注意多级缩进。
2-6-2 while循环
显然在for循环中,我们需要提前设定好循环次数,但是有时,我们无法提前获知,比如假设我想知道至少3的多少次方会大于123,这时就需要使用到while循环。显然这里也涉及到了一次条件的判定。
#while 循环条件:
# 操作
#底数
a=3
#记录当前n次方值
ans=a
#记录n
i=0
while ans<123:
ans*=3
i+=1
2-6-3 条件语句
条件语句用于实现程序的分支执行。即当满足某些条件时执行一些命令,否则不执行。如判断一个变量是否大于10:
#if 条件:
# 操作
a=0
if a>10:
print("a is bigger than 10")
显然这段代码不会有打印输出。
在条件不被满足时,我们也希望会有相应操作时,可以用else完成:
#if 条件:
# 操作
#else:
# 操作
a=0
if a>10:
print("a is bigger than 10")
else:
print("{} is not bigger than 10".format(a))
对于这里的else输出我们使用了字符串格式化的操作。{}
是一个占位符。.format(a)
表示将变量 a
的值插入到占位符的位置。
条件语句也有嵌套的情况,如对于不大于10的数,我们想进一步确定它是不是大于5
a=0
if a>10:
print("a is bigger than 10")
if a>5:
print("a is bigger than 5")
if a<=5:
print("a is not bigger than 5")
在这里,三个if语句是并列的,变量a会一次进行这三个判断,而显然当输入大于10的数字时,无需进入后续的判断。这时可简化如下:
a=0
if a>10:
print("a is bigger than 10")
elif a>5:
print("a is bigger than 5")
else:
print("a is not bigger than 5")
关于if/else的相关探讨读者可以自行尝试,如更换条件顺序实现与上述功能相同的程序。
2-7 列表
在 Python 中,列表(list)是一种非常常用的数据结构。列表是一个可变的有序序列,可以包含任意类型的对象,如整数、字符串、其他列表(可嵌套)等。例如:
my_list = [1, 'asd', 3.14, [4, 5, 6]]
#使用内置的list函数,结合range函数
my_list2 = list(range(5))
对于列表内的元素我们可以通过索引获得,索引从0开始,获得当前月份9方法:
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
months[8]
列表常见操作还有切片,即截取列表的一段,由冒号和数字组合形式的索引完成,当有一个 冒号时,前后分别为左右边界,且取到右侧索引的前一项(入夏季,索引8对应九月,但是没有取到september而取到august)。有两个冒号时,第三个数值为步长(=间隔+1),切片时,左侧边界索引为首项计算步长。负数索引代表从右向左数的个数,-1为最后一项。左右不设边界时,左侧可以写作0,也可省略,右侧即设为空(三四季度首月例子中,省略了右边界,两个冒号连在一起)。
在range函数中也是类似的情况,函数的传入参数用逗号隔开,当只输入一个数字时,为左边界(上界),右边界默认为0。两个参数时分别为左右边界。三个参数时,第三个参数是布长。
#夏季
months_summer=months[5:8]
months_summer #做输出使用,后续部分省略
#['June', 'July', 'August']
#一二季度奇数月份
quarter12_months_even = months[0:6:2]
quarter12_months_even
#['January', 'March', 'May']
#三四季度首月
quarter34_months_head = months[6::3]
quarter34_months_head
#['July', 'October']
#除了最后一个月
months_beforelast=months[:-1]
months_beforelast
#最后一项
months[-1]
#range 生成7到20之间,每隔2个数取一个数的列表
list_range=list(range(7,20,3))
list_range
#[7, 10, 13, 16, 19]
列表的修改:
#在末尾追加一个元素 注意在变量一节提到的命名规范,最好不要将列表起名为list
list_temp=[1,2,3]
list_temp.append(4)
#[1, 2, 3, 4]
#修改 索引获取+赋值
list_temp[0]=10
#[10, 2, 3, 4]
#扩展,在末尾连接上另一个列表
list_temp.extend([7, 8, 9])
#[10, 2, 3, 4, 7, 8, 9]
#删除元素1,删除某个索引的元素
del list_temp[0]
#[2, 3, 4, 7, 8, 9]
#删除并获得该元素,指定索引
temp=list_temp.pop(1)
#[2, 4, 7, 8, 9]
#temp 值为 3
#删除元素2,制定值删除,注意这里输入的7是值,删除第一个值为该输入的元素。
list_temp.remove(7)
#[2, 4, 8, 9]
list2=[1,1,1,1]
list2.remove(1)
#[1,1,1]
列表还有一些其他常用功能(方法,上述通过“列表名.函数()”的调用的函数均是列表类的方法,这一概念在后续进一步介绍)。这些功能包括:查找,计数,排序,反转(反向排列)等。
list3=[1,1,2,2,3,4,5,10,9]
##查找,输入值返回第一次出现该值时的索引
list3.index(2)
#2
list3.index(3)
#4
##计数,分别返回值为2,值为3的元素的个数
list3.count(2)
list3.count(3)
#排序,这里将调换元素9,10的位置
list3.sort()
#[1, 1, 2, 2, 3, 4, 5, 9, 10]
#反转,将列表反转,但不会逆向排序
list3=[1,1,2,2,3,4,5,10,9]
list3.reverse()
#[9, 10, 5, 4, 3, 2, 2, 1, 1]
获取列表长度的方法:通过python内置函数len完成,除了列表它还可以计算元组、字符串集合、字典的长度。
my_list = [1, 2, 3, 4, 5]
length = len(my_list)
print(length)
对列表的每一个元素要进行相同操作时,可以利用循环for。
按照某种顺序访问数据结构中的每个元素的过程叫做遍历。
list4=[1,1,2]
for i in list4:
print(i)
#通过索引
for i in range(len(list4)):
print("{},{}".format(i,list4[i]))
2-8 字典
字典是一个或多个由键值对组成的数据类型,python的字典由花括号扩出,字典(dictionary)是一种可变的、无序的容器数据类型。在访问、修改、删除时,均使用键作为标识(列表里通常是索引,也可以是值)
weather_dict = {
"January": "Cold and snowy",
"February": "Chilly ",
"March": "Warming up but still cool",
"April": "Mild and pleasant",
"May": "Warm",
"June": "Hot",
"July": "Very hot and humid",
"August": "Still hot",
"September": "Starting to cool down",
"October": "Cool",
"November": "Chilly",
"December": "Cold and sometimes snowy"
}
#dict函数
weather_dict = dict({
"January": "Cold and snowy",
"February": "Chilly ",
"March": "Warming up but still cool",
"April": "Mild and pleasant",
"May": "Warm",
"June": "Hot",
"July": "Very hot and humid",
"August": "Still hot",
"September": "Starting to cool down",
"October": "Cool",
"November": "Chilly",
"December": "Cold and sometimes snowy"
})
#查询七月天气
print(weather_dict["July"]) # Very hot and humid
#修改四月天气
weather_dict["April"] = "Rainy and mild"
print(weather_dict["April"]) # Rainy and mild
#删除十二月
del weather_dict["December"]
#添加十二月
weather_dict["December"] = "Cold "
print(weather_dict["December"]) # Unknown weather
#获取长度,字典无序,但是也有长度,即键值对个数
len(weather_dict)
#遍历键
for month in weather_dict:
print(month)
#或
for month in weather_dict.keys():
print(month)
#遍历值
for weather in weather_dict.values():
print(weather)
#同时遍历键值
for month, weather in weather_dict.items():
print(f"{month}: {weather}")
字典的值可以是列表和元组,以学生成绩和经纬坐标为例
student_grades = {
"Alice": [90, 85, 92],
"Bob": [80, 75, 82],
"Charlie": [88, 91, 87]
}
# 访问特定学生的成绩列表
alice_grades = student_grades["Alice"]
print(alice_grades) # [90, 85, 92]
# 修改特定学生的成绩列表
student_grades["Bob"] = [85, 80, 88]
print(student_grades["Bob"]) # [85, 80, 88]
city_coordinates = {
"New York": (40.7128, -74.0060),
"London": (51.5074, -0.1278),
"Tokyo": (35.6895, 139.6917)
}
# 访问特定城市的坐标元组
new_york_coords = city_coordinates["New York"]
print(new_york_coords) # (40.7128, -74.0060)
2-9 文件处理
在 Python 中,文件处理通常涉及打开、读取、写入和关闭文件等操作。以下是一些常见的文件处理方法:
使用 open()
函数来打开文件。它接受文件名和模式作为参数,并返回一个文件对象。
常见的文件打开模式有:
'r'
:只读模式(默认)。'w'
:写入模式,会覆盖原有内容。如果文件不存在,会创建一个新文件。'a'
:追加模式,在文件末尾添加内容。如果文件不存在,会创建一个新文件。'b'
:二进制模式,可与其他模式结合使用(如'rb'
、'wb'
)。't'
:文本模式(默认),可与其他模式结合使用(如'rt'
、'wt'
)。
# 写入模式,文件不存在时,会创建新文件,存在时会覆盖原始文件。
file = open('example.txt', 'w')
file.close()
python中读取文件后,需要使用 close()
方法关闭文件,以释放资源。为了确保文件在使用后总是被正确关闭,可以使用 with
语句,它会在代码块执行完毕后自动关闭文件:
line= ['Line 1', 'Line 2', 'Line 3']
with open('example.txt', 'w') as file:
#写入一个列表
file.writelines(line)
#write会返回一个写入的字符串长度
file.write("\n")
#写入一个列表,逗号隔开
content = ', '.join(map(str, line))
file.write(content)
file.write("\n")
file.write('Hello, world!')
print(lines)
# 文件会在这个代码块执行完毕后自动关闭
with open('example.txt', 'r') as file:
content = file.read()
print(content)
with open('example.txt', 'r') as file:
for line in file:
print(line.strip()) # 使用 strip() 去除每行末尾的换行符
2-10 函数
在 Python 中,函数(function)是一段可重复使用的代码块,用于执行特定的任务。我们已经用到了很多函数,如print,open等,本文目前使用的函数均为内置函数。现在我们来定义自己的函数:
#def 函数名(参数列表):
# 函数体
#
def greet(name):
return f"Hello, {name}!"
通过使用函数名并传入相应的参数来调用函数
message = greet("Alice")
print(message) # 输出:Hello, Alice!
函数头的括号内为需要传入的参数:
- 位置参数:按照参数在函数定义中的位置顺序传递。
- 关键字参数:通过参数名和对应的值来传递参数,可以不按照位置顺序。
- 默认参数:在函数定义时为参数指定一个默认值,如果调用函数时没有传入该参数,则使用默认值。
def describe_person(name, age=30): return f"{name} is {age} years old." print(describe_person("Bob")) # 输出:Bob is 30 years old. print(describe_person("Charlie", 25)) # 输出:Charlie is 25 years old.
函数返回值:函数可以使用 return
语句返回一个值或多个值。如果没有 return
语句,函数默认返回 None
。
def add_numbers(a, b):
return a + b
result = add_numbers(3, 4)
print(result) # 输出:7
匿名函数 lambda
#lambda arguments: expression
ef square(x):
return x * x
# 使用 lambda 函数实现相同功能,这里将匿名函数又赋给了square_lambda
square_lambda = lambda x: x * x
print(square(5)) # 输出:25
print(square_lambda(5)) # 输出:25
lambda 函数通常作为参数传递给其他函数,比如内置函数 map()
、filter()
和 sorted()
等。map将一个函数应用于可迭代对象(如列表、元组等)的每个元素,并返回一个新的可迭代对象,其中包含函数应用后的结果。
#map(function, iterable,...)
#可输入多个可迭代对象,作为第一个参数function的输入参数
numbers = [1, 2, 3, 4, 5]
#使用 map 和 lambda 函数计算列表中每个元素的平方
squares = list(map(lambda x: x * x, numbers))
print(squares) # 输出:[1, 4, 9, 16, 25]
#将两个列表中的对应元素相加
list1 = [1, 2, 3]
list2 = [4, 5, 6]
added_lists = map(lambda x, y: x + y, list1, list2)
print(list(added_lists)) # [5, 7, 9]
filter过滤,过滤列表中字符串长度大于5的元素
words = ['apple', 'banana', 'cherry', 'date', 'elderberry']
long_words = filter(lambda word: len(word) >= 5, words)
print(list(long_words)) # ['banana', 'cherry', 'elderberry']
过滤非空字符串
strings = ['', 'hello', '', 'world', '', 'python']
non_empty_strings = filter(None, strings)
print(list(non_empty_strings)) # ['hello', 'world', 'python']
2-11 搜索和排序
搜索和排序针对于列表等数据类型,在其相关小节中已有讲解,这里举一两个较为例子,讲解sorted等函数。
1.搜索
判断一个值是否在列表或字典中,用in即可判断。
my_dict = {'a': 1, 'b': 2, 'c': 3}
value = 2
if value in my_dict.values():
print(f"{value} 在字典的值中。")
else:
print(f"{value} 不在字典的值中。")
2.已知存放学生各科成绩的字典,按第二门成绩有高到低的顺序返回一个学生名字的列表。
这个例子中使用了内置函数sort,第一个参数为待排序列表,由字典的key方法返回了学生姓名列表,key参数是排序时的关键变量(按key参数排序),lambda表达式定义了一个输入student(名字),输出原始字典中查找该键对应值的索引为1的参数。reverse,是否逆序。
可以理解为对student_grades.keys()这个列表的每个元素,应用lambda函数得到一个值(第二门成绩),按改成绩排序后,返回student_grades.keys()列表的内容的顺序。
student_grades = {
"Alice": [90, 85, 92],
"Bob": [80, 75, 82],
"Charlie": [88, 91, 87]
}
sorted_students = sorted(student_grades.keys(), key=lambda student: student_grades[student][1], reverse=True)
print(sorted_students)
当然也可以不采用lambda函数,使用显式函数。
#最后一门课的成绩
def last_grade(name):
return student_grades[name][-1]
sorted_students = sorted(student_grades.keys(), key=last_grade, reverse=True)
print(sorted_students)
这看起来有一些复杂,但实际上sort还是十分简便的:
list_s=[4,1,2,3]
sorted(list_s)
#会有直接输出[1, 2, 3, 4]
list_s
#但是list_s仍为[4, 1, 2, 3]
#sorted不会改变原来的列表,注意与列表的sort方法区分
#赋给一个新列表
sorted_list=sorted(list_s)
2-12 类与对象
在 Python 中,类是一种用户自定义的数据类型,它定义了一组属性(数据)和方法(行为)。对象是类的一个实例。
class Dog:
# 类属性
species = "Canis lupus familiaris"
# 构造方法
def __init__(self, name, age):
# 实例属性
self.name = name
self.age = age
# 实例方法
def bark(self):
print(f"{self.name} says woof!")
# 静态方法
@staticmethod
def info():
print("Dogs are loyal animals.")
在 Python 中,静态方法是一种不依赖于类实例也不依赖于类本身的方法。它通过在方法前加上 @staticmethod
装饰器来定义。静态方法的特点:
- 静态方法不需要访问类实例(通常用
self
表示)或类本身(通常用cls
表示)的状态,它只是一个普通的函数,被放在类的命名空间中,方便组织代码。 - 可以直接通过类名来调用静态方法,而无需创建类的实例。
当我们需要创建对象时,可以通过调用类名并传入必要的参数来完成:
my_dog = Dog("Buddy", 3)
访问属性和方法:(我们之前对列表和字典的操作多数就是它们的方法)
print(my_dog.name) # Buddy
print(my_dog.age) # 3
my_dog.bark() # Buddy says woof!
Dog.info() # Dogs are loyal animals.
类可以继承其他类的属性和方法。例如:
class Teddy(Dog):
def fetch(self):
print(f"{self.name} is fetching.")
my_golden = Teddy("Max", 2)
my_golden.bark() # Max says woof!
my_golden.fetch() # Max is fetching.
Python 中的类可以定义一些特殊方法,以实现特定的行为。例如,__str__
方法可以定义对象的字符串表示形式:
class Dog:
#...
def __str__(self):
return f"{self.name} is {self.age} years old."
my_dog = Dog("Buddy", 3)
print(my_dog) # Buddy is 3 years old.
如果不定义str直接打印,会返回对象信息及其在内存中的内存地址。
这里再举一个机器学习相关的简单例子:线性回归(这里只是一个非常基础的示例,并非真正意义上的强大机器学习算法)
"""
这个方法用于拟合线性回归模型,确定模型的斜率和截距。
参数:
- X:输入特征列表。
- y:目标值列表。
实现步骤:
1. 计算样本数量 n。
2. 分别计算输入特征 X 的总和(sum_x)、目标值 y 的总和(sum_y)。
3. 计算输入特征与目标值对应元素乘积的总和(sum_xy)以及输入特征平方的总和(sum_x_squared)。
4. 计算斜率(slope)和截距(intercept)的分子和分母。
5. 确定模型的斜率和截距。
"""
#python
import math
class SimpleLinearRegression:
def __init__(self):
self.slope = 0
self.intercept = 0
def fit(self, X, y):
n = len(X)
sum_x = sum(X)
sum_y = sum(y)
sum_xy = sum([x * y for x, y in zip(X, y)])
sum_x_squared = sum([x * x for x in X])
numerator = n * sum_xy - sum_x * sum_y
denominator = n * sum_x_squared - sum_x * sum_x
self.slope = numerator / denominator
self.intercept = (sum_y - self.slope * sum_x) / n
def predict(self, X):
return [self.intercept + self.slope * x for x in X]
def mean_squared_error(self, y_true, y_pred):
n = len(y_true)
return sum([(yt - yp)**2 for yt, yp in zip(y_true, y_pred)]) / n
X = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]
regressor = SimpleLinearRegression()
regressor.fit(X, y)
predictions = regressor.predict(X)
mse = regressor.mean_squared_error(y, predictions)
print(f"Slope: {regressor.slope}, Intercept: {regressor.intercept}")
print(f"Predictions: {predictions}")
print(f"Mean Squared Error: {mse}")