Python 是一种上手简单、功能丰富的编程语言,是数据科学领域首选的可靠工具。通过 Python 你可以迅速解决问题,而不是把精力消耗在复杂的语法与编程细节上,这与本教程的核心思想“简洁”不谋而合。
当全世界的数据科学家与研究人员享受 Python 带来的便利时,另一部分人正在致力于开发各种强大的 数据分析 / 机器学习 / 神经网络运行库,使得复杂的算法和模型不再成为技术门槛,越来越多的人都有机会进入数据科学领域进行学习与创新。
对于 Windows / Mac 用户,首先在官网 https://www.python.org/downloads/ 下载对应操作系统的 Python3 安装包,然后双击运行安装。
对于Linux用户,执行 sudo apt-get update && sudo apt-get install python3
命令进行安装。
在安装完成后,打开命令提示符(win + R键,输入cmd回车) / 终端(command + 空格,输入term回车),执行 python3 -V 命令,若出现对应python版本号则安装成功。
一个 Python 程序要经过“编写”和“运行”两个阶段。
编辑器可以是notepad++、emeditor、甚至 windows 中最常见的 txt 编辑器。但为了提高我们的编程效率,我们往往选择功能更全面的 PyCharm 或者 vscode 等专用集成代码编辑器(IDLE)。
解释器就是我们在上步安装的 python 可执行文件,在 windows 中它是 python3.exe,在 Mac / Linux 中它是名为 python3 的可执行文件。
在成功安装后,我们将尝试编写第一个Python程序。
首先我们选择 Python 自带的IDLE编辑器
然后输入 print("hello world")
,并保存到任意位置,我们的程序编写阶段就完成啦!
下一步我们尝试用解释器运行保存的.py程序。
首先通过命令行输入 cd ~/***
进入到文件存储的位置(这里 *** 是你文件储存位置的路径)
然后命令行执行 Python3 test.py
命令,这时输出 hello world 字样则程序运行成功!
相比于其他编程语言,Python的一个特色是交互式环境,为我们提供了可以同时编写运行的编程方式。
首先我们下载一个名为 jupyter notebook 的编辑器,它可以支持交互式环境。
在命令行执行命令 pip install jupyter
安装编辑器。
然后执行命令 jupyter notebook
。
这时你发现你的浏览器自动打开了,并且出现了一个在线的精美简洁的编辑器,这就是notebook的主界面。
我们点击右上角的 New 按钮,选择 Python3,然后输入 print('hello world')
,之后按下上面的 Run 按钮,这时我们发现在代码的下面也出现了hello world。
编写代码之后即刻运行,运行之后还可以继续编辑,省去了不停打开编写保存运行的过程,这便是交互式编程的奇妙之处!而交互式编程带来的便捷不止如此,在数据科学中我们经常要处理较大的数据,整个程序的运行动辄十几分钟。通过交互式编程我们可以一行一行运行程序,同时通过下面的输出内容观察程序的中间运行结果,在出现错误时及时修改代码,从而节省重复运行程序的时间!
下面的教程中,交互式编程将全程陪伴你的学习过程,相信随着时间你会更加感触到先进工具带来的效率提升!
可能你现在会产生疑惑,代码中的 print 代表什么意义?括号又是什么作用?为什么 hello world 外面有个双引号?没关系,下面我们就来了解 Python 语法的奥秘。
首先我们介绍常量与变量,他们相当于语言中的 “名词” 部分,功能是用来表示某些事物。
常量是编程语言中固定的量,它的值不能改变。例如 2 就表示数字二,不能被修改表示其他值。Python 中的常量包括数字,字符串,逻辑值三种。
使用 type( * )
可以查看 * 的类型,例如 type(2)
返回 int 表示 2 为 整数。
## 2 表示 整数(integer) 2
type(2)
int
## 2.333 与 1e-9 表示对应浮点数(float)
type(2.33)
float
type(1e-9)
float
## 用单引号括起来的内容表示字符串(string)
type('这是1个字符串')
str
## True 代表逻辑值(Boolen)
type(True)
bool
type(False)
bool
与常量相反,变量可以存储不同的值以表示不同的内容,并且它的值可以被更改。变量通过赋值符号 =
创建,例如 variable = 1
。
注意变量存在命名规范。变量的第一个字符必须是字母或下划线,其余部分由下划线或数字组成,且区分大小写。例如 a_123
可以是一个变量,123_a 不可以是一个变量,A_123
与 a_123
表示两个不同变量。
## 创建名为 variable 的变量存储一个 整数 值
variable = 1
type(variable)
int
## 修改 variable 变量的值为一个字符串
variable = 'Hi'
type(variable)
str
## 常量的值无法修改 触发语法错误提示
2.33 = 2.55
Input In [9]
2.33 = 2.55
^
SyntaxError: cannot assign to literal
## 变量的命名不满足规范 触发语法错误提示
123_a = 1
Input In [10]
123_a = 1
^
SyntaxError: invalid decimal literal
学习了常量与变量之后,我们可以在 Python 中表示一些数值或字符串,然而要想解决更复杂的问题,我们需要了解如何对这些常量与变量进行操作。
运算符与函数相当于语言中的 “动词” 部分,用来表示某种操作。
运算符有以下几种,表示运算操作/逻辑操作/位运算操作
算数运算符:
+
表示加法,1 + 2
的结果是 3-
表示减法,1 - 2
的结果是 -1*
表示乘法,1 * 2
的结果是 2**
表示乘方,1 ** 2
的结果是 1/
表示除法,1 / 2
的结果是 0.5//
表示整除,1 // 2
的结果是 0 (相当于除法结果向下取整)%
表示取余,1 % 2
的结果是 1逻辑运算符
>
表示大于,1 > 2
的结果是 False>=
表示大于等于, 1 >= 2
的结果是 False<=
表示小于,1 <= 2
的结果是 True<
表示小于等于, 1 < 2
的结果是 True==
表示等于, 1 == 2
的结果是 False!=
表示不等于, 1 != 2
的结果是 Trueand
表示逻辑"与",True and False
的结果是 Falseor
表示逻辑"或",True or False
的结果是 Truenot
表示逻辑"非",not True
的结果是 False位运算符
>>
表示右移操作<<
表示左移操作&
表示按位与|
表示按位或^
表示按位异或~
表示按位取反其中最常用的是算数运算符与逻辑运算符,位运算符在 集合 操作中经常使用。
附:逻辑运算参照表
X | Y | X and Y | X or Y | not X | not Y |
---|---|---|---|---|---|
True | True | True | True | False | False |
True | False | False | True | False | True |
False | False | False | False | True | True |
False | True | False | True | True | False |
问题:给你任意五个整数和一个目标值target,找到这五个整数中和为target的那两个整数。
例如:
输入:2,3,7,11,15, target = 13
输出:2,11
解释:第0个数和第3个数的和为13 (注:编程时我们习惯从第0个开始数)
## 尝试求解,改变 a b 的值依次两两尝试,直到 a + b = target
target = 13
a = 2
b = 3
a + b == target
False
a = 2
b = 7
a + b == target
False
a = 2
b = 11
a + b == target
True
a,b
(2, 11)
在上述过程中,下列代码被重复多次书写,这时我们可以使用函数减少代码冗余。函数是一种可复用的部件,用于定义更加复杂的操作以减少代码冗余。
a = *
b = *
a + b == target
如果把运算符比作 “握” “抬手” “张嘴” “吞咽” 等基本动作,那么函数往往是 “吃饭” “喝水” 等一系列基本动作构成的复杂动作。
函数通过 def
关键字定义,函数的输入由函数名后括号内 参数 定义,函数的结果由 return
关键字定义。
另外程序中还存在着预先定义好的函数,例如我们在前面使用的 type
函数。以及 1.1.1.3 节中使用的 print
函数,它的功能是在屏幕输出某个变量的内容。可能你早就心存疑惑,为什么上面不用 print
也能输出呢?原因就在于交互式环境 notebook 会自动输出最后一个变量的内容。
## 自动输出最后的 target
variable
target
13
## 自动输出最后的 variable
target
variable
'Hi'
下面我们尝试定义一个函数减少之前代码的冗余。
## num1,num2 是输入的参数, return 后面的 a+b==target 是函数的结果
## 这里num1,num2,target 是形参
def check_sum(num1, num2, target):
## 在 def xxx(): 下面缩进的是函数的内容
a = num1
b = num2
return a + b == target
Python的一大语法特点是缩进敏感,这里第 5,6,7 行距离开头有 1个TAB / 4个空格 的距离并不只是为了美观,而是为了说明第 5,6,7 行是函数的内容。相比下面 C++ 函数用花括号的表示方法,相信你可以在这个角度感受 Python 的简洁。
int check_sum(int num1, int num2, int target)
{
int a = num1;
int b = num2;
return a + b == target;
}
下面我们尝试调用前面定义的 check_sum 函数完成之前的任务。
## 这里 2,3,13 是实参,函数返回结果 False
print(check_sum(2, 3, 13))
print(check_sum(2, 7, 13))
print(check_sum(2, 11, 13))
False
False
True
通过引入函数,上面的小例子变得更加简洁。然而我们发现无论测试哪两个数字的和与target一致,target的值是始终不变的。我们可以通过引入 局部变量 与 全局变量 简化函数。
在 check_sum
中定义的变量 a
, b
, num1
, num2
, target
都属于局部变量。
在 1.1.3.1 节中我们定义的 target
变量属于全局变量。当我们希望在函数内部使用全局变量时,应当用 global
关键字予以标注。
## 尝试在函数外部使用变量 num1,系统报错 num1 未定义
print(num1)
NameError: name 'num1' is not defined
## 尝试重新定义函数 check_sum, 此时函数参数中已不存在target
def check_sum(num1, num2):
global target
a = num1
b = num2
return a + b == target
print(check_sum(2, 3))
print(check_sum(2, 7))
print(check_sum(2, 11))
False
False
True
通过 全局变量 的方法,我们的函数变得更加简洁了。
通过运算符与函数,我们可以操作变量完成简单的任务。然而本质上我们还在把 Python 当作一个计算器使用,而不是一个可以实现自动化的编程语言,每行代码按照自上而下的顺序依次执行。通过控制流,我们可以让程序自动判断逻辑,自动跳转到某个位置,从而实现自动控制。
控制流中涉及几个关键字:
if-else
逻辑语句:判断某个条件是否成立,若成立则执行 if 语句,若不成立则执行 else 语句。while
循环语句:根据某一条件重复执行某个语句块。for-in
循环语句:根据某一序列进行循环迭代,直到迭代完整个序列。(序列这一概念在下章介绍)break
停止语句:停止当前 while 或 for-in 循环。continue
继续语句:暂停当前 while 或 for-in 循环,继续执行循环到下一个迭代。控制流就像语言中的“介词”,帮助我们联接名词与动词组成流畅优美的句子。
while 循环语句根据某一条件重复执行某个语句块,它的基本结构如下:
while ***:
statemnt
若 *** 的结果为 True 则继续重复执行 statement,若结果为 False 则停止循环。
## while 循环语句样例
a = 0
while a < 5:
a = a + 1
print(a)
1
2
3
4
5
在上面的代码中,首先我们定义变量 a 的值为 0,之后每次迭代使 a 的值增加 1,并输出当前 a 的值。
当 a 的值等于 5 时,循环停止。
for-in 据某一序列进行循环迭代,直到迭代完整个序列。
首先我们简单介绍下序列,序列只是一个有序的项的集合。例如方括号括起来的一组常量或变量 [0, 1, 2, 3, 4]
可以是一个序列。
循环的基本结构如下:
for * in ***:
statemnt
其中 *** 是被迭代的序列,* 是存储当前迭代元素的变量,当 *** 中所有元素都被迭代一次后,循环停止。
在下面的代码中,每次循环迭代序列中的一个元素,直到最后一个元素 5 被迭代。
## for-in 循环语句样例
for i in [1,2,3,4,5]:
print(i)
1
2
3
4
5
考虑之前的求和问题,在最坏的情况下,我们需要把所有元素两两求和才能得到答案。在5个元素时,我们最多需要对比10次,也就是重复写10次 check_sum 函数。但在有100个元素时,我们需要重复写4950次!因此这时我们用循环进行简化:
## 依次迭代元素 a,一共迭代 5 次
for a in [2,3,7,11,15]:
## 依次迭代元素 b,一共迭代 5 次
for b in [2,3,7,11,15]:
## 每个元素 a 与 5 个元素 b 依次两两尝试,一共迭代了 5 * 5 = 25 次
print(a, b, check_sum(a, b))
NameError: name 'check_sum' is not defined
在这个例子中,我们可以看到循环是可以嵌套的,在循环的每一次迭代中开启一个新的循环。外层的 for a in [2, 3, 7, 11, 15]
按照顺序选择第 1 个元素,内层的 for b in [2, 3, 7, 11, 15]
按照顺序选择第 2 个元素,每次迭代输出两个值以及是否与 target 相等。
最终我们找到输出 True 的两个元素 ( 2, 11 ),只要三行代码就可以解决问题!
if else 逻辑语句根据某一条件运行不同代码,它的基本结构如下:
if ***:
statement1
else:
statement2
若 *** 的结果为 True 则执行 statement1,若结果为 False 则执行 statement2
女朋友说,下班回来带一个西瓜。如果看到番茄,就买两个。最后程序员买回来两个西瓜。
虽然通过 for-in 不需要写很长代码,然而我们还需要从输出结果中一个个找。通过 if-else 逻辑语句,我们可以让程序真正的实现自动化!
这里 pass 代表不进行任何操作。
## 加入 if-else 逻辑语句
for a in [2,3,7,11,15]:
for b in [2,3,7,11,15]:
## 如果 check_sum(a,b)的结果为 True 则 输出,否则什么也不做
if check_sum(a,b):
print(a, b)
else:
pass
2 11
11 2
通过 if-else 逻辑语句,我们仅输出求和等于 target 的两个元素,不再需要从输出结果中逐个查找。
break 停止语句用于停止当前的循环。在上面的例子中,我们仅输出 1 种顺序即可,可以添加 break 停止语句在找到符合条件的两个元素后停止。
注意 break 仅能跳出当前循环,因此我们需要添加一个 finded 变量记录是否已找到符合条件的两个元素,若找到后外层循环也使用 break 跳出。
## 添加 break 停止语句
## finded 初始为 False
finded = False
for a in [2,3,7,11,15]:
for b in [2,3,7,11,15]:
if check_sum(a,b):
print(a, b)
## 若找到则 finded 变为 True
finded = True
break
else:
pass
## 若 finded 为 True,停止外层循环
if finded:
break
2 11
continue 语句用于停止当前循环并继续执行循环到下一个迭代,下面我们用一个例子展示 continue 的用法。
for a in [2,3,7,11,15]:
print(a)
continue
## continue 使循环停止,并继续执行下一个迭代,后面的内容被跳过
print(a + 1)
2
3
7
11
15
按规定,某种电子元件使用寿命超过 1000 小时为一级品。已知某一大批产品的一级品率为 0.2,现在从中随机地抽查 20 只。使用 Python 计算 20 只元件中恰好有 k 只 (k=0,1,…,20) 为一级品的概率为?
根据二项分布公式,所求的概率为:
P { X = k } = ( 20 k ) ( 0.2 ) k ( 0.8 ) 20 − k , k = 0 , 1 , ⋯ , 20 P\{X=k\}=\left(\begin{array}{c} 20 \\ k \end{array}\right)(0.2)^{k}(0.8)^{20-k}, k=0,1, \cdots, 20 P{X=k}=(20k)(0.2)k(0.8)20−k,k=0,1,⋯,20
## 定义阶乘函数,用于排列组合中
def multiple(x):
result = 1
while x != 0:
result = result * x
x = x - 1
return result
## 定义二项分布计算函数
def p_xk(k):
## 计算排列组合
temp = multiple(20) / (multiple(k) * multiple(20 - k))
## 计算概率
p = (0.2 ** k) * (0.8 ** (20 - k))
return temp * p
## 根据二项分布计算概率
k = 0
while k != 21:
print('P{ X =',k,'} = ', p_xk(k))
k = k + 1
P{ X = 0 } = 0.011529215046068483
P{ X = 1 } = 0.05764607523034242
P{ X = 2 } = 0.13690942867206327
P{ X = 3 } = 0.20536414300809488
P{ X = 4 } = 0.21819940194610074
P{ X = 5 } = 0.17455952155688062
P{ X = 6 } = 0.10909970097305038
P{ X = 7 } = 0.054549850486525185
P{ X = 8 } = 0.022160876760150862
P{ X = 9 } = 0.007386958920050286
P{ X = 10 } = 0.0020314137030138287
P{ X = 11 } = 0.00046168493250314287
P{ X = 12 } = 8.65659248443393e-05
P{ X = 13 } = 1.3317834591436813e-05
P{ X = 14 } = 1.6647293239296018e-06
P{ X = 15 } = 1.6647293239296019e-07
P{ X = 16 } = 1.3005697843200012e-08
P{ X = 17 } = 7.65041049600001e-10
P{ X = 18 } = 3.1876710400000044e-11
P{ X = 19 } = 8.38860800000001e-13
P{ X = 20 } = 1.0485760000000012e-14