更新了部分文档
This commit is contained in:
parent
cf74785a34
commit
a6d501a725
|
|
@ -96,7 +96,7 @@ Visual Studio Code 是由微软开发能够在 Windows、 Linux 和 macOS 等操
|
|||
|
||||
按照行业惯例,我们学习任何一门编程语言写的第一个程序都是输出`hello, world`,因为这段代码是伟大的丹尼斯·里奇(C 语言之父,和肯·汤普森一起开发了 Unix 操作系统)和布莱恩·柯尼汉(awk 语言的发明者)在他们的不朽著作《*The C Programming Language*》中写的第一段代码,下面是对应的 Python 语言的版本。
|
||||
|
||||
```Python
|
||||
```python
|
||||
print('hello, world')
|
||||
```
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ print('hello, world')
|
|||
|
||||
上面的代码只有一个语句,在这个语句中,我们用到了一个名为`print`的函数,它可以帮助我们输出指定的内容;`print`函数圆括号中的`'hello, world'`是一个字符串,它代表了一段文本内容;在 Python 语言中,我们可以用单引号或双引号来表示一个字符串。不同于 C、C++ 或 Java 这样的编程语言,Python 代码中的语句不需要用分号来表示结束,也就是说,如果我们想再写一条语句,只需要回车换行即可,代码如下所示。此外,Python 代码也不需要通过编写名为`main`的入口函数来使其运行,提供入口函数是编写可执行的 C、C++ 或 Java 代码必须要做的事情,这一点很多程序员都不陌生,但是在 Python 语言中它并不是必要的。
|
||||
|
||||
```Python
|
||||
```python
|
||||
print('hello, world')
|
||||
print('goodbye, world')
|
||||
```
|
||||
|
|
@ -134,7 +134,7 @@ Python 中有两种形式的注释:
|
|||
1. 单行注释:以`#`和空格开头,可以注释掉从`#`开始后面一整行的内容。
|
||||
2. 多行注释:三个引号(通常用双引号)开头,三个引号结尾,通常用于添加多行说明性内容。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
第一个Python程序 - hello, world
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
1. 整型(`int`):Python 中可以处理任意大小的整数,而且支持二进制(如`0b100`,换算成十进制是4)、八进制(如`0o100`,换算成十进制是64)、十进制(`100`)和十六进制(`0x100`,换算成十进制是256)的表示法。运行下面的代码,看看会输出什么。
|
||||
|
||||
```Python
|
||||
```python
|
||||
print(0b100) # 二进制整数
|
||||
print(0o100) # 八进制整数
|
||||
print(100) # 十进制整数
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
2. 浮点型(`float`):浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如`123.456`)之外还支持科学计数法(如`1.23456e2`,表示$\small{1.23456 \times 10^{2}}$)。运行下面的代码,看看会输出什么。
|
||||
|
||||
```Python
|
||||
```python
|
||||
print(123.456) # 数学写法
|
||||
print(1.23456e2) # 科学计数法
|
||||
```
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
下面通过例子来说明变量的类型和变量的使用。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
使用变量保存数据并进行加减乘除运算
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ print(a / b) # 3.75
|
|||
|
||||
在 Python 中可以使用`type`函数对变量的类型进行检查。程序设计中函数的概念跟数学上函数的概念非常类似,数学上的函数相信大家并不陌生,它包括了函数名、自变量和因变量。如果暂时不理解函数这个概念也不要紧,我们会在后续的内容中专门讲解函数的定义和使用。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
使用type函数检查变量的类型
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ print(type(d)) # <class 'bool'>
|
|||
|
||||
下面的例子为大家演示了Python中类型转换的操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
变量的类型转换操作
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
> **说明**:素数指的是只能被 1 和自身整除的正整数(不包括 1),之前我们写过判断素数的代码,这里相当于是一个升级版本。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
输出100以内的素数
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ for num in range(2, 100):
|
|||
|
||||
> **说明**:斐波那契数列(Fibonacci sequence),通常也被称作黄金分割数列,是意大利数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)在《计算之书》中研究理想假设条件下兔子成长率问题而引入的数列,因此这个数列也常被戏称为“兔子数列”。斐波那契数列的特点是数列的前两个数都是 1,从第三个数开始,每个数都是它前面两个数的和。按照这个规律,斐波那契数列的前 10 个数是:`1, 1, 2, 3, 5, 8, 13, 21, 34, 55`。斐波那契数列在现代物理、准晶体结构、化学等领域都有直接的应用。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
输出斐波那契数列中的前20个数
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ for x in range(0, 21):
|
|||
|
||||
> **说明**:CRAPS又称花旗骰,是美国拉斯维加斯非常受欢迎的一种的桌上赌博游戏。该游戏使用两粒骰子,玩家通过摇两粒骰子获得点数进行游戏。简化后的规则是:玩家第一次摇骰子如果摇出了 7 点或 11 点,玩家胜;玩家第一次如果摇出 2 点、3 点或 12 点,庄家胜;玩家如果摇出其他点数则游戏继续,玩家重新摇骰子,如果玩家摇出了 7 点,庄家胜;如果玩家摇出了第一次摇的点数,玩家胜;其他点数玩家继续摇骰子,直到分出胜负。为了增加代码的趣味性,我们设定游戏开始时玩家有 1000 元的赌注,每局游戏开始之前,玩家先下注,如果玩家获胜就可以获得对应下注金额的奖励,如果庄家获胜,玩家就会输掉自己下注的金额。游戏结束的条件是玩家破产(输光所有的赌注)。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
Craps赌博游戏
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ print(nums2)
|
|||
|
||||
场景三: 有一个整数列表`nums1`,创建一个新的列表`nums2`,将`nums1`中大于`50`的元素放到`nums2`中。
|
||||
|
||||
```Python
|
||||
```python
|
||||
nums1 = [35, 12, 97, 64, 55]
|
||||
nums2 = []
|
||||
for num in nums1:
|
||||
|
|
@ -126,7 +126,7 @@ print(nums2)
|
|||
|
||||
使用列表生成式做同样的事情,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
nums1 = [35, 12, 97, 64, 55]
|
||||
nums2 = [num for num in nums1 if num > 50]
|
||||
print(nums2)
|
||||
|
|
@ -148,7 +148,7 @@ print(scores[0][1])
|
|||
|
||||
如果想通过键盘输入的方式来录入5个学生3门课程的成绩并保存在列表中,可以使用如下所示的代码。
|
||||
|
||||
```Python
|
||||
```python
|
||||
scores = []
|
||||
for _ in range(5):
|
||||
temp = []
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ print(len('goodbye, world')) # 14
|
|||
|
||||
#### 索引和切片
|
||||
|
||||
字符串的索引和切片操作跟列表几乎区别,因为字符串也是一种有序序列,可以通过正向或反向的整数索引访问其中的元素。但是有一点需要注意,因为**字符串是不可变类型**,所以**不能通过索引运算修改字符串中的字符**。
|
||||
字符串的索引和切片操作跟列表、元组几乎没有区别,因为字符串也是一种有序序列,可以通过正向或反向的整数索引访问其中的元素。但是有一点需要注意,因为**字符串是不可变类型**,所以**不能通过索引运算修改字符串中的字符**。
|
||||
|
||||
```python
|
||||
s = 'abc123456'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
## 常用数据结构之集合
|
||||
|
||||
在学习了列表和元组之后,我们再来学习一种容器型的数据类型,它的名字叫集合(set)。说到集合这个词大家一定不会陌生,在数学课本上就有这个概念。如果我们**把一定范围的、确定的、可以区别的事物当作一个整体来看待**,那么这个整体就是集合,集合中的各个事物称为集合的**元素**。通常,集合需要满足以下特性:
|
||||
在学习了列表和元组之后,我们再来学习一种容器型的数据类型,它的名字叫集合(set)。说到集合这个词大家一定不会陌生,在数学课本上就有这个概念。如果我们**把一定范围的、确定的、可以区别的事物当作一个整体来看待**,那么这个整体就是集合,集合中的各个事物称为集合的**元素**。通常,集合需要满足以下要求:
|
||||
|
||||
1. **无序性**:一个集合中,每个元素的地位都是相同的,元素之间是无序的。
|
||||
2. **互异性**:一个集合中,任何两个元素都是不相同的,即元素在集合中只能出现一次。
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
Python 程序中的集合跟数学上的集合没有什么本质区别,需要强调的是上面所说的无序性和互异性。无序性说明集合中的元素并不像列中的元素那样存在某种次序,可以通过索引运算就能访问任意元素,**集合并不支持索引运算**。另外,集合的互异性决定了**集合中不能有重复元素**,这一点也是集合区别于列表的地方,我们无法将重复的元素添加到一个集合中。集合类型必然是支持`in`和`not in`成员运算的,这样就可以确定一个元素是否属于集合,也就是上面所说的集合的确定性。**集合的成员运算在性能上要优于列表的成员运算**,这是集合的底层存储特性决定的,此处我们暂时不做讨论,大家记住这个结论即可。
|
||||
|
||||
> **说明**:集合底层使用了哈希存储(散列存储),对哈希存储感兴趣的读者可以看看维基百科上“散列表”这个词条。
|
||||
> **说明**:集合底层使用了哈希存储(散列存储),对哈希存储不了解的读者可以先看看“Hello 算法”网站对[哈希表](https://www.hello-algo.com/chapter_hashing/)的讲解,感谢作者的开源精神。
|
||||
|
||||
### 创建集合
|
||||
|
||||
|
|
@ -31,7 +31,9 @@ set5 = {num for num in range(1, 20) if num % 3 == 0 or num % 7 == 0}
|
|||
print(set5)
|
||||
```
|
||||
|
||||
需要提醒大家,集合中的元素必须是`hashable`类型,使用哈希存储的容器都会对元素提出这一要求。所谓`hashable`类型指的是能够计算出哈希码的数据类型,通常不可变类型都是`hashable`类型,如整数(`int`)、浮点小数(`float`)、布尔值(`bool`)、字符串(`str`)、元组(`tuple`)等。可变类型都不是`hashable`类型,因为可变类型无法计算出确定的哈希码,所以它们不能放到集合中。例如:我们不能将列表作为集合中的元素;同理,由于集合本身也是可变类型,所以集合也不能作为集合中的元素。我们可以创建出嵌套的列表,但是我们不能创建出嵌套的集合,这一点在使用集合的时候一定要引起注意。
|
||||
需要提醒大家,集合中的元素必须是`hashable`类型,所谓`hashable`类型指的是能够计算出哈希码的数据类型,通常不可变类型都是`hashable`类型,如整数(`int`)、浮点小数(`float`)、布尔值(`bool`)、字符串(`str`)、元组(`tuple`)等。可变类型都不是`hashable`类型,因为可变类型无法计算出确定的哈希码,所以它们不能放到集合中。例如:我们不能将列表作为集合中的元素;同理,由于集合本身也是可变类型,所以集合也不能作为集合中的元素。我们可以创建出嵌套列表(列表的元素也是列表),但是我们不能创建出嵌套的集合,这一点在使用集合的时候一定要引起注意。
|
||||
|
||||
> **温馨提示**:如果不理解上面提到的哈希码、哈希存储这些概念,可以先放放,因为它并不影响你继续学习和使用 Python 语言。当然,如果是计算机专业的小伙伴,不理解哈希存储是很难被原谅的,要赶紧去补课了。
|
||||
|
||||
### 元素的遍历
|
||||
|
||||
|
|
@ -47,7 +49,7 @@ for elem in set1:
|
|||
|
||||
### 集合的运算
|
||||
|
||||
Python 为集合类型提供了非常丰富的运算符,主要包括:成员运算、交集运算、并集运算、差集运算、比较运算(相等性、子集、超集)等。
|
||||
Python 为集合类型提供了非常丰富的运算,主要包括:成员运算、交集运算、并集运算、差集运算、比较运算(相等性、子集、超集)等。
|
||||
|
||||
#### 成员运算
|
||||
|
||||
|
|
@ -130,7 +132,7 @@ print(set2.issuperset(set1)) # True
|
|||
|
||||
### 集合的方法
|
||||
|
||||
刚才我们说过,Python 中的集合是可变类型,我们可以通过集合类型的方法向集合添加元素或从集合中删除元素。
|
||||
刚才我们说过,Python 中的集合是可变类型,我们可以通过集合的方法向集合添加元素或从集合中删除元素。
|
||||
|
||||
```python
|
||||
set1 = {1, 10, 100}
|
||||
|
|
@ -151,7 +153,7 @@ set1.clear()
|
|||
print(set1) # set()
|
||||
```
|
||||
|
||||
> **说明**:删除集合元素的`remove`方法在元素不存在时会引发`KeyError`错误,所以上面的代码中我们先通过成员运算判断元素是否在集合中。集合类型还有一个`pop`方法可以从集合中随机删除一个元素,该方法在删除元素的同时会获得被删除的元素,而`remove`和`discard`方法仅仅是删除元素,不会获得被删除的元素。
|
||||
> **说明**:删除元素的`remove`方法在元素不存在时会引发`KeyError`错误,所以上面的代码中我们先通过成员运算判断元素是否在集合中。集合类型还有一个`pop`方法可以从集合中随机删除一个元素,该方法在删除元素的同时会返回(获得)被删除的元素,而`remove`和`discard`方法仅仅是删除元素,不会返回(获得)被删除的元素。
|
||||
|
||||
集合类型还有一个名为`isdisjoint`的方法可以判断两个集合有没有相同的元素,如果没有相同元素,该方法返回`True`,否则该方法返回`False`,代码如下所示。
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
## 常用数据结构之字典
|
||||
|
||||
迄今为止,我们已经为大家介绍了Python中的三种容器型数据类型(列表、元组、集合),但是这些数据类型仍然不足以帮助我们解决所有的问题。例如,我们需要一个变量来保存一个人的多项信息,包括:姓名、年龄、身高、体重、家庭住址、本人手机号、紧急联系人手机号,此时你会发现,我们之前学过的列表、元组和集合类型都不够好使。
|
||||
迄今为止,我们已经为大家介绍了 Python 中的三种容器型数据类型(列表、元组、集合),但是这些数据类型仍然不足以帮助我们解决所有的问题。例如,我们需要一个变量来保存一个人的多项信息,包括:姓名、年龄、身高、体重、家庭住址、本人手机号、紧急联系人手机号,此时你会发现,我们之前学过的列表、元组和集合类型都不够好使。
|
||||
|
||||
```Python
|
||||
```python
|
||||
person1 = ['王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877']
|
||||
person2 = ('王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877')
|
||||
person3 = {'王大锤', 55, 168, 60, '成都市武侯区科华北路62号1栋101', '13122334455', '13800998877'}
|
||||
|
|
@ -20,7 +20,7 @@ Python 程序中的字典跟现实生活中的字典很像,它以键值对(
|
|||
|
||||
Python 中创建字典可以使用`{}`字面量语法,这一点跟上一节课讲的集合是一样的。但是字典的`{}`中的元素是以键值对的形式存在的,每个元素由`:`分隔的两个值构成,`:`前面是键,`:`后面是值,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
xinhua = {
|
||||
'麓': '山脚下',
|
||||
'路': '道,往来通行的地方;方面,地区:南~货,外~货;种类:他俩是一~人',
|
||||
|
|
@ -44,7 +44,7 @@ print(person)
|
|||
|
||||
当然,如果愿意,我们也可以使用内置函数`dict`或者是字典的生成式语法来创建字典,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
# dict函数(构造器)中的每一组参数就是字典中的一组键值对
|
||||
person = dict(name='王大锤', age=55, height=168, weight=60, addr='成都市武侯区科华北路62号1栋101')
|
||||
print(person) # {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
|
|
@ -60,10 +60,16 @@ items3 = {x: x ** 3 for x in range(1, 6)}
|
|||
print(items3) # {1: 1, 2: 8, 3: 27, 4: 64, 5: 125}
|
||||
```
|
||||
|
||||
想知道字典中一共有多少组键值对,仍然是使用`len`函数;如果想对字典进行遍历,可以用`for`循环,但是需要注意,`for`循环只是对字典的键进行了遍历,不过没关系,在学习了字典的索引运算后,我们可以通过字典的键获取到和这个键对应的值。
|
||||
想知道字典中一共有多少组键值对,仍然是使用`len`函数;如果想对字典进行遍历,可以用`for`循环,但是需要注意,`for`循环只是对字典的键进行了遍历,不过没关系,在学习了字典的索引运算后,我们可以通过字典的键访问它对应的值。
|
||||
|
||||
```Python
|
||||
person = {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
```python
|
||||
person = {
|
||||
'name': '王大锤',
|
||||
'age': 55,
|
||||
'height': 168,
|
||||
'weight': 60,
|
||||
'addr': '成都市武侯区科华北路62号1栋101'
|
||||
}
|
||||
print(len(person)) # 5
|
||||
for key in person:
|
||||
print(key)
|
||||
|
|
@ -71,9 +77,30 @@ for key in person:
|
|||
|
||||
### 字典的运算
|
||||
|
||||
对于字典类型来说,成员运算和索引运算肯定是很重要的,前者可以判定指定的键在不在字典中,后者可以通过键获取对应的值或者向字典中添加新的键值对。值得注意的是,字典的索引不同于列表的索引,列表中的元素因为有属于自己有序号,所以列表的索引是一个整数;字典中因为保存的是键值对,所以字典需要用键去索引对应的值。需要**特别提醒**大家注意的是,**字典中的键必须是不可变类型**,例如整数(`int`)、浮点数(`float`)、字符串(`str`)、元组(`tuple`)等类型,这一点跟集合类型对元素的要求是一样的;很显然,之前我们讲的列表(`list`)和集合(`set`)不能作为字典中的键,字典类型本身也不能再作为字典中的键,因为字典也是可变类型,但是字典可以作为字典中的值。大家可以先看看下面的代码,了解一下字典的成员运算和索引运算。
|
||||
对于字典类型来说,成员运算和索引运算肯定是很重要的,前者可以判定指定的键在不在字典中,后者可以通过键访问对应的值或者向字典中添加新的键值对。值得注意的是,字典的索引不同于列表的索引,列表中的元素因为有属于自己有序号,所以列表的索引是一个整数;字典中因为保存的是键值对,所以字典需要用键去索引对应的值。需要**特别提醒**大家注意的是,**字典中的键必须是不可变类型**,例如整数(`int`)、浮点数(`float`)、字符串(`str`)、元组(`tuple`)等类型,这一点跟集合类型对元素的要求是一样的;很显然,之前我们讲的列表(`list`)和集合(`set`)不能作为字典中的键,字典类型本身也不能再作为字典中的键,因为字典也是可变类型,但是列表、集合、字典都可以作为字典中的值,例如:
|
||||
|
||||
```Python
|
||||
```python
|
||||
person = {
|
||||
'name': '王大锤',
|
||||
'age': 55,
|
||||
'height': 168,
|
||||
'weight': 60,
|
||||
'addr': ['成都市武侯区科华北路62号1栋101', '北京市西城区百万庄大街1号'],
|
||||
'car': {
|
||||
'brand': 'BMW X7',
|
||||
'maxSpeed': '250',
|
||||
'length': 5170,
|
||||
'width': 2000,
|
||||
'height': 1835,
|
||||
'displacement': 3.0
|
||||
}
|
||||
}
|
||||
print(person)
|
||||
```
|
||||
|
||||
大家可以看看下面的代码,了解一下字典的成员运算和索引运算。
|
||||
|
||||
```python
|
||||
person = {'name': '王大锤', 'age': 55, 'height': 168, 'weight': 60, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
|
||||
# 成员运算
|
||||
|
|
@ -118,7 +145,7 @@ for key, value in person.items():
|
|||
print(f'{key}:\t{value}')
|
||||
```
|
||||
|
||||
字典的`update`方法会用一个字典更新另一个字典中的键值对。例如,有两个字典`x`和`y`,当执行`x.update(y)`操作时,`x`跟`y`相同的键对应的值会`y`中的值被更新,而`y`中有但`x`中没有的键值对会直接添加到`x`中,代码如下所示。
|
||||
字典的`update`方法实现两个字典的合并操作。例如,有两个字典`x`和`y`,当执行`x.update(y)`操作时,`x`跟`y`相同的键对应的值会被`y`中的值更新,而`y`中有但`x`中没有的键值对会直接添加到`x`中,代码如下所示。
|
||||
|
||||
```python
|
||||
person1 = {'name': '王大锤', 'age': 55, 'height': 178}
|
||||
|
|
@ -127,7 +154,16 @@ person1.update(person2)
|
|||
print(person1) # {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
```
|
||||
|
||||
可以通过`pop`或`popitem`方法从字典中删除元素,前者会返回键对应的值,但是如果字典中不存在指定的键,会引发`KeyError`错误;后者在删除元素时,会返回键和值组成的二元组。字典的`clear`方法会清空字典中所有的键值对,代码如下所示。
|
||||
如果使用 Python 3.9 及以上的版本,也可以使用`|`运算符来完成同样的操作,代码如下所示。
|
||||
|
||||
```python
|
||||
person1 = {'name': '王大锤', 'age': 55, 'height': 178}
|
||||
person2 = {'age': 25, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
person1 |= person2
|
||||
print(person1) # {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
```
|
||||
|
||||
可以通过`pop`或`popitem`方法从字典中删除元素,前者会返回(获得)键对应的值,但是如果字典中不存在指定的键,会引发`KeyError`错误;后者在删除元素时,会返回(获得)键和值组成的二元组。字典的`clear`方法会清空字典中所有的键值对,代码如下所示。
|
||||
|
||||
```python
|
||||
person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
|
|
@ -141,7 +177,7 @@ print(person) # {}
|
|||
|
||||
跟列表一样,从字典中删除元素也可以使用`del`关键字,在删除元素的时候如果指定的键索引不到对应的值,一样会引发`KeyError`错误,具体的做法如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
person = {'name': '王大锤', 'age': 25, 'height': 178, 'addr': '成都市武侯区科华北路62号1栋101'}
|
||||
del person['age']
|
||||
del person['addr']
|
||||
|
|
@ -154,7 +190,7 @@ print(person) # {'name': '王大锤', 'height': 178}
|
|||
|
||||
**例子1**:输入一段话,统计每个英文字母出现的次数,按出现次数从高到低输出。
|
||||
|
||||
```Python
|
||||
```python
|
||||
sentence = input('请输入一段话: ')
|
||||
counter = {}
|
||||
for ch in sentence:
|
||||
|
|
@ -204,7 +240,7 @@ x 出现了 1 次.
|
|||
|
||||
> **说明**:可以用字典的生成式语法来创建这个新字典。
|
||||
|
||||
```Python
|
||||
```python
|
||||
stocks = {
|
||||
'AAPL': 191.88,
|
||||
'GOOG': 1186.96,
|
||||
|
|
@ -226,4 +262,4 @@ print(stocks2)
|
|||
|
||||
### 总结
|
||||
|
||||
Python 程序中的字典跟现实生活中字典非常像,允许我们**以键值对的形式保存数据**,再**通过键索引对应的值**。这是一种非常**有利于数据检索**的数据类型。再次提醒大家注意,**字典中的键必须是不可变类型**,字典中的值可以是任意类型。
|
||||
Python 程序中的字典跟现实生活中字典非常像,允许我们**以键值对的形式保存数据**,再**通过键访问对应的值**。字典是一种非常**有利于数据检索**的数据类型,但是需要再次提醒大家,**字典中的键必须是不可变类型**,列表、集合、字典等类型的数据都不能作为字典的键。
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
我们回到之前讲过的一个例子,设计一个函数,传入任意多个参数,对其中`int`类型或`float`类型的元素实现求和操作。我们对之前的代码稍作调整,让整个代码更加紧凑一些,如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def calc(*args, **kwargs):
|
||||
items = list(args) + list(kwargs.values())
|
||||
result = 0
|
||||
|
|
@ -18,7 +18,7 @@ def calc(*args, **kwargs):
|
|||
|
||||
如果我们希望上面的`calc`函数不仅仅可以做多个参数的求和,还可以实现更多的甚至是自定义的二元运算,我们该怎么做呢?上面的代码只能求和是因为函数中使用了`+=`运算符,这使得函数跟加法运算形成了耦合关系,如果能解除这种耦合关系,函数的通用性和灵活性就会更好。解除耦合的办法就是将`+`运算符变成函数调用,并将其设计为函数的参数,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def calc(init_value, op_func, *args, **kwargs):
|
||||
items = list(args) + list(kwargs.values())
|
||||
result = init_value
|
||||
|
|
@ -55,7 +55,7 @@ print(calc(1, mul, 1, 2, 3, 4, 5)) # 120
|
|||
|
||||
如果我们没有提前定义好`add`和`mul`函数,也可以使用 Python 标准库中的`operator`模块提供的`add`和`mul`函数,它们分别代表了做加法和做乘法的二元运算,我们拿过来直接使用即可,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import operator
|
||||
|
||||
print(calc(0, operator.add, 1, 2, 3, 4, 5)) # 15
|
||||
|
|
@ -64,7 +64,7 @@ print(calc(1, operator.mul, 1, 2, 3, 4, 5)) # 120
|
|||
|
||||
Python 内置函数中有不少高阶函数,我们前面提到过的`filter`和`map`函数就是高阶函数,前者可以实现对序列中元素的过滤,后者可以实现对序列中元素的映射,例如我们要去掉一个整数列表中的奇数,并对所有的偶数求平方得到一个新的列表,就可以直接使用这两个函数来做到,具体的做法是如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def is_even(num):
|
||||
"""判断num是不是偶数"""
|
||||
return num % 2 == 0
|
||||
|
|
@ -82,7 +82,7 @@ print(new_nums) # [144, 64, 3600, 2704]
|
|||
|
||||
当然,要完成上面代码的功能,也可以使用列表生成式,列表生成式的做法更为简单优雅。
|
||||
|
||||
```Python
|
||||
```python
|
||||
old_nums = [35, 12, 8, 99, 60, 52]
|
||||
new_nums = [num ** 2 for num in old_nums if num % 2 == 0]
|
||||
print(new_nums) # [144, 64, 3600, 2704]
|
||||
|
|
@ -110,7 +110,7 @@ print(new_strings) # ['in', 'zoo', 'pear', 'apple', 'waxberry']
|
|||
|
||||
在使用高阶函数的时候,如果作为参数或者返回值的函数本身非常简单,一行代码就能够完成,也不需要考虑对函数的复用,那么我们可以使用 lambda 函数。Python 中的 lambda 函数是没有的名字函数,所以很多人也把它叫做**匿名函数**,lambda 函数只能有一行代码,代码中的表达式产生的运算结果就是这个匿名函数的返回值。之前的代码中,我们写的`is_even`和`square`函数都只有一行代码,我们可以考虑用 lambda 函数来替换掉它们,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
old_nums = [35, 12, 8, 99, 60, 52]
|
||||
new_nums = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, old_nums)))
|
||||
print(new_nums) # [144, 64, 3600, 2704]
|
||||
|
|
@ -120,7 +120,7 @@ print(new_nums) # [144, 64, 3600, 2704]
|
|||
|
||||
前面我们说过,Python 中的函数是“一等函数”,函数是可以直接赋值给变量的。在学习了 lambda 函数之后,前面我们写过的一些函数就可以用一行代码来实现它们了,大家可以看看能否理解下面的求阶乘和判断素数的函数。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import functools
|
||||
import operator
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
Python 语言中,装饰器是“**用一个函数装饰另外一个函数并为其提供额外的能力**”的语法现象。装饰器本身是一个函数,它的参数是被装饰的函数,它的返回值是一个带有装饰功能的函数。通过前面的描述,相信大家已经听出来了,装饰器是一个高阶函数,它的参数和返回值都是函数。但是,装饰器的概念对编程语言的初学者来说,还是让人头疼的,下面我们先通过一个简单的例子来说明装饰器的作用。假设有名为`downlaod`和`upload`的两个函数,分别用于文件的上传和下载,如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
import time
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ upload('Python从入门到住院.pdf')
|
|||
|
||||
现在有一个新的需求,我们希望知道调用`download`和`upload`函数上传下载文件到底用了多少时间,这应该如何实现呢?相信很多小伙伴已经想到了,我们可以在函数开始执行的时候记录一个时间,在函数调用结束后记录一个时间,两个时间相减就可以计算出下载或上传的时间,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
start = time.time()
|
||||
download('MySQL从删库到跑路.avi')
|
||||
end = time.time()
|
||||
|
|
@ -62,7 +62,7 @@ def record_time(func):
|
|||
|
||||
看懂这个结构后,我们就可以把记录时间的功能写到这个装饰器中,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import time
|
||||
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ def record_time(func):
|
|||
|
||||
写装饰器虽然颇费周折,但是这是个一劳永逸的骚操作,将来再有记录函数执行时间的需求时,我们只需要添加上面的装饰器即可。使用上面的装饰器函数有两种方式,第一种方式就是直接调用装饰器函数,传入被装饰的函数并获得返回值,我们可以用这个返回值直接替代原来的函数,那么在调用时就已经获得了装饰器提供的额外的能力(记录执行时间),大家试试下面的代码就明白了。
|
||||
|
||||
```Python
|
||||
```python
|
||||
download = record_time(download)
|
||||
upload = record_time(upload)
|
||||
download('MySQL从删库到跑路.avi')
|
||||
|
|
@ -94,7 +94,7 @@ upload('Python从入门到住院.pdf')
|
|||
|
||||
在 Python 中,使用装饰器很有更为便捷的**语法糖**(编程语言中添加的某种语法,这种语法对语言的功能没有影响,但是使用更加方法,代码的可读性也更强,我们将其称之为“语法糖”或“糖衣语法”),可以用`@装饰器函数`将装饰器函数直接放在被装饰的函数上,效果跟上面的代码相同。我们把完整的代码为大家罗列出来,大家可以再看看我们是如何定义和使用装饰器的。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
import time
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ upload('Python从入门到住院.pdf')
|
|||
|
||||
如果在代码的某些地方,我们想去掉装饰器的作用执行原函数,那么在定义装饰器函数的时候,需要做一点点额外的工作。Python 标准库`functools`模块的`wraps`函数也是一个装饰器,我们将它放在`wrapper`函数上,这个装饰器可以帮我们保留被装饰之前的函数,这样在需要取消装饰器时,可以通过被装饰函数的`__wrapped__`属性获得被装饰之前的函数。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
import time
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ upload.__wrapped__('Python从新手到大师.pdf')
|
|||
|
||||
Python 中允许函数嵌套定义,也允许函数之间相互调用,而且一个函数还可以直接或间接的调用自身。函数自己调用自己称为递归调用,那么递归调用有什么用处呢?现实中,有很多问题的定义本身就是一个递归定义,例如我们之前讲到的阶乘,非负整数`N`的阶乘是`N`乘以`N-1`的阶乘,即 $\small{N! = N \times (N-1)!}$ ,定义的左边和右边都出现了阶乘的概念,所以这是一个递归定义。既然如此,我们可以使用递归调用的方式来写一个求阶乘的函数,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def fac(num):
|
||||
if num in (0, 1):
|
||||
return 1
|
||||
|
|
@ -190,7 +190,7 @@ def fac(num):
|
|||
|
||||
上面的代码中,`fac`函数中又调用了`fac`函数,这就是所谓的递归调用。代码第2行的`if`条件叫做递归的收敛条件,简单的说就是什么时候要结束函数的递归调用,在计算阶乘时,如果计算到`0`或`1`的阶乘,就停止递归调用,直接返回`1`;代码第4行的`num * fac(num - 1)`是递归公式,也就是阶乘的递归定义。下面,我们简单的分析下,如果用`fac(5)`计算`5`的阶乘,整个过程会是怎样的。
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 递归调用函数入栈
|
||||
# 5 * fac(4)
|
||||
# 5 * (4 * fac(3))
|
||||
|
|
@ -211,7 +211,7 @@ print(fac(5)) # 120
|
|||
|
||||
再举一个之前讲过的生成斐波那契数列的例子,因为斐波那契数列前两个数都是`1`,从第三个数开始,每个数是前两个数相加的和,可以记为`f(n) = f(n - 1) + f(n - 2)`,很显然这又是一个递归的定义,所以我们可以用下面的递归调用函数来计算第`n`个斐波那契数。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def fib1(n):
|
||||
if n in (1, 2):
|
||||
return 1
|
||||
|
|
@ -224,7 +224,7 @@ for i in range(1, 21):
|
|||
|
||||
需要提醒大家,上面计算斐波那契数的代码虽然看起来非常简单明了,但执行性能是比较糟糕的。大家可以试一试,把上面代码`for`循环中`range`函数的第二个参数修改为`51`,即输出前50个斐波那契数,看看需要多长时间,也欢迎大家在评论区留下你的代码执行时间。至于为什么这么慢,大家可以自己思考一下原因。很显然,直接使用循环递推的方式获得斐波那契数列是更好的选择,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
def fib2(n):
|
||||
a, b = 0, 1
|
||||
for _ in range(n):
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
在 Python 语言中,我们可以使用`class`关键字加上类名来定义类,通过缩进我们可以确定类的代码块,就如同定义函数那样。在类的代码块中,我们需要写一些函数,我们说过类是一个抽象概念,那么这些函数就是我们对一类对象共同的动态特征的提取。写在类里面的函数我们通常称之为**方法**,方法就是对象的行为,也就是对象可以接收的消息。方法的第一个参数通常都是`self`,它代表了接收这个消息的对象本身。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Student:
|
||||
|
||||
def study(self, course_name):
|
||||
|
|
@ -42,7 +42,7 @@ class Student:
|
|||
|
||||
在我们定义好一个类之后,可以使用构造器语法来创建对象,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
stu1 = Student()
|
||||
stu2 = Student()
|
||||
print(stu1) # <__main__.Student object at 0x10ad5ac50>
|
||||
|
|
@ -54,7 +54,7 @@ print(hex(id(stu1)), hex(id(stu2))) # 0x10ad5ac50 0x10ad5acd0
|
|||
|
||||
接下来,我们尝试给对象发消息,即调用对象的方法。刚才的`Student`类中我们定义了`study`和`play`两个方法,两个方法的第一个参数`self`代表了接收消息的学生对象,`study`方法的第二个参数是学习的课程名称。Python中,给对象发消息有两种方式,请看下面的代码。
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 通过“类.方法”调用方法
|
||||
# 第一个参数是接收消息的对象
|
||||
# 第二个参数是学习的课程名称
|
||||
|
|
@ -74,7 +74,7 @@ stu2.play() # 学生正在玩游戏.
|
|||
|
||||
我们对上面的`Student`类稍作修改,给学生对象添加`name`(姓名)和`age`(年龄)两个属性。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Student:
|
||||
"""学生"""
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ class Student:
|
|||
|
||||
修改刚才创建对象和给对象发消息的代码,重新执行一次,看看程序的执行结果有什么变化。
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 调用Student类的构造器创建对象并传入初始化参数
|
||||
stu1 = Student('骆昊', 44)
|
||||
stu2 = Student('王大锤', 25)
|
||||
|
|
@ -117,7 +117,7 @@ stu2.play() # 王大锤正在玩游戏.
|
|||
|
||||
> **要求**:定义一个类描述数字时钟,提供走字和显示时间的功能。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import time
|
||||
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ while True:
|
|||
|
||||
> **要求**:定义一个类描述平面上的点,提供计算到另一个点距离的方法。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Point:
|
||||
"""平面上的点"""
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
在很多面向对象编程语言中,对象的属性通常会被设置为私有(private)或受保护(protected)的成员,简单的说就是不允许直接访问这些属性;对象的方法通常都是公开的(public),因为公开的方法是对象能够接受的消息,也是对象暴露给外界的调用接口,这就是所谓的访问可见性。在 Python 中,可以通过给对象属性名添加前缀下划线的方式来说明属性的访问可见性,例如,可以用`__name`表示一个私有属性,`_name`表示一个受保护属性,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Student:
|
||||
|
||||
def __init__(self, name, age):
|
||||
|
|
@ -30,7 +30,7 @@ Python 语言属于动态语言,维基百科对动态语言的解释是:“
|
|||
|
||||
在 Python 中,我们可以动态为对象添加属性,这是 Python 作为动态类型语言的一项特权,代码如下所示。需要提醒大家的是,对象的方法其实本质上也是对象的属性,如果给对象发送一个无法接收的消息,引发的异常仍然是`AttributeError`。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Student:
|
||||
|
||||
def __init__(self, name, age):
|
||||
|
|
@ -44,7 +44,7 @@ stu.sex = '男' # 给学生对象动态添加sex属性
|
|||
|
||||
如果不希望在使用对象时动态的为对象添加属性,可以使用 Python 语言中的`__slots__`魔法。对于`Student`类来说,可以在类中指定`__slots__ = ('name', 'age')`,这样`Student`类的对象只能有`name`和`age`属性,如果想动态添加其他属性将会引发异常,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Student:
|
||||
__slots__ = ('name', 'age')
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ stu.sex = '男'
|
|||
|
||||
举一个例子,定义一个三角形类,通过传入三条边的长度来构造三角形,并提供计算周长和面积的方法。计算周长和面积肯定是三角形对象的方法,这一点毫无疑问。但是在创建三角形对象时,传入的三条边长未必能构造出三角形,为此我们可以先写一个方法来验证给定的三条边长是否可以构成三角形,这种方法很显然就不是对象方法,因为在调用这个方法时三角形对象还没有创建出来。我们可以把这类方法设计为静态方法或类方法,也就是说这类方法不是发送给三角形对象的消息,而是发送给三角形类的消息,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Triangle(object):
|
||||
"""三角形"""
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ print(f'面积: {t.area}')
|
|||
|
||||
面向对象的编程语言支持在已有类的基础上创建新类,从而减少重复代码的编写。提供继承信息的类叫做父类(超类、基类),得到继承信息的类叫做子类(派生类、衍生类)。例如,我们定义一个学生类和一个老师类,我们会发现他们有大量的重复代码,而这些重复代码都是老师和学生作为人的公共属性和行为,所以在这种情况下,我们应该先定义人类,再通过继承,从人类派生出老师类和学生类,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Person:
|
||||
"""人"""
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
牌的属性显而易见,有花色和点数。我们可以用 0 到 3 的四个数字来代表四种不同的花色,但是这样的代码可读性会非常糟糕,因为我们并不知道黑桃、红心、草花、方块跟 0 到 3 的数字的对应关系。如果一个变量的取值只有有限多个选项,我们可以使用枚举。与 C、Java 等语言不同的是,Python 中没有声明枚举类型的关键字,但是可以通过继承`enum`模块的`Enum`类来创建枚举类型,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from enum import Enum
|
||||
|
||||
|
||||
|
|
@ -21,14 +21,14 @@ class Suite(Enum):
|
|||
|
||||
通过上面的代码可以看出,定义枚举类型其实就是定义符号常量,如`SPADE`、`HEART`等。每个符号常量都有与之对应的值,这样表示黑桃就可以不用数字 0,而是用`Suite.SPADE`;同理,表示方块可以不用数字 3, 而是用`Suite.DIAMOND`。注意,使用符号常量肯定是优于使用字面常量的,因为能够读懂英文就能理解符号常量的含义,代码的可读性会提升很多。Python 中的枚举类型是可迭代类型,简单的说就是可以将枚举类型放到`for-in`循环中,依次取出每一个符号常量及其对应的值,如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
for suite in Suite:
|
||||
print(f'{suite}: {suite.value}')
|
||||
```
|
||||
|
||||
接下来我们可以定义牌类。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Card:
|
||||
"""牌"""
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class Card:
|
|||
|
||||
可以通过下面的代码来测试下`Card`类。
|
||||
|
||||
```Python
|
||||
```python
|
||||
card1 = Card(Suite.SPADE, 5)
|
||||
card2 = Card(Suite.HEART, 13)
|
||||
print(card1) # ♠5
|
||||
|
|
@ -53,7 +53,7 @@ print(card2) # ♥K
|
|||
|
||||
接下来我们定义扑克类。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ class Poker:
|
|||
|
||||
可以通过下面的代码来测试下`Poker`类。
|
||||
|
||||
```Python
|
||||
```python
|
||||
poker = Poker()
|
||||
print(poker.cards) # 洗牌前的牌
|
||||
poker.shuffle()
|
||||
|
|
@ -94,7 +94,7 @@ print(poker.cards) # 洗牌后的牌
|
|||
|
||||
定义玩家类。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Player:
|
||||
"""玩家"""
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ class Player:
|
|||
|
||||
创建四个玩家并将牌发到玩家的手上。
|
||||
|
||||
```Python
|
||||
```python
|
||||
poker = Poker()
|
||||
poker.shuffle()
|
||||
players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
|
||||
|
|
@ -134,7 +134,7 @@ for player in players:
|
|||
|
||||
修改后的`Card`类代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Card:
|
||||
"""牌"""
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ class Card:
|
|||
|
||||
通过对上述需求的分析,可以看出部门经理、程序员、销售员都是员工,有相同的属性和行为,那么我们可以先设计一个名为`Employee`的父类,再通过继承的方式从这个父类派生出部门经理、程序员和销售员三个子类。很显然,后续的代码不会创建`Employee` 类的对象,因为我们需要的是具体的员工对象,所以这个类可以设计成专门用于继承的抽象类。Python 语言中没有定义抽象类的关键字,但是可以通过`abc`模块中名为`ABCMeta` 的元类来定义抽象类。关于元类的概念此处不展开讲解,当然大家不用纠结,照做即可。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ class Employee(metaclass=ABCMeta):
|
|||
|
||||
在上面的员工类中,有一个名为`get_salary`的方法用于结算月薪,但是由于还没有确定是哪一类员工,所以结算月薪虽然是员工的公共行为但这里却没有办法实现。对于暂时无法实现的方法,我们可以使用`abstractmethod`装饰器将其声明为抽象方法,所谓**抽象方法就是只有声明没有实现的方法**,**声明这个方法是为了让子类去重写这个方法**。接下来的代码展示了如何从员工类派生出部门经理、程序员、销售员这三个子类以及子类如何重写父类的抽象方法。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class Manager(Employee):
|
||||
"""部门经理"""
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ class Salesman(Employee):
|
|||
|
||||
我们通过下面的代码来完成这个工资结算系统,由于程序员和销售员需要分别录入本月的工作时间和销售额,所以在下面的代码中我们使用了 Python 内置的`isinstance`函数来判断员工对象的类型。我们之前讲过的`type`函数也能识别对象的类型,但是`isinstance`函数更加强大,因为它可以判断出一个对象是不是某个继承结构下的子类型,你可以简单的理解为`type`函数是对对象类型的精准匹配,而`isinstance`函数是对对象类型的模糊匹配。
|
||||
|
||||
```Python
|
||||
```python
|
||||
emps = [Manager('刘备'), Programmer('诸葛亮'), Manager('曹操'), Programmer('荀彧'), Salesman('张辽')]
|
||||
for emp in emps:
|
||||
if isinstance(emp, Programmer):
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
下面的例子演示了如何读取一个纯文本文件(一般指只有字符原生编码构成的文件,与富文本相比,纯文本不包含字符样式的控制元素,能够被最简单的文本编辑器直接读取)。
|
||||
|
||||
```Python
|
||||
```python
|
||||
file = open('致橡树.txt', 'r', encoding='utf-8')
|
||||
print(file.read())
|
||||
file.close()
|
||||
|
|
@ -42,7 +42,7 @@ file.close()
|
|||
|
||||
除了使用文件对象的`read`方法读取文件之外,还可以使用`for-in`循环逐行读取或者用`readlines`方法将文件按行读取到一个列表容器中,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
file = open('致橡树.txt', 'r', encoding='utf-8')
|
||||
for line in file:
|
||||
print(line, end='')
|
||||
|
|
@ -57,7 +57,7 @@ file.close()
|
|||
|
||||
如果要向文件中写入内容,可以在打开文件时使用`w`或者`a`作为操作模式,前者会截断之前的文本内容写入新的内容,后者是在原来内容的尾部追加新的内容。
|
||||
|
||||
```Python
|
||||
```python
|
||||
file = open('致橡树.txt', 'a', encoding='utf-8')
|
||||
file.write('\n标题:《致橡树》')
|
||||
file.write('\n作者:舒婷')
|
||||
|
|
@ -69,7 +69,7 @@ file.close()
|
|||
|
||||
请注意上面的代码,如果`open`函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码具有健壮性和容错性,我们可以**使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理**。Python中和异常相关的关键字有五个,分别是`try`、`except`、`else`、`finally`和`raise`,我们先看看下面的代码,再来为大家介绍这些关键字的用法。
|
||||
|
||||
```Python
|
||||
```python
|
||||
file = None
|
||||
try:
|
||||
file = open('致橡树.txt', 'r', encoding='utf-8')
|
||||
|
|
@ -160,7 +160,7 @@ BaseException
|
|||
|
||||
在Python中,可以使用`raise`关键字来引发异常(抛出异常对象),而调用者可以通过`try...except...`结构来捕获并处理异常。例如在函数中,当函数的执行条件不满足时,可以使用抛出异常的方式来告知调用者问题的所在,而调用者可以通过捕获处理异常来使得代码从异常中恢复,定义异常和抛出异常的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
class InputError(ValueError):
|
||||
"""自定义异常类型"""
|
||||
pass
|
||||
|
|
@ -177,7 +177,7 @@ def fac(num):
|
|||
|
||||
调用求阶乘的函数`fac`,通过`try...except...`结构捕获输入错误的异常并打印异常对象(显示异常信息),如果输入正确就计算阶乘并结束程序。
|
||||
|
||||
```Python
|
||||
```python
|
||||
flag = True
|
||||
while flag:
|
||||
num = int(input('n = '))
|
||||
|
|
@ -194,7 +194,7 @@ while flag:
|
|||
|
||||
用`with`上下文语法改写后的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
try:
|
||||
with open('致橡树.txt', 'r', encoding='utf-8') as file:
|
||||
print(file.read())
|
||||
|
|
@ -210,7 +210,7 @@ except UnicodeDecodeError:
|
|||
|
||||
读写二进制文件跟读写文本文件的操作类似,但是需要注意,在使用`open`函数打开文件时,如果要进行读操作,操作模式是`'rb'`,如果要进行写操作,操作模式是`'wb'`。还有一点,读写文本文件时,`read`方法的返回值以及`write`方法的参数是`str`对象(字符串),而读写二进制文件时,`read`方法的返回值以及`write`方法的参数是`bytes-like`对象(字节串)。下面的代码实现了将当前路径下名为`guido.jpg`的图片文件复制到`吉多.jpg`文件中的操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
try:
|
||||
with open('guido.jpg', 'rb') as file1:
|
||||
data = file1.read()
|
||||
|
|
@ -225,7 +225,7 @@ print('程序执行结束.')
|
|||
|
||||
如果要复制的图片文件很大,一次将文件内容直接读入内存中可能会造成非常大的内存开销,为了减少对内存的占用,可以为`read`方法传入`size`参数来指定每次读取的字节数,通过循环读取和写入的方式来完成上面的操作,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
try:
|
||||
with open('guido.jpg', 'rb') as file1, open('吉多.jpg', 'wb') as file2:
|
||||
data = file1.read(512)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ let obj = {
|
|||
|
||||
在Python中,如果要将字典处理成JSON格式(以字符串形式存在),可以使用`json`模块的`dumps`函数,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import json
|
||||
|
||||
my_dict = {
|
||||
|
|
@ -91,7 +91,7 @@ print(json.dumps(my_dict))
|
|||
|
||||
如果要将字典处理成JSON格式并写入文本文件,只需要将`dumps`函数换成`dump`函数并传入文件对象即可,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import json
|
||||
|
||||
my_dict = {
|
||||
|
|
@ -121,7 +121,7 @@ with open('data.json', 'w') as file:
|
|||
|
||||
我们可以通过下面的代码,读取上面创建的`data.json`文件,将JSON格式的数据还原成Python中的字典。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import json
|
||||
|
||||
with open('data.json', 'r') as file:
|
||||
|
|
@ -215,7 +215,7 @@ pip install requests
|
|||
|
||||
获取国内新闻并显示新闻标题和链接。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import requests
|
||||
|
||||
resp = requests.get('http://api.tianapi.com/guonei/?key=APIKey&num=10')
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ CSV文件可以使用文本编辑器或类似于Excel电子表格这类工具打
|
|||
|
||||
现有五个学生三门课程的考试成绩需要保存到一个CSV文件中,要达成这个目标,可以使用Python标准库中的`csv`模块,该模块的`writer`函数会返回一个`csvwriter`对象,通过该对象的`writerow`或`writerows`方法就可以将数据写入到CSV文件中,具体的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import csv
|
||||
import random
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ with open('scores.csv', 'w') as file:
|
|||
|
||||
需要说明的是上面的`writer`函数,除了传入要写入数据的文件对象外,还可以`dialect`参数,它表示CSV文件的方言,默认值是`excel`。除此之外,还可以通过`delimiter`、`quotechar`、`quoting`参数来指定分隔符(默认是逗号)、包围值的字符(默认是双引号)以及包围的方式。其中,包围值的字符主要用于当字段中有特殊符号时,通过添加包围值的字符可以避免二义性。大家可以尝试将上面第5行代码修改为下面的代码,然后查看生成的CSV文件。
|
||||
|
||||
```Python
|
||||
```python
|
||||
writer = csv.writer(file, delimiter='|', quoting=csv.QUOTE_ALL)
|
||||
```
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ writer = csv.writer(file, delimiter='|', quoting=csv.QUOTE_ALL)
|
|||
|
||||
如果要读取刚才创建的CSV文件,可以使用下面的代码,通过`csv`模块的`reader`函数可以创建出`csvreader`对象,该对象是一个迭代器,可以通过`next`函数或`for-in`循环读取到文件中的数据。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import csv
|
||||
|
||||
with open('scores.csv', 'r') as file:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pip install xlwt xlrd xlutils
|
|||
|
||||
例如在当前文件夹下有一个名为“阿里巴巴2020年股票数据.xls”的 Excel 文件,如果想读取并显示该文件的内容,可以通过如下所示的代码来完成。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import xlrd
|
||||
|
||||
# 使用xlrd模块的open_workbook函数打开指定Excel文件并获得Book对象(工作簿)
|
||||
|
|
@ -65,7 +65,7 @@ print(sheet.row_slice(3, 0, 5))
|
|||
|
||||
写入 Excel 文件可以通过`xlwt` 模块的`Workbook`类创建工作簿对象,通过工作簿对象的`add_sheet`方法可以添加工作表,通过工作表对象的`write`方法可以向指定单元格中写入数据,最后通过工作簿对象的`save`方法将工作簿写入到指定的文件或内存中。下面的代码实现了将5 个学生 3 门课程的考试成绩写入 Excel 文件的操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
|
||||
import xlwt
|
||||
|
|
@ -93,7 +93,7 @@ wb.save('考试成绩表.xls')
|
|||
|
||||
在写Excel文件时,我们还可以为单元格设置样式,主要包括字体(Font)、对齐方式(Alignment)、边框(Border)和背景(Background)的设置,`xlwt`对这几项设置都封装了对应的类来支持。要设置单元格样式需要首先创建一个`XFStyle`对象,再通过该对象的属性对字体、对齐方式、边框等进行设定,例如在上面的例子中,如果希望将表头单元格的背景色修改为黄色,可以按照如下的方式进行操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
header_style = xlwt.XFStyle()
|
||||
pattern = xlwt.Pattern()
|
||||
pattern.pattern = xlwt.Pattern.SOLID_PATTERN
|
||||
|
|
@ -107,7 +107,7 @@ for index, title in enumerate(titles):
|
|||
|
||||
如果希望为表头设置指定的字体,可以使用`Font`类并添加如下所示的代码。
|
||||
|
||||
```Python
|
||||
```python
|
||||
font = xlwt.Font()
|
||||
# 字体名称
|
||||
font.name = '华文楷体'
|
||||
|
|
@ -126,7 +126,7 @@ header_style.font = font
|
|||
|
||||
如果希望表头垂直居中对齐,可以使用下面的代码进行设置。
|
||||
|
||||
```Python
|
||||
```python
|
||||
align = xlwt.Alignment()
|
||||
# 垂直方向的对齐方式
|
||||
align.vert = xlwt.Alignment.VERT_CENTER
|
||||
|
|
@ -137,7 +137,7 @@ header_style.alignment = align
|
|||
|
||||
如果希望给表头加上黄色的虚线边框,可以使用下面的代码来设置。
|
||||
|
||||
```Python
|
||||
```python
|
||||
borders = xlwt.Borders()
|
||||
props = (
|
||||
('top', 'top_colour'), ('right', 'right_colour'),
|
||||
|
|
@ -153,7 +153,7 @@ header_style.borders = borders
|
|||
|
||||
如果要调整单元格的宽度(列宽)和表头的高度(行高),可以按照下面的代码进行操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 设置行高为40px
|
||||
sheet.row(0).set_style(xlwt.easyxf(f'font:height {20 * 40}'))
|
||||
titles = ('姓名', '语文', '数学', '英语')
|
||||
|
|
@ -170,7 +170,7 @@ for index, title in enumerate(titles):
|
|||
|
||||
实现公式计算的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import xlrd
|
||||
import xlwt
|
||||
from xlutils.copy import copy
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pip install openpyxl
|
|||
|
||||
例如在当前文件夹下有一个名为“阿里巴巴2020年股票数据.xlsx”的 Excel 文件,如果想读取并显示该文件的内容,可以通过如下所示的代码来完成。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import datetime
|
||||
|
||||
import openpyxl
|
||||
|
|
@ -63,7 +63,7 @@ for row_ch in range(2, sheet.max_row + 1):
|
|||
|
||||
下面我们使用`openpyxl`来进行写 Excel 操作。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
|
||||
import openpyxl
|
||||
|
|
@ -93,7 +93,7 @@ wb.save('考试成绩表.xlsx')
|
|||
|
||||
在使用`openpyxl`操作 Excel 时,如果要调整单元格的样式,可以直接通过单元格对象(`Cell`对象)的属性进行操作。单元格对象的属性包括字体(`font`)、对齐(`alignment`)、边框(`border`)等,具体的可以参考`openpyxl`的[官方文档](https://openpyxl.readthedocs.io/en/stable/index.html)。在使用`openpyxl`时,如果需要做公式计算,可以完全按照 Excel 中的操作方式来进行,具体的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font, Alignment, Border, Side
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ wb.save('考试成绩表.xlsx')
|
|||
|
||||
通过`openpyxl`库,可以直接向 Excel 中插入统计图表,具体的做法跟在 Excel 中插入图表大体一致。我们可以创建指定类型的图表对象,然后通过该对象的属性对图表进行设置。当然,最为重要的是为图表绑定数据,即横轴代表什么,纵轴代表什么,具体的数值是多少。最后,可以将图表对象添加到表单中,具体的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.chart import BarChart, Reference
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ wb.save('demo.xlsx')
|
|||
|
||||
运行上面的代码,打开生成的 Excel 文件,效果如下图所示。
|
||||
|
||||
<img src="res/20210819235009.png" alt="image-20210819235009026" width="75%">
|
||||
<img src="res/20210819235009.png" width="75%">
|
||||
|
||||
### 总结
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pip install python-docx
|
|||
|
||||
按照[官方文档](https://python-docx.readthedocs.io/en/latest/)的介绍,我们可以使用如下所示的代码来生成一个简单的 Word 文档。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from docx import Document
|
||||
from docx.shared import Cm, Pt
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ document.save('demo.docx')
|
|||
|
||||
对于一个已经存在的 Word 文件,我们可以通过下面的代码去遍历它所有的段落并获取对应的内容。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from docx import Document
|
||||
from docx.document import Document as Doc
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ for no, p in enumerate(doc.paragraphs):
|
|||
|
||||
接下来我们读取该文件,将占位符替换为真实信息,就可以生成一个新的 Word 文档,如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from docx import Document
|
||||
from docx.document import Document as Doc
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ pip install python-pptx
|
|||
|
||||
用 Python 操作 PowerPoint 的内容,因为实际应用场景不算很多,我不打算在这里进行赘述,有兴趣的读者可以自行阅读`python-pptx`的[官方文档](https://python-pptx.readthedocs.io/en/latest/),下面仅展示一段来自于官方文档的代码。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from pptx import Presentation
|
||||
|
||||
# 创建幻灯片对象
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pip install PyPDF2
|
|||
|
||||
`PyPDF2`没有办法从 PDF 文档中提取图像、图表或其他媒体,但它可以提取文本,并将其返回为 Python 字符串。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import PyPDF2
|
||||
|
||||
reader = PyPDF2.PdfReader('test.pdf')
|
||||
|
|
@ -35,7 +35,7 @@ pdf2text.py test.pdf
|
|||
|
||||
上面的代码中通过创建`PdfFileReader`对象的方式来读取 PDF 文档,该对象的`getPage`方法可以获得PDF文档的指定页并得到一个`PageObject`对象,通过`PageObject`对象的`rotateClockwise`和`rotateCounterClockwise`方法可以实现页面的顺时针和逆时针方向旋转,通过`PageObject`对象的`addBlankPage`方法可以添加一个新的空白页,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
reader = PyPDF2.PdfReader('XGBoost.pdf')
|
||||
writer = PyPDF2.PdfWriter()
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ with open('temp.pdf', 'wb') as file_obj:
|
|||
|
||||
使用`PyPDF2`中的`PdfFileWrite`对象可以为PDF文档加密,如果需要给一系列的PDF文档设置统一的访问口令,使用Python程序来处理就会非常的方便。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import PyPDF2
|
||||
|
||||
reader = PyPDF2.PdfReader('XGBoost.pdf')
|
||||
|
|
@ -73,7 +73,7 @@ with open('temp.pdf', 'wb') as file_obj:
|
|||
|
||||
上面提到的`PageObject`对象还有一个名为`mergePage`的方法,可以两个 PDF 页面进行叠加,通过这个操作,我们很容易实现给PDF文件添加水印的功能。例如要给上面的“XGBoost.pdf”文件添加一个水印,我们可以先准备好一个提供水印页面的 PDF 文件,然后将包含水印的`PageObject`读取出来,然后再循环遍历“XGBoost.pdf”文件的每个页,获取到`PageObject`对象,然后通过`mergePage`方法实现水印页和原始页的合并,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
reader1 = PyPDF2.PdfReader('XGBoost.pdf')
|
||||
reader2 = PyPDF2.PdfReader('watermark.pdf')
|
||||
writer = PyPDF2.PdfWriter()
|
||||
|
|
@ -99,7 +99,7 @@ pip install reportlab
|
|||
|
||||
下面通过一个例子为大家展示`reportlab`的用法。
|
||||
|
||||
```Python
|
||||
```python
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
1. 读取和显示图像
|
||||
|
||||
```Python
|
||||
```python
|
||||
from PIL import Image
|
||||
|
||||
# 读取图像获得Image对象
|
||||
|
|
@ -44,7 +44,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
2. 剪裁图像
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 通过Image对象的crop方法指定剪裁区域剪裁图像
|
||||
image.crop((80, 20, 310, 360)).show()
|
||||
```
|
||||
|
|
@ -53,7 +53,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
3. 生成缩略图
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 通过Image对象的thumbnail方法生成指定尺寸的缩略图
|
||||
image.thumbnail((128, 128))
|
||||
image.show()
|
||||
|
|
@ -63,7 +63,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
4. 缩放和黏贴图像
|
||||
|
||||
```Python
|
||||
```python
|
||||
# 读取骆昊的照片获得Image对象
|
||||
luohao_image = Image.open('luohao.png')
|
||||
# 读取吉多的照片获得Image对象
|
||||
|
|
@ -81,7 +81,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
5. 旋转和翻转
|
||||
|
||||
```Python
|
||||
```python
|
||||
image = Image.open('guido.jpg')
|
||||
# 使用Image对象的rotate方法实现图像的旋转
|
||||
image.rotate(45).show()
|
||||
|
|
@ -95,7 +95,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
6. 操作像素
|
||||
|
||||
```Python
|
||||
```python
|
||||
for x in range(80, 310):
|
||||
for y in range(20, 360):
|
||||
# 通过Image对象的putpixel方法修改图像指定像素点
|
||||
|
|
@ -107,7 +107,7 @@ Pillow 中最为重要的是`Image`类,可以通过`Image`模块的`open`函
|
|||
|
||||
7. 滤镜效果
|
||||
|
||||
```Python
|
||||
```python
|
||||
from PIL import ImageFilter
|
||||
|
||||
# 使用Image对象的filter方法对图像进行滤镜处理
|
||||
|
|
@ -125,7 +125,7 @@ Pillow 中有一个名为`ImageDraw`的模块,该模块的`Draw`函数会返
|
|||
|
||||
要绘制如上图所示的图像,完整的代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
用手机扫码上面的二维码可以通过发送短信的方式来获取授权码,短信发送成功后,点击“我已发送”就可以获得授权码。授权码需要妥善保管,因为一旦泄露就会被其他人冒用你的身份来发送邮件。接下来,我们就可以编写发送邮件的代码了,如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import smtplib
|
||||
from email.header import Header
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
|
@ -50,7 +50,7 @@ smtp_obj.sendmail(
|
|||
|
||||
下面的代码演示了如何发送带附件的邮件。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import smtplib
|
||||
from email.header import Header
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
|
@ -95,7 +95,7 @@ smtp_obj.sendmail(
|
|||
|
||||
为了方便大家用 Python 实现邮件发送,我将上面的代码封装成了函数,使用的时候大家只需要调整邮件服务器域名、端口、用户名和授权码就可以了。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import smtplib
|
||||
from email.header import Header
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
|
|
@ -151,7 +151,7 @@ def send_email(*, from_user, to_users, subject='', content='', filenames=[]):
|
|||
|
||||
接下来,我们可以通过`requests`库向平台提供的短信网关发起一个 HTTP 请求,通过将接收短信的手机号和短信内容作为参数,就可以发送短信,代码如下所示。
|
||||
|
||||
```Python
|
||||
```python
|
||||
import random
|
||||
|
||||
import requests
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Python 提供了`re`模块来支持正则表达式相关操作,下面是`re`
|
|||
|
||||
#### 例子1:验证输入用户名和QQ号是否有效并给出对应的提示信息。
|
||||
|
||||
```Python
|
||||
```python
|
||||
"""
|
||||
要求:用户名必须由字母、数字或下划线构成且长度在6~20个字符之间,QQ号是5~12的数字且首位不能为0
|
||||
"""
|
||||
|
|
@ -102,7 +102,7 @@ if m1 and m2:
|
|||
|
||||
<img src="res/20210803203134.png" style="zoom:100%;">
|
||||
|
||||
```Python
|
||||
```python
|
||||
import re
|
||||
|
||||
# 创建正则表达式对象,使用了前瞻和回顾来保证手机号前后不应该再出现数字
|
||||
|
|
@ -131,7 +131,7 @@ while m:
|
|||
|
||||
#### 例子3:替换字符串中的不良内容
|
||||
|
||||
```Python
|
||||
```python
|
||||
import re
|
||||
|
||||
sentence = 'Oh, shit! 你是傻逼吗? Fuck you.'
|
||||
|
|
@ -144,7 +144,7 @@ print(purified) # Oh, *! 你是*吗? * you.
|
|||
|
||||
#### 例子4:拆分长字符串
|
||||
|
||||
```Python
|
||||
```python
|
||||
import re
|
||||
|
||||
poem = '窗前明月光,疑是地上霜。举头望明月,低头思故乡。'
|
||||
|
|
|
|||
|
|
@ -1,14 +1,24 @@
|
|||
## 数据分析概述
|
||||
|
||||
当今世界对信息技术的依赖程度在不断加深,每天都会有大量的数据产生,我们经常会感到数据越来越多,但是要从中发现有价值的信息却越来越难。这里所说的信息,可以理解为对数据集处理之后的结果,是从数据集中提炼出的可用于其他场合的结论性的东西,而**从原始数据中抽取出有价值的信息**的这个过程我们就称之为**数据分析**,它是数据科学工作的一部分。
|
||||
当今世界,各行各业对信息技术的依赖程度在不断加深,每天都会有大量的数据产生,我们常常会感到数据越来越多,但是要从中发现有价值的信息却越来越难。这里所说的信息,可以理解为对数据集处理之后的结果,是从数据集中提炼出的可用于支撑和指导决策的东西,而**从原始数据中抽取出有价值的信息**的这个过程我们就称之为**数据分析**,它是数据科学的重要组成部分。
|
||||
|
||||
<img src="res/data_science.png" style="zoom:50%;">
|
||||
|
||||
> 定义:**数据分析是有针对性的收集、加工、整理数据并采用统计、挖掘等技术对数据进行探索、分析、呈现和解释的科学**。
|
||||
> **定义1**:数据分析是有针对性的收集、加工、整理数据并采用统计、挖掘等技术对数据进行探索、分析、呈现和解释的科学。
|
||||
>
|
||||
> **定义2**:数据分析是通过收集、整理和分析数据,从中提取有价值的信息和洞察,以支持决策和优化过程的活动。(GPT-4o)
|
||||
>
|
||||
> **定义3**:数据分析是通过系统性的收集、整理、处理、检验和解释数据,从中提取有价值的信息、形成结论并支持决策的过程,其核心是利用统计、算法和逻辑方法揭示数据背后的规律、趋势或关联。(DeepSeek)
|
||||
|
||||
### 数据分析师的职责和技能栈
|
||||
对于想从事数据分析工作的人来说,需要掌握两个部分的技能,一是“数据思维”,二是“分析工具”,如下图所示。
|
||||
|
||||
HR在发布招聘需求时,通常将数据工程、数据分析、数据挖掘等岗位都统称为数据分析岗位,但是根据工作性质的不同,又可以分为偏工程的**数据治理方向**、偏业务的**数据分析方向**、偏算法的**数据挖掘方向**、偏开发的**数据开发方向**、偏产品的**数据产品经理**。我们通常所说的数据分析师主要是指**业务数据分析师**,很多数据分析师的职业生涯都是从这个岗位开始的,而且这个岗位也是招聘数量最多的岗位。业务数据分析师在公司通常不属于研发部门而属于运营部门,所以这个岗位也称为**数据运营**或**商业分析**,这类人员通常也被称为“BI工程师”。通常招聘信息对这个岗位的描述(JD)是:
|
||||

|
||||
|
||||
上图中,分析工具部分其实是比较容易掌握的,像 SQL 或 Python 这样的编程语言,只要经过系统的学习和适量的练习,大部分人都是可以驾驭的;像 Power BI、Tableau 这样的商业智能工具,更是让我们通过“拖拉拽”操作就能完成数据的可视化并在此基础上产生商业洞察,上手难度会更低。相反,数据思维部分的内容对大多数新手来说是不太容易驾驭的,例如“统计思维”,很多人在读书的时候都学习过“概率论和统计学”这样的课程,但是当面对实际的业务场景时,却很难将这些知识映射到业务场景来解决现实的问题。此外,如果没有掌握基本的分析方法、没有理解常用的分析模型,没有相关业务知识的积累,即便我们拿到再多有用的数据,也会感觉无从下手,更不用说产生业务洞察发现商业价值了。所以,数据思维这个部分,除了系统的学习相关知识技能,还需要不断的在实际业务场景中积累和沉淀。
|
||||
|
||||
### 数据分析师的职责
|
||||
|
||||
HR在发布招聘需求时,通常将数据工程、数据分析、数据挖掘等岗位都统称为数据分析岗位,但是根据工作性质的不同,又可以分为偏工程的**数据治理方向**、偏业务的**商业分析方向**、偏算法的**数据挖掘方向**、偏应用的**数据开发方向**、偏产品的**数据产品经理**。我们通常所说的数据分析师主要是指**业务数据分析师**,很多数据分析师的职业生涯都是从这个岗位开始的,而且这个岗位也是招聘数量最多的岗位。有些公司会将业务数据分析师归属到具体的业务部门(市场、运营、产品等),有些公司有专门的数据部门(数据分析团队或数据科学团队),还有些公司数据分析师会直接服务高层决策,属于企业战略部门。正因如此,你在招聘网站上看到的把数据分析师称为**数据运营**、**商业分析师**、**BI工程师**就不会感到奇怪了。通常,我们在招聘网站看到的对业务数据分析师岗位职责(JD)的描述如下所示:
|
||||
|
||||
1. 负责相关报表的输出。
|
||||
2. 建立和优化指标体系。
|
||||
|
|
@ -16,25 +26,31 @@ HR在发布招聘需求时,通常将数据工程、数据分析、数据挖掘
|
|||
4. 优化和驱动业务,推动数字化运营。
|
||||
5. 找出潜在的市场和产品的上升空间。
|
||||
|
||||
根据上面的描述,作为业务数据分析师,我们的工作不是给领导一个简单浅显的结论,而是结合公司的业务,完成**监控数据**、**揪出异常**、**找到原因**、**探索趋势**等工作。作为数据分析师,不管是用 Python 语言、Excel、SPSS或其他的商业智能工具,工具只是达成目标的手段,**数据思维是核心技能**,从实际业务问题出发到最终**发现数据中的商业价值**是终极目标。数据分析师在很多公司只是一个基础岗位,精于业务的数据分析师可以向**数据分析经理**或**数据运营总监**等管理岗位发展;对于熟悉机器学习算法的数据分析师来说,可以向**数据挖掘工程师**或**算法专家**方向发展,而这些岗位除了需要相应的数学和统计学知识,在编程能力方面也比数据分析师有更高的要求,可能还需要有大数据存储和处理的相关经验。数据治理岗位主要是帮助公司建设数据仓库或数据湖,实现数据从业务系统、埋点系统、日志系统到分析库的转移,为后续的数据分析和挖掘提供基础设施。数据治理岗位对 SQL 和 HiveSQL 有着较高的要求,需要熟练的使用 ETL 工具,此外还需要对 Hadoop 生态圈有一个较好的认知。作为数据产品经理,除了传统产品经理的技能栈之外,也需要较强的技术能力,例如要了解常用的推荐算法、机器学习模型,能够为算法的改进提供依据,能够制定相关埋点的规范和口径,虽然不需要精通各种算法,但是要站在产品的角度去考虑数据模型、指标、算法等的落地。
|
||||
根据上面的描述,作为业务数据分析师,我们的工作不是给出一个简单浅显的结论,而是结合公司的业务,完成**监控数据**、**揪出异常**、**找到原因**、**探索趋势**等工作。不管你是用 Python 语言、Excel、Tableau、SPSS或其他的商业智能工具,工具只是达成目标的手段,**数据思维是核心技能**,从实际业务问题出发到最终**发现数据中的商业价值**是终极目标。数据分析师在很多公司只是一个基础岗位,精于业务的数据分析师可以向**数据分析经理**或**数据运营总监**等管理岗位发展;对于熟悉机器学习算法的数据分析师来说,可以向**数据挖掘工程师**或**算法专家**方向发展,这些岗位除了需要相应的数学和统计学知识,在编程能力方面也比数据分析师有更高的要求,可能还需要有大数据存储和处理的相关经验。
|
||||
|
||||
以下是我总结的数据分析师的技能栈,仅供参考。
|
||||
这里顺便说一下其他几个方向,数据治理岗位主要是帮助公司建设数据仓库或数据湖,实现数据从业务系统、埋点系统、日志系统到数据仓库或数据湖的转移,为后续的数据分析和挖掘提供基础设施。数据治理岗位对 SQL 和 HiveSQL 有着较高的要求,需要熟练的使用 ETL 工具,此外还需要对 Hadoop 生态圈有较好的认知。作为数据产品经理,除了传统产品经理的技能栈之外,也需要较强的技术能力,例如要了解常用的推荐算法、机器学习模型,能够为算法的改进提供依据,能够制定相关埋点的规范和口径,虽然不需要精通各种算法,但是要站在产品的角度去考虑数据模型、指标、算法等的落地。
|
||||
|
||||
### 数据分析师的技能栈
|
||||
|
||||
数据分析师的技能栈也包括硬技能和软技能,以下是我对这个职位的理解,仅供参考。
|
||||
|
||||
1. 计算机科学(数据分析工具、编程语言、数据库)
|
||||
2. 数学和统计学(数据思维、统计思维)
|
||||
3. 人工智能(机器学习中的数据挖掘算法)
|
||||
3. 人工智能(机器学习和深度学习算法)
|
||||
4. 业务理解能力(沟通、表达、经验)
|
||||
5. 总结和表述能力(商业PPT、文字总结)
|
||||
5. 总结和表述能力(总结、汇报、商业 PPT)
|
||||
|
||||
### 数据分析的流程
|
||||
当然,对于一个新手来收,不可能用短时间掌握整个技能栈的内容,但是随着这份工作的深入,上面提到的东西多多少少都会涉猎到,大家可以根据实际工作的需求去深耕其中的某个或某些技能。
|
||||
|
||||
### 数据分析通用流程
|
||||
|
||||
我们提到数据分析这个词很多时候可能指的都是**狭义的数据分析**,这类数据分析主要目标就是生成可视化报表并通过这些报表来洞察业务中的问题,这类工作一般都是具有滞后性的。**广义的数据分析**还包含了数据挖掘的部分,不仅要通过数据实现对业务的监控和分析,还要利用机器学习算法,找出隐藏在数据背后的知识,并利用这些知识为将来的决策提供支撑,具备一定的前瞻性。
|
||||
|
||||
基本的数据分析工作一般包含以下几个方面的内容,当然因为行业和工作内容的不同会略有差异。
|
||||
|
||||
1. 确定目标(输入):理解业务,确定指标口径
|
||||
2. 获取数据:数据仓库(SQL提数)、电子表格、三方接口、网络爬虫、开放数据集等
|
||||
3. 清洗数据:包括对缺失值、重复值、异常值的处理以及相关的预处理(格式化、离散化、二值化等)
|
||||
2. 获取数据:数据仓库、电子表格、三方接口、网络爬虫、开放数据集等
|
||||
3. 清洗数据:缺失值、重复值、异常值的处理以及其他预处理(格式化、离散化、二值化等)
|
||||
4. 数据透视:排序、统计、分组聚合、交叉表、透视表等
|
||||
5. 数据呈现(输出):数据可视化,发布工作成果(数据分析报告)
|
||||
6. 分析洞察(后续):解释数据的变化,提出对应的方案
|
||||
|
|
@ -50,17 +66,23 @@ HR在发布招聘需求时,通常将数据工程、数据分析、数据挖掘
|
|||
|
||||
### 数据分析相关库
|
||||
|
||||
使用 Python 从事数据科学相关的工作是一个非常棒的选择,因为 Python 整个生态圈中,有大量的成熟的用于数据科学的软件包(工具库)。而且不同于其他的用于数据科学的编程语言(如:Julia、R),Python 除了可以用于数据科学,还能做很多其他的事情,可以说 Python 语言几乎是无所不能的。
|
||||
使用 Python 从事数据分析相关的工作是一个非常棒的选择,首先 Python 语言非常容易上手,而且整个 Python 生态圈中,有非常多成熟的用于数据科学的软件包和工具库。不同于其他的数据科学编程语言(如:Julia、R等),Python 除了可以用于数据科学,还能做很多其他的事情。
|
||||
|
||||
#### 三大神器
|
||||
#### 经典的三大神器
|
||||
|
||||
1. [NumPy](https://numpy.org/):支持常见的数组和矩阵操作,通过`ndarray`类实现了对多维数组的封装,提供了操作这些数组的方法和函数集。由于 NumPy 内置了并行运算功能,当使用多核 CPU 时,Numpy会自动做并行计算。
|
||||
2. [Pandas](https://pandas.pydata.org/):pandas 的核心是其特有的数据结构`DataFrame`和`Series`,这使得 pandas 可以处理包含不同类型数据的表格和时间序列,这一点是NumPy的`ndarray`做不到的。使用 pandas,可以轻松顺利的加载各种形式的数据,然后对数据进行切片、切块、处理缺失值、聚合、重塑和可视化等操作。
|
||||
1. [NumPy](https://numpy.org/):支持常见的数组和矩阵操作,通过`ndarray`类实现了对多维数组的封装,提供了操作这些数组的方法和函数。由于 NumPy 内置了并行运算功能,当使用多核 CPU 时,NumPy 会自动做并行计算。
|
||||
2. [Pandas](https://pandas.pydata.org/):pandas 的核心是其特有的数据结构`DataFrame`和`Series`,这使得 pandas 可以处理包含不同类型数据的表格和时间序列,这一点是 NumPy 的`ndarray`做不到的。使用 pandas,可以轻松顺利的加载各种形式的数据,然后对数据进行切片、切块、重塑、清洗、聚合、呈现等操作。
|
||||
3. [Matplotlib](https://matplotlib.org/):matplotlib 是一个包含各种绘图模块的库,能够根据我们提供的数据创建高质量的图表。此外,matplotlib 还提供了 pylab 模块,这个模块包含了很多像 [MATLAB](https://www.mathworks.com/products/matlab.html) 一样的绘图组件。
|
||||
|
||||
#### 其他相关库
|
||||
|
||||
1. [SciPy](https://scipy.org/):完善了 NumPy 的功能,封装了大量科学计算的算法,包括线性代数、统计检验、稀疏矩阵、信号和图像处理、最优化问题、快速傅里叶变换等。
|
||||
2. [Seaborn](https://seaborn.pydata.org/):seaborn 是基于 matplotlib 的图形可视化工具,直接使用 matplotlib 虽然可以定制出漂亮的统计图表,但是总体来说还不够简单方便,seaborn 相当于是对 matplotlib 做了封装,让用户能够以更简洁有效的方式做出各种有吸引力的统计图表。
|
||||
3. [Scikit-learn](https://scikit-learn.org/):scikit-learn 最初是 SciPy 的一部分,提供了大量机器学习可能用到的工具,包括数据预处理、监督学习(分类、回归)、无监督学习(聚类)、模式选择、交叉检验等。
|
||||
4. [Statsmodels](https://www.statsmodels.org/stable/index.html):包含了经典统计学和经济计量学算法的库。
|
||||
2. [Polars](https://pola.rs/):一个高性能的数据分析库,旨在提供比 pandas 更快的数据操作。它支持大规模数据处理,并能够利用多核 CPU 来加速计算,在处理大规模数据集时可以用来替代 pandas。
|
||||
3. [Seaborn](https://seaborn.pydata.org/):seaborn 是基于 matplotlib 的图形可视化工具,直接使用 matplotlib 虽然可以定制出漂亮的统计图表,但是总体来说还不够简单方便,seaborn 相当于是对 matplotlib 做了封装,让用户能够以更简洁有效的方式做出各种有吸引力的统计图表。
|
||||
4. [Scikit-learn](https://scikit-learn.org/):scikit-learn 最初是 SciPy 的一部分,提供了大量机器学习可能用到的工具,包括数据预处理、监督学习(分类、回归)、无监督学习(聚类)、模式选择、交叉检验等。
|
||||
5. [Statsmodels](https://www.statsmodels.org/stable/index.html):包含了经典统计学和计量经济学算法的库,帮助帮助用户完成数据探索、回归分析、假设检验等任务。
|
||||
6. [PySpark](https://spark.apache.org/):Apache Spark(大数据处理引擎)的 Python 版本,用于大规模数据处理和分布式计算,能够在分布式环境中高效地进行数据清洗、转化和分析。
|
||||
7. [Tensorflow](https://www.tensorflow.org/):TensorFlow 是一个开源的深度学习框架,由 Google 开发,主要面向深度学习任务,常用于构建和训练机器学习模型(尤其是复杂的神经网络模型)。
|
||||
8. [Keras](https://keras.io/):Keras 是一个高层次的神经网络 API,主要用于构建和训练深度学习模型。Keras 适合深度学习初学者和研究人员,因为它让构建和训练神经网络变得更加简单。
|
||||
9. [PyTorch](https://pytorch.org/):PyTorch 是一个开源的深度学习框架,由 Facebook 开发,广泛用于研究和生产环境。PyTorch 是深度学习研究中的热门框架,在计算机视觉、自然语言处理等领域得到了广泛应用。
|
||||
10. [NLTK](https://www.nltk.org/) / [SpaCy](https://spacy.io/):自然语言处理(NLP)库。
|
||||
|
|
|
|||
|
Can't render this file because it is too large.
|
|
|
@ -0,0 +1,602 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c664c108-059f-402a-b216-5ba4caa2d98b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Python数据分析第1天\n",
|
||||
"\n",
|
||||
"### 热身练习\n",
|
||||
"\n",
|
||||
"如下列表保存着本公司从2022年1月到12月五个销售区域(南京、无锡、苏州、徐州、南通)的销售额(以百万元为单位),请利用这些数据完成以下操作:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"sales_month = [f'{i:>2d}月' for i in range(1, 13)]\n",
|
||||
"sales_area = ['南京', '无锡', '苏州', '徐州', '南通']\n",
|
||||
"sales_data = [\n",
|
||||
" [32, 17, 12, 20, 28],\n",
|
||||
" [41, 30, 17, 15, 35],\n",
|
||||
" [35, 18, 13, 11, 24],\n",
|
||||
" [12, 42, 44, 21, 34],\n",
|
||||
" [29, 11, 42, 32, 50],\n",
|
||||
" [10, 15, 11, 12, 26],\n",
|
||||
" [16, 28, 48, 22, 28],\n",
|
||||
" [31, 40, 45, 30, 39],\n",
|
||||
" [25, 41, 47, 42, 47],\n",
|
||||
" [47, 21, 13, 49, 48],\n",
|
||||
" [41, 36, 17, 36, 22],\n",
|
||||
" [22, 25, 15, 20, 37]\n",
|
||||
"]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"1. 统计本公司每个月的销售额。\n",
|
||||
"2. 统计本公司销售额的月环比。\n",
|
||||
"3. 统计每个销售区域全年的销售额。\n",
|
||||
"4. 按销售额从高到低排序销售区域及其销售额。\n",
|
||||
"5. 统计全年最高的销售额出现在哪个月哪个区域。\n",
|
||||
"6. 找出哪个销售区域的业绩最不稳定。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f9d87cfc-deb0-46eb-b98c-2799a4908bc8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sales_month = [f'{i:>2d}月' for i in range(1, 13)]\n",
|
||||
"sales_area = ['南京', '无锡', '苏州', '徐州', '南通']\n",
|
||||
"sales_data = [\n",
|
||||
" [32, 17, 12, 20, 28],\n",
|
||||
" [41, 30, 17, 15, 35],\n",
|
||||
" [35, 18, 13, 11, 24],\n",
|
||||
" [12, 42, 44, 21, 34],\n",
|
||||
" [29, 11, 42, 32, 50],\n",
|
||||
" [10, 15, 11, 12, 26],\n",
|
||||
" [16, 28, 48, 22, 28],\n",
|
||||
" [31, 40, 45, 30, 39],\n",
|
||||
" [25, 41, 47, 42, 47],\n",
|
||||
" [47, 21, 13, 49, 48],\n",
|
||||
" [41, 36, 17, 36, 22],\n",
|
||||
" [22, 25, 15, 20, 37]\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dc581dfc-9108-46fa-ace2-60ace650434e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 魔法指令 - %whos - 查看变量\n",
|
||||
"%whos"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a50e4c3e-6dc1-426f-977b-aef9a5c9a02f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print = 100"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4c0b54ca-1556-4a14-9a6a-b6bd6af5d822",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 魔法指令 - %xdel - 删除变量\n",
|
||||
"%xdel print"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fe8eb05f-f45b-491a-b98e-6f6c924997ff",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 1. 统计本公司每个月的销售额。\n",
|
||||
"monthly_sales = []\n",
|
||||
"for i, month in enumerate(sales_month):\n",
|
||||
" monthly_sales.append(sum(sales_data[i]))\n",
|
||||
" print(f'{month}销售额: {monthly_sales[i]}百万')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "53e6bf88-e6a9-4ac9-a7fe-bd1d18ff88f5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 2. 统计本公司销售额的月环比。\n",
|
||||
"for i in range(1, len(monthly_sales)):\n",
|
||||
" temp = (monthly_sales[i] - monthly_sales[i - 1]) / monthly_sales[i - 1]\n",
|
||||
" print(f'{sales_month[i]}: {temp:.2%}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f5a130d6-b781-4ee3-a96b-d1fe5e3b4b90",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 3. 统计每个销售区域全年的销售额。\n",
|
||||
"arealy_sales = {}\n",
|
||||
"for j, area in enumerate(sales_area):\n",
|
||||
" temp = [sales_data[i][j] for i in range(len(sales_month))]\n",
|
||||
" arealy_sales[area] = sum(temp)\n",
|
||||
" print(f'{area}: {arealy_sales[area]}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a7bd0510-5e68-4e58-ac3b-6c531f7abccb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 4. 按销售额从高到低排序销售区域及其销售额。\n",
|
||||
"sorted_keys = sorted(arealy_sales, key=lambda x: arealy_sales[x], reverse=True)\n",
|
||||
"for key in sorted_keys:\n",
|
||||
" print(f'{key}: {arealy_sales[key]}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b4b2f3e8-c5c2-481e-b277-9623d30892ac",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 5. 统计全年最高的销售额出现在哪个月哪个区域。\n",
|
||||
"max_value = sales_data[0][0]\n",
|
||||
"max_i, max_j = 0, 0\n",
|
||||
"for i in range(len(sales_month)):\n",
|
||||
" for j in range(len(sales_area)):\n",
|
||||
" temp = sales_data[i][j]\n",
|
||||
" if temp > max_value:\n",
|
||||
" max_value = temp\n",
|
||||
" max_i, max_j = i, j\n",
|
||||
"print(sales_month[max_i], sales_area[max_j])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "647d0a87-b672-4e0c-81cc-a3bbb76dca11",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"总体方差:\n",
|
||||
"$$\n",
|
||||
"\\sigma^{2} = \\frac{1}{N} \\sum_{i=1}^{N}(x_{i} - \\mu)^{2}\n",
|
||||
"$$\n",
|
||||
"\n",
|
||||
"样本方差:\n",
|
||||
"$$\n",
|
||||
"s^{2} = \\frac{1}{n - 1} \\sum_{i=1}^{n}(x_{i} - \\bar{x})^{2}\n",
|
||||
"$$"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b43fb247-32fc-4e10-a9ee-488fd1f56a9a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 6. 找出哪个销售区域的业绩最不稳定。\n",
|
||||
"import statistics as stats\n",
|
||||
"\n",
|
||||
"arealy_vars = []\n",
|
||||
"for j, area in enumerate(sales_area):\n",
|
||||
" temp = [sales_data[i][j] for i in range(len(sales_month))]\n",
|
||||
" arealy_vars.append(stats.pvariance(temp))\n",
|
||||
"sales_area[arealy_vars.index(max(arealy_vars))]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3ea677d0-7a33-43e5-b10b-ddfcb82f7f6a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 三大神器\n",
|
||||
"\n",
|
||||
"1. numpy - Numerical Python - 核心是`ndarray`类型,可以用来表示N维数组,提供了一系列处理数据的运算、函数和方法。\n",
|
||||
"2. pandas - Panel Data Set - 封装了和数据分析(加载、重塑、清洗、预处理、透视、呈现)相关的类型、函数和诸多的方法,为数据分析提供了一站式解决方案。它的核心有三个数据类型,分别是:`Series`、`DataFrame`、`Index`。\n",
|
||||
"3. matplotlib - 封装了各种常用的统计图表,帮助我们实现数据呈现。\n",
|
||||
"4. scipy - Scientific Python - 针对NumPy进行了很好的补充,提供了高级的数据运算的函数和方法。\n",
|
||||
"5. scikit-learn - 封装了常用的机器学习(分类、聚类、回归等)算法,除此之外,还提供了数据预处理、特征工程、模型验证相关的函数和方法。\n",
|
||||
"6. sympy - Symbolic Python - 封装了符号运算相关操作。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0db758cc-d83c-47c4-9a0b-c7ef5abd6c18",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 魔法指令 - %pip - 调用包管理工具pip\n",
|
||||
"# %pip install numpy pandas matplotlib openpyxl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8eb6970b-3907-4b84-af60-67cbf67f2e74",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.rcParams['font.sans-serif'].insert(0, 'SimHei')\n",
|
||||
"plt.rcParams['axes.unicode_minus'] = False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5fb76dec-cd51-4e79-9bd2-3b210ae20522",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"np.__version__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e6369df9-7577-496c-bfc1-2fce096c0162",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pd.__version__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "eb5733cd-38f7-4afd-b45b-70c1439ab36b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 将嵌套列表处理成二维数组\n",
|
||||
"data = np.array(sales_data)\n",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "da304104-8cf0-4425-b3b4-dcb148ac4b3a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 沿着1轴求和(每个月的销售额)\n",
|
||||
"data.sum(axis=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1507ac63-f53b-4e36-a7fb-b9c636fd81ea",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 沿着0轴求和(每个区域的销售)\n",
|
||||
"data.sum(axis=0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "26be450d-44ba-4d83-9351-c52a13c2c338",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 总体方差\n",
|
||||
"data.var(axis=0).round(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "81e5b2a0-c86e-4720-909f-ce8b1b6fdd58",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 样本方差\n",
|
||||
"data.var(axis=0, ddof=1).round(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ba4e0f0a-e711-4041-8834-1e3be86ce8a4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 构造DataFrame对象(处理二维数据)\n",
|
||||
"df = pd.DataFrame(data, columns=sales_area, index=sales_month)\n",
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9d1a6a43-6dfc-41e3-98c8-be2681e0d547",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 求和(默认沿着0轴)\n",
|
||||
"df.sum()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a478ec0e-499f-4e31-b8c2-ba45e691b834",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 排序\n",
|
||||
"df.sum().sort_values(ascending=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6f221833-855c-45ad-91b2-e3f4da627704",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 求和(指定沿着1轴)\n",
|
||||
"df.sum(axis=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "80df8865-4ea0-4c72-a581-215cd953cfbe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 计算月环比\n",
|
||||
"df.sum(axis=1).pct_change()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ea4579c3-11cd-4179-9c96-8dbe9a033da2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df['合计'] = df.sum(axis=1)\n",
|
||||
"df['月环比'] = df['合计'].pct_change()\n",
|
||||
"df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3c660052-dded-4a0a-8b72-7747d3cae816",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 渲染DataFrame\n",
|
||||
"df.style.format(\n",
|
||||
" formatter={'月环比': '{:.2%}'},\n",
|
||||
" na_rep='------'\n",
|
||||
").bar(\n",
|
||||
" subset='合计'\n",
|
||||
").background_gradient(\n",
|
||||
" 'RdYlBu', subset='月环比'\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a092c12c-dab6-4272-b1cd-5218998fcd90",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 将DataFrame输出到Excel文件\n",
|
||||
"df.to_excel('sales.xlsx', sheet_name='data')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "54c3f505-e866-4c4e-a3f8-f55a71a95c3f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 魔法指令 - %config - 修改配置\n",
|
||||
"# %config InlineBackend.figure_format = 'svg'\n",
|
||||
"get_ipython().run_line_magic('config', 'InlineBackend.figure_format = \"svg\"')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3951055d-d5d2-4e4e-bbe7-a1b40a6731e0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制柱状图\n",
|
||||
"plt.figure(figsize=(8, 4), dpi=200)\n",
|
||||
"df.plot(ax=plt.gca(), kind='bar', y='合计', legend=False)\n",
|
||||
"plt.xticks(rotation=0)\n",
|
||||
"plt.savefig('aa.png')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8a5236f7-072b-466c-9be3-afbab394f5cb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 魔法指令"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d5c6a18b-2863-4855-8ef7-2c0aa99b7d5c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看当前工作路径 - print working directory\n",
|
||||
"%pwd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "80a9f9e0-1528-40cf-910c-f3c8e5e7e3b9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看指定路径文件列表 - list directory contents\n",
|
||||
"%ls"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "620a54ed-9c29-4058-9d20-c4df72ba4c62",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 执行系统命令\n",
|
||||
"%system date"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "659215ed-113a-4d8f-9036-0fcf47c96021",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 保存运行过的代码\n",
|
||||
"%save temp.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8fc9c4e4-1423-40f3-b4ee-db2ba2e5d125",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载指定文件内容\n",
|
||||
"%load temp.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "58a08283-561c-43d4-8db6-74cde401b8a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计代码执行时间\n",
|
||||
"%timeit (1, 2, 3, 4, 5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "22a271ab-3f5c-4167-b89e-66a31e891cbd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看历史输入\n",
|
||||
"%hist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d4ffa792-f1a0-4be9-b2aa-642ee0b9a1ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 查看魔法指令\n",
|
||||
"%lsmagic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a15db907-c068-41d7-a24c-8f1c5c20d4ec",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 获取帮助"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5e037694-9357-46b9-864a-c5f93e1aa8c8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"np.random?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "11a97abd-d73d-493e-b727-9c4ded3e5060",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"np.random.normal?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "66503921-cd69-4394-80ea-7fecf6ecdc33",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"np.random.r*?"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,673 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "97982f4b-b3d0-47fe-b6e8-a1a327d03d93",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 深入浅出pandas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "834d7d19-4015-4048-a1a6-2b8c756f0115",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.rcParams['font.sans-serif'].insert(0, 'SimHei')\n",
|
||||
"plt.rcParams['axes.unicode_minus'] = False"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "56becc00-f1c7-4f81-86d1-7f7b23fd65d4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%config InlineBackend.figure_format = 'svg'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c81bfe94-906c-4e13-b321-0e6c397aea46",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 数据透视\n",
|
||||
"\n",
|
||||
"1. 数据聚合(指标统计)\n",
|
||||
"2. 排序和头部值\n",
|
||||
"3. 透视表和交叉表"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7836ce8b-1e1d-40e5-b01c-c228ebf60928",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sales_df = pd.read_excel('res/2020年销售数据.xlsx', sheet_name='data')\n",
|
||||
"sales_df.head(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ca3b2020-9470-4e49-a3ca-066dc9a437b3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sales_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "224ae45b-172a-48bc-8df0-7d6c7099529a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 添加销售额、毛利润、月份列\n",
|
||||
"sales_df['销售额'] = sales_df.售价 * sales_df.销售数量\n",
|
||||
"sales_df['毛利润'] = sales_df.销售额 - sales_df.直接成本\n",
|
||||
"sales_df['月份'] = sales_df.销售日期.dt.month\n",
|
||||
"sales_df.head(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c8878bfd-64de-4a6a-9ae3-36e9af40d45e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def make_tag(price):\n",
|
||||
" if price < 300:\n",
|
||||
" return '低端'\n",
|
||||
" elif price < 800:\n",
|
||||
" return '中端'\n",
|
||||
" return '高端'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4cba4262-b952-4fce-9b07-fed9c5f2a2e3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 根据商品的价格添加价位标签\n",
|
||||
"sales_df['价位'] = sales_df.售价.apply(make_tag)\n",
|
||||
"sales_df.head(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b2a2b472-55fc-4d35-8530-445e8ffbf800",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计北极星指标\n",
|
||||
"GMV, profit, quantity = sales_df[['销售额', '毛利润', '销售数量']].sum()\n",
|
||||
"print(f'销售额: {GMV}元')\n",
|
||||
"print(f'毛利润: {profit}元')\n",
|
||||
"print(f'销售数量: {quantity}件')\n",
|
||||
"print(f'毛利率: {profit / GMV:.2%}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5b6ac225-6834-462f-a5b7-8be8297b66d0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计每个月的销售额和毛利润\n",
|
||||
"temp1 = sales_df.groupby('月份')[['销售额', '毛利润']].agg('sum')\n",
|
||||
"temp1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a8f179a1-c270-458d-be84-b862ca2c143d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 使用透视表统计每个月的销售额和毛利润\n",
|
||||
"pd.pivot_table(\n",
|
||||
" sales_df,\n",
|
||||
" index='月份',\n",
|
||||
" values=['销售额', '毛利润'],\n",
|
||||
" aggfunc='sum'\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3a3cb912-c47f-4d47-8bd4-ffc9eb171cba",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制折线图\n",
|
||||
"temp1.plot(\n",
|
||||
" kind='line',\n",
|
||||
" figsize=(10, 5),\n",
|
||||
" y=['销售额', '毛利润'], # 放到纵轴上的数据\n",
|
||||
" xlabel='', # 横轴的标签\n",
|
||||
" ylabel='销售额和毛利润', # 纵轴的标签\n",
|
||||
" marker='^', # 标记点符号\n",
|
||||
")\n",
|
||||
"# plt.fill_between(np.arange(1, 13), temp1.销售额, where=temp1.销售额 >= 3e6, facecolor='red', alpha=0.25)\n",
|
||||
"# plt.fill_between(np.arange(1, 13), temp1.销售额, where=temp1.销售额 < 3e6, facecolor='green', alpha=0.25)\n",
|
||||
"# 定制纵轴的取值范围\n",
|
||||
"plt.ylim(0, 6e6)\n",
|
||||
"# 定制横轴的刻度\n",
|
||||
"plt.xticks(np.arange(1, 13), labels=[f'{x}月' for x in range(1, 13)])\n",
|
||||
"# 定制标题\n",
|
||||
"plt.title('2020年月度销售额和毛利润', fontdict={'fontsize': 22, 'color': 'navy'})\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "389db27d-2b11-47ea-a8c6-660fcc39b863",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.cm.RdYlBu_r"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "621a2487-2d15-450d-9f69-df8089616bd9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 计算月环比\n",
|
||||
"temp1['销售额月环比'] = temp1.销售额.pct_change()\n",
|
||||
"temp1['毛利润月环比'] = temp1.毛利润.pct_change()\n",
|
||||
"# 索引重排序\n",
|
||||
"temp1 = temp1.reindex(columns=['销售额', '销售额月环比', '毛利润', '毛利润月环比'])\n",
|
||||
"# 渲染输出\n",
|
||||
"temp1.style.format(\n",
|
||||
" formatter={\n",
|
||||
" '销售额月环比': '{:.2%}',\n",
|
||||
" '毛利润月环比': '{:.2%}'\n",
|
||||
" },\n",
|
||||
" na_rep='-------'\n",
|
||||
").background_gradient(\n",
|
||||
" 'RdYlBu_r',\n",
|
||||
" subset=['销售额月环比', '毛利润月环比']\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6b158aea-fe6e-4938-a4f8-4b880c6f23d0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制横线图\n",
|
||||
"mu = temp1.销售额.mean()\n",
|
||||
"temp1['diff'] = temp1.销售额 - mu\n",
|
||||
"temp1['colors'] = temp1.销售额.map(lambda x: 'green' if x > mu else 'red')\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(8, 6), dpi=200)\n",
|
||||
"plt.hlines(y=temp1.index, xmin=0, xmax=temp1['diff'], color=temp1.colors, alpha=0.6, linewidth=6)\n",
|
||||
"plt.yticks(np.arange(1, 13), labels=[f'{x}月' for x in np.arange(1, 13)])\n",
|
||||
"# 定制网格线\n",
|
||||
"plt.grid(linestyle='--', linewidth=0.4, alpha=0.5)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "810936a1-f6c5-43e9-9eda-b9fe8014ba9f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 各品牌对销售额贡献占比\n",
|
||||
"temp2 = sales_df.groupby('品牌')['销售额'].sum()\n",
|
||||
"temp2.plot(\n",
|
||||
" kind='pie',\n",
|
||||
" ylabel='',\n",
|
||||
" autopct='%.2f%%', # 自动计算并显示百分比\n",
|
||||
" pctdistance=0.82, # 百分比标签到圆心的距离\n",
|
||||
" wedgeprops=dict(width=0.35, edgecolor='w'), # 定制环状饼图\n",
|
||||
" explode=[0.1, 0, 0, 0, 0], # 分离饼图\n",
|
||||
")\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1465d545-14e8-435d-9b12-651df3bab9ea",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 各销售区域每个月的销售额\n",
|
||||
"temp3 = sales_df.groupby(['销售区域', '月份'], as_index=False)[['销售额']].sum()\n",
|
||||
"# pivot - 将行旋转到列上(窄表 ----> 宽表)\n",
|
||||
"# melt - 将列旋转到行上(宽表 ----> 窄表)\n",
|
||||
"temp3.pivot(index='销售区域', columns='月份', values='销售额').fillna(0).astype('i8')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1adf23bb-7120-416c-846e-1098aac2e1f4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 创建透视表\n",
|
||||
"pd.pivot_table(\n",
|
||||
" sales_df,\n",
|
||||
" index='销售区域',\n",
|
||||
" columns='月份',\n",
|
||||
" values='销售额',\n",
|
||||
" aggfunc='sum',\n",
|
||||
" fill_value=0,\n",
|
||||
" margins=True,\n",
|
||||
" margins_name='总计'\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fdf54c9a-64c3-453d-bc5b-533fce7b25ed",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 将价位字段处理成category类型并指定排序的顺序\n",
|
||||
"sales_df['价位'] = sales_df.价位.astype('category').cat.reorder_categories(['高端', '中端', '低端'])\n",
|
||||
"sales_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6e706575-3260-4b37-99fe-696db4f6fe7b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计每个月各种价位产品的销量\n",
|
||||
"temp4 = sales_df.pivot_table(\n",
|
||||
" index='价位',\n",
|
||||
" columns='月份',\n",
|
||||
" values='销售数量',\n",
|
||||
" observed=False,\n",
|
||||
" fill_value=0,\n",
|
||||
" aggfunc='sum'\n",
|
||||
")\n",
|
||||
"temp4"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "12527025-64f5-4a0a-9bf5-6bdbc4b6f93b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 交叉表\n",
|
||||
"pd.crosstab(\n",
|
||||
" index=sales_df.价位,\n",
|
||||
" columns=sales_df.月份,\n",
|
||||
" values=sales_df.销售数量,\n",
|
||||
" aggfunc='sum'\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d99ecd49-2669-493c-ae04-974afa71dc4d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"blood_types = np.array(['B', 'A', 'O', 'O', 'AB', 'B', 'O', 'B', 'AB', 'A', 'A', 'O', 'B', 'O', 'O', 'O', 'O', 'A', 'B', 'B'])\n",
|
||||
"personality_types = np.array(['𝛃', '𝛂', '𝛂', '𝛂', '𝛃', '𝛂', '𝛄', '𝛄', '𝛂', '𝛄', '𝛃', '𝛂', '𝛂', '𝛂', '𝛄', '𝛄', '𝛂', '𝛂', '𝛂', '𝛂'])\n",
|
||||
"\n",
|
||||
"# 创建交叉表\n",
|
||||
"pd.crosstab(\n",
|
||||
" index=blood_types,\n",
|
||||
" columns=personality_types,\n",
|
||||
" rownames=['血型'],\n",
|
||||
" colnames=['人格'],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3cba2e9e-8335-4081-a253-5ab6d08d8559",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制堆叠柱状图\n",
|
||||
"temp4.T.plot(\n",
|
||||
" figsize=(10, 4),\n",
|
||||
" kind='bar',\n",
|
||||
" width=0.6,\n",
|
||||
" xlabel='',\n",
|
||||
" ylabel='销售数量',\n",
|
||||
" stacked=True\n",
|
||||
")\n",
|
||||
"plt.xticks(rotation=0)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9eba1698-d8a5-4b66-b617-fc68072a670e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 让每一项数据除以对应月份的销售数量之和\n",
|
||||
"temp5 = temp4.T.divide(temp4.sum(), axis=0)\n",
|
||||
"temp5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1ce2e80e-0af9-4162-a46d-b5d357a9362d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制百分比堆叠柱状图\n",
|
||||
"temp5.plot(\n",
|
||||
" figsize=(10, 4),\n",
|
||||
" kind='bar',\n",
|
||||
" width=0.6,\n",
|
||||
" xlabel='',\n",
|
||||
" ylabel='销量占比',\n",
|
||||
" stacked=True\n",
|
||||
")\n",
|
||||
"plt.xticks(rotation=0)\n",
|
||||
"plt.yticks(np.linspace(0, 1, 6), labels=[f'{x:.0%}' for x in np.linspace(0, 1, 6)])\n",
|
||||
"plt.legend(loc='lower center')\n",
|
||||
"\n",
|
||||
"for i in temp5.index:\n",
|
||||
" y1, y2, y3 = temp5.loc[i]\n",
|
||||
" plt.text(i - 1, y2 / 2 + y1, f'{y2:.2%}', ha='center', va='center', fontdict={'size': 8})\n",
|
||||
" plt.text(i - 1, y3 / 2 + y2 + y1, f'{y3:.2%}', ha='center', va='center', fontdict={'size': 8})\n",
|
||||
"\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "82ac6b37-302e-4913-a973-4a7f4e6daf1d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 作业:招聘岗位数据分析\n",
|
||||
"\n",
|
||||
"1. 统计出城市、招聘信息、招聘岗位的数量和平均月薪。\n",
|
||||
"2. 统计每个城市的岗位数量从高到低排序。\n",
|
||||
"3. 统计每个城市的平均薪资从高到低排序。\n",
|
||||
"4. 统计招聘岗位对学历要求的占比。\n",
|
||||
"5. 统计招聘岗位对工作年限的要求占比。\n",
|
||||
"6. 分析薪资跟学历和工作年限的关系。"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "91e8b171-7568-4da1-8170-5d13fc8945bc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"jobs_df = pd.read_csv('res/cleaned_jobs.csv')\n",
|
||||
"jobs_df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7cadf547-f7aa-494b-beeb-678f5a09e967",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计北极星指标\n",
|
||||
"city_count = jobs_df['city'].nunique()\n",
|
||||
"info_count = jobs_df['company_name'].count()\n",
|
||||
"post_count = jobs_df['pos_count'].sum()\n",
|
||||
"salary_avg = jobs_df['salary'].mean().round(1)\n",
|
||||
"print(f'城市数量: {city_count}')\n",
|
||||
"print(f'信息数量: {info_count}')\n",
|
||||
"print(f'岗位数量: {post_count}')\n",
|
||||
"print(f'平均薪资: {salary_avg}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb9fc057-df56-4f01-a08e-ab3427dca467",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计每个城市的岗位数量从高到低排序\n",
|
||||
"jobs_df.groupby('city')[['pos_count']].sum().sort_values(by='pos_count', ascending=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "430af08e-2ce2-4f4f-9d64-df2d09c7c9f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pd.pivot_table(\n",
|
||||
" jobs_df,\n",
|
||||
" index='city',\n",
|
||||
" values='pos_count',\n",
|
||||
" aggfunc='sum'\n",
|
||||
").sort_values(by='pos_count', ascending=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bcd4aeca-bb90-42e6-b45c-6cdea2c76271",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"jobs_df.groupby('city')[['salary']].mean().round(1).sort_values(by='salary', ascending=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6e93f5c8-da3e-4064-ac77-748eb3167504",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计每个城市的平均薪资从高到低排序\n",
|
||||
"pd.pivot_table(\n",
|
||||
" jobs_df,\n",
|
||||
" index='city',\n",
|
||||
" values='salary',\n",
|
||||
" aggfunc='mean'\n",
|
||||
").round(1).sort_values(by='salary', ascending=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7ae067bf-2981-49f2-a224-28a5223dc21f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"jobs_df['edu'] = jobs_df.edu.astype('category').cat.reorder_categories(['学历不限', '大专', '本科', '研究生'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a87fab8f-18af-4c0b-9546-63d79778b4d8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计招聘岗位对学历要求占比\n",
|
||||
"pd.pivot_table(\n",
|
||||
" jobs_df,\n",
|
||||
" index='edu',\n",
|
||||
" values='pos_count',\n",
|
||||
" aggfunc='sum',\n",
|
||||
" observed=True\n",
|
||||
").plot(\n",
|
||||
" kind='pie',\n",
|
||||
" ylabel='',\n",
|
||||
" subplots=True,\n",
|
||||
" legend=False,\n",
|
||||
" autopct='%.2f%%',\n",
|
||||
" pctdistance=0.85,\n",
|
||||
" wedgeprops={'width': 0.35}\n",
|
||||
")\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "15202818-48a8-40bb-8701-47bc1b481f80",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"jobs_df['year'] = jobs_df.year.astype('category').cat.reorder_categories(['应届生', '1年以内', '经验不限', '1-3年', '3-5年', '5年以上'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6d965229-36d5-4c38-850c-3300726f208a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计招聘岗位对工作年限要求绘制饼图\n",
|
||||
"pd.pivot_table(\n",
|
||||
" jobs_df,\n",
|
||||
" index='year',\n",
|
||||
" values='pos_count',\n",
|
||||
" aggfunc='sum',\n",
|
||||
" observed=True\n",
|
||||
").plot(\n",
|
||||
" kind='pie',\n",
|
||||
" y='pos_count',\n",
|
||||
" ylabel='',\n",
|
||||
" legend=False,\n",
|
||||
" autopct='%.2f%%',\n",
|
||||
" pctdistance=0.85,\n",
|
||||
" wedgeprops={'width': 0.35}\n",
|
||||
")\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9c7ab419-0bc4-428f-be9b-6d4d617b6663",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计不同学历和工作年限平均薪资\n",
|
||||
"temp6 = pd.pivot_table(\n",
|
||||
" jobs_df,\n",
|
||||
" index='edu',\n",
|
||||
" columns='year',\n",
|
||||
" values='salary',\n",
|
||||
" observed=False,\n",
|
||||
" fill_value=0\n",
|
||||
").round(1)\n",
|
||||
"temp6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d8492b17-5ae8-47f0-a058-ab303a6087a9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 绘制热力图\n",
|
||||
"plt.imshow(temp6, cmap='Reds')\n",
|
||||
"plt.xticks(np.arange(6), labels=temp6.columns)\n",
|
||||
"plt.yticks(np.arange(4), labels=temp6.index)\n",
|
||||
"\n",
|
||||
"for i in range(temp6.index.size):\n",
|
||||
" for j in range(temp6.columns.size):\n",
|
||||
" value = temp6.iat[i, j]\n",
|
||||
" color = 'w' if value > salary_avg else 'k'\n",
|
||||
" plt.text(j, i, value, ha='center', va='center', color=color)\n",
|
||||
"\n",
|
||||
"# 定制颜色条\n",
|
||||
"plt.colorbar()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a3eb8cd0-fe07-43a4-9514-8a38c08ca081",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %pip install seaborn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f6287994-0865-432a-9932-92b05b5bf7e8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import seaborn as sns\n",
|
||||
"\n",
|
||||
"sns.heatmap(temp6, cmap='Reds', annot=True)\n",
|
||||
"plt.xlabel('')\n",
|
||||
"plt.ylabel('')\n",
|
||||
"plt.yticks(rotation=0)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
|
@ -0,0 +1,809 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e4ad3216-d45c-4328-a509-3c01e0fec4d5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 深入浅出pandas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5faacbe5-d44a-4e0e-a287-19270bc1a693",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.rcParams['font.sans-serif'].insert(0, 'SimHei')\n",
|
||||
"plt.rcParams['axes.unicode_minus'] = False\n",
|
||||
"get_ipython().run_line_magic('config', \"InlineBackend.figure_format = 'svg'\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9b6101ba-4d7b-408c-8f94-76cf789ab71a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 科比投篮数据分析\n",
|
||||
"\n",
|
||||
"1. 科比使用得最多的投篮动作\n",
|
||||
"2. 科比交手次数最多的球队\n",
|
||||
"3. 科比有出手的比赛有多少场\n",
|
||||
"4. 科比职业生涯(常规赛+季后赛)总得分(不含罚篮)\n",
|
||||
"5. 科比得分最高的五场比赛(对手、投篮次数、得分、命中率)\n",
|
||||
"6. 科比得分最多的三个赛季(赛季、投篮次数、得分、命中率)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5008a34f-e108-4c35-a71e-0b28e2f4cbfc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 不限制最大显示的列数\n",
|
||||
"pd.set_option('display.max_columns', None)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "526e6f01-7b18-487a-bd89-fdc5a5a494b0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 加载科比投篮数据\n",
|
||||
"kobe_df = pd.read_csv('res/科比投篮数据.csv', index_col='shot_id')\n",
|
||||
"kobe_df.tail(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "127b7ab9-568c-4982-8238-d5fcafe6e9b2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kobe_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4cbe2e96-0bbe-43a7-bafc-f5f956090ea4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比使用得最多的投篮动作是什么\n",
|
||||
"kobe_df.action_type.value_counts().index[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "46bd394d-05f3-4adc-bc69-d8ef70e1f877",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kobe_df.groupby('action_type')['action_type'].count().nlargest(1).index[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3ebb1eab-a675-4f2f-833b-ff7c4207ec77",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比交手次数最多的球队是哪支队伍\n",
|
||||
"kobe_df.drop_duplicates('game_id').opponent.value_counts().index[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6b53491a-1e04-4684-94de-ddcf4eba0a9d",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kobe_df.drop_duplicates('game_id').groupby('opponent').opponent.count().idxmax()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bf1b9f70-23df-4103-87db-7727329eb679",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比有出手的比赛有多少场\n",
|
||||
"kobe_df.game_id.nunique()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "91dfb7c3-c2d8-4eff-9df9-8be558e054d1",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计科比常规赛和季后赛的投篮命中率\n",
|
||||
"temp = kobe_df.dropna().pivot_table(index=['playoffs', 'shot_type'], columns=['shot_made_flag'], values='game_id', aggfunc='count')\n",
|
||||
"temp = temp.divide(temp.sum(axis=1), axis=0)\n",
|
||||
"temp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e998d2d7-1259-479d-b74e-6e9dccf8de36",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 填充shot_made_flag字段的缺失值\n",
|
||||
"def handle(x):\n",
|
||||
" playoffs, shot_type, shot_made_flag = x\n",
|
||||
" if np.isnan(shot_made_flag):\n",
|
||||
" shot_made_flag = 1 if np.random.random() < temp.at[(playoffs, shot_type), 1.0] else 0\n",
|
||||
" return shot_made_flag\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"kobe_df['shot_made_flag'] = kobe_df[['playoffs', 'shot_type', 'shot_made_flag']].apply(handle, axis=1).astype('?')\n",
|
||||
"kobe_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1fd5dbf5-e89f-4f6c-9867-cca583d08527",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 处理得分字段\n",
|
||||
"kobe_df['point'] = kobe_df.shot_type.str[0].astype('i8')\n",
|
||||
"kobe_df['point'] = kobe_df[['shot_made_flag', 'point']].apply(lambda x: x.loc['point'] if x.loc['shot_made_flag'] else 0, axis=1)\n",
|
||||
"kobe_df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b431b8a2-600e-4ed2-8092-0ed8598043f4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 参考数据:投篮命中数11719\n",
|
||||
"kobe_df.shot_made_flag.sum()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a2fdf20e-54d2-43b4-a5b2-52b6f7e815c4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 参考数据:不含罚篮的投篮得分25265\n",
|
||||
"kobe_df.point.sum()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8929cfa5-2152-45ad-9ac4-ce9154ef8830",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比得分最多的赛季是哪个赛季和分数\n",
|
||||
"kobe_df.groupby('season').point.sum().nlargest(3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d5bd3ccf-6654-4c84-a295-4142fd24cebe",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获得得分最高的5场比赛的game_id\n",
|
||||
"index = kobe_df.groupby('game_id').point.sum().nlargest(5).index.values\n",
|
||||
"index"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e48b6dfb-c6f8-40c5-beda-a1e50ae742b4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 用布尔索引筛选数据\n",
|
||||
"kobe_df[np.in1d(kobe_df.game_id, index)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e6ba3500-a50f-400c-a2bc-7f04cf0e3393",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 用query方法筛选数据\n",
|
||||
"kobe_df.query('game_id in @index')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "171a9b52-e917-4b41-9472-80532cc1a72e",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比得分最高的五场比赛(对手、投篮次数、得分、命中率)\n",
|
||||
"# 参考数据(含罚篮):TOR - 81分 / POR - 65分 / DAL - 62分 / NYK - 61分 / MEM - 60分 / UTA - 60分\n",
|
||||
"df1 = kobe_df[np.in1d(kobe_df.game_id, index)].groupby(\n",
|
||||
" 'game_id'\n",
|
||||
")[['game_date', 'opponent', 'game_id', 'shot_made_flag', 'point']].agg({\n",
|
||||
" 'game_date': 'max',\n",
|
||||
" 'opponent': 'max',\n",
|
||||
" 'game_id': 'count',\n",
|
||||
" 'shot_made_flag': 'sum',\n",
|
||||
" 'point': 'sum'\n",
|
||||
"})\n",
|
||||
"df1['rate'] = df1.shot_made_flag / df1.game_id\n",
|
||||
"df1.drop(columns=['shot_made_flag'], inplace=True)\n",
|
||||
"df1.reset_index(drop=True, inplace=True)\n",
|
||||
"df1.set_index('game_date', inplace=True)\n",
|
||||
"df1.rename(columns={'opponent': '对手', 'game_id': '出手次数', 'point': '得分', 'rate': '命中率'}, inplace=True)\n",
|
||||
"df1.sort_values(by='得分', ascending=False).style.format(formatter={'命中率': '{:.2%}'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a129218e-4ceb-4004-9b91-5668b8d3940f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df2 = kobe_df.query('game_id in @index').groupby(\n",
|
||||
" 'game_id'\n",
|
||||
")[['game_date', 'opponent', 'game_id', 'shot_made_flag', 'point']].agg({\n",
|
||||
" 'game_date': 'max',\n",
|
||||
" 'opponent': 'max',\n",
|
||||
" 'game_id': 'count',\n",
|
||||
" 'shot_made_flag': 'sum',\n",
|
||||
" 'point': 'sum'\n",
|
||||
"})\n",
|
||||
"df2['rate'] = df2.shot_made_flag / df2.game_id\n",
|
||||
"df2.drop(columns=['shot_made_flag'], inplace=True)\n",
|
||||
"df2.reset_index(drop=True, inplace=True)\n",
|
||||
"df2.set_index('game_date', inplace=True)\n",
|
||||
"df2.rename(columns={'opponent': '对手', 'game_id': '出手次数', 'point': '得分', 'rate': '命中率'}, inplace=True)\n",
|
||||
"df2.sort_values(by='得分', ascending=False).style.format(formatter={'命中率': '{:.2%}'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "473883f8-acfa-4d32-806d-4201c50106e1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 科比得分最多的三个赛季(赛季、投篮次数、得分、命中率)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c1ae87f9-1698-48b8-be11-0edd47cae298",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 深圳二手房数据分析\n",
|
||||
"\n",
|
||||
"1. 统计深圳二手房单价分布规律\n",
|
||||
"2. 统计深圳二手房总价分布规律\n",
|
||||
"3. 统计每个区总价和均价的均值\n",
|
||||
"4. 深圳每个区单价Top3的商圈\n",
|
||||
"5. 哪种户型的二手房数量最多\n",
|
||||
"6. 总价Top10的二手房分布在哪些区"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "041ac635-9598-4a10-9e04-664678f23448",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df = pd.read_csv('res/深圳二手房数据.csv')\n",
|
||||
"sz_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7298d0f3-d9ef-4cee-975d-8d720711d749",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df.drop(columns='Unnamed: 0', inplace=True)\n",
|
||||
"sz_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f140da58-6846-4595-b365-359cdc5b7dd1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 修正列名\n",
|
||||
"sz_df.rename(columns={'hourseType': 'house_type', 'hourseSize': 'house_size'}, inplace=True)\n",
|
||||
"sz_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "731f00a4-1db8-4aac-ba7c-7bf65ebc3b40",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 将tax字段处理为bool类型\n",
|
||||
"sz_df['tax'] = sz_df.tax.fillna('').astype('?')\n",
|
||||
"sz_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5b2bad9d-ae47-478d-8be1-139121742012",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df.head(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4a780b30-c8d8-4b40-b416-99b1d6572e26",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 获取描述性统计信息\n",
|
||||
"sz_df.total_price.agg(['mean', 'max', 'min', 'skew', 'kurt'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a2b4a48c-9775-424f-bc10-4bc1d71b3813",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df.unit_price.agg(['mean', 'max', 'min', 'skew', 'kurt'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c742fc0c-9b3c-4b8d-861a-879012677458",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df.house_size.agg(['mean', 'max', 'min', 'skew', 'kurt'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7c6a64d4-7bd8-4d04-b9a9-3d787ba9c732",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df[sz_df.unit_price < 10000]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "22989374-3017-48a5-9802-61459df9f8d6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 删除异常数据(单价小于10000)\n",
|
||||
"sz_df.drop(index=sz_df[sz_df.unit_price < 10000].index, inplace=True)\n",
|
||||
"sz_df.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "02a1b493-6d66-4e31-8298-bbe50eae9676",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 删除面积在10平米以下200平米以上的房屋信息\n",
|
||||
"sz_df.drop(index=sz_df.query('house_size < 10 or house_size > 200').index, inplace=True)\n",
|
||||
"sz_df.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bf37b2b5-1493-4a2b-a16c-3df39a99fcf2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 添加一个总房间数字段\n",
|
||||
"sz_df['rooms_num'] = sz_df.house_type.str.extract('(\\d+)室(\\d+)厅').astype('i8').sum(axis=1)\n",
|
||||
"sz_df.rooms_num.describe()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f605b5bd-9ccf-4946-b084-c05db4b1f78b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"sz_df.tail(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6f197094-8843-4575-bf87-8e6599d4dce9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 删除房间总数大于8个的房屋信息\n",
|
||||
"sz_df.drop(index=sz_df[sz_df.rooms_num > 8].index, inplace=True)\n",
|
||||
"sz_df.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "920d0e09-fa58-456a-9d3d-6329ef49ae67",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 单价分布\n",
|
||||
"sz_df.unit_price.plot(kind='hist', figsize=(9, 5), bins=15, ylabel='')\n",
|
||||
"plt.xticks(np.arange(10000, 210001, 20000))\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2fd023d2-b7a9-456e-a58d-731512711484",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 总价分布\n",
|
||||
"sz_df.total_price.plot(kind='hist', figsize=(9, 5), bins=15, ylabel='')\n",
|
||||
"plt.xticks(np.arange(100, 2901, 400))\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d1d68635-d7fa-44dc-97dc-8938cba1de80",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 统计每个区总价和均价的均值\n",
|
||||
"sz_df.pivot_table(\n",
|
||||
" index='area',\n",
|
||||
" values=['title', 'unit_price', 'total_price'],\n",
|
||||
" aggfunc={'title': 'count', 'unit_price': 'mean', 'total_price': 'mean'}\n",
|
||||
").round(1).sort_values(\n",
|
||||
" 'unit_price', ascending=False\n",
|
||||
").style.format(\n",
|
||||
" formatter={\n",
|
||||
" 'total_price': '¥{:.0f}万元',\n",
|
||||
" 'unit_price': '¥{:,.0f}元'\n",
|
||||
" }\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "538ebe18-432e-4951-8667-ce90cb73ae5e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 深圳每个区房屋平均单价Top3商圈\n",
|
||||
"temp_df = sz_df.groupby(['area', 'position'])[['unit_price']].mean().round(1)\n",
|
||||
"temp_df['rank'] = temp_df.unit_price.groupby('area').rank(method='dense', ascending=False).astype('i8')\n",
|
||||
"temp_df.query('rank <= 3')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "04aaf617-240d-4fc2-b702-fa3e03978347",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 深圳每个区房屋平均单价Top3商圈\n",
|
||||
"temp_df = sz_df.groupby(['area', 'position'], as_index=False)[['unit_price']].mean().round(1)\n",
|
||||
"temp_df = temp_df.groupby('area')[['position', 'unit_price']].apply(lambda x: x.nlargest(3, 'unit_price'))\n",
|
||||
"temp_df.style.hide(level=1).format(formatter={'unit_price': '¥{:,.0f}元'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "38f91365-6b40-40a1-b8bd-f0fd4cac9d50",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 哪种户型的二手房数量最多\n",
|
||||
"sz_df.groupby('house_type').house_type.count().nlargest(1).index[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4db07743-51cd-4007-8faf-7aa5714167d9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 总价Top10的二手房分布在哪些区\n",
|
||||
"top10 = sz_df.total_price.nlargest(10).index.values\n",
|
||||
"# 通过花式索引获取对应的行\n",
|
||||
"sz_df.loc[top10].groupby('area').area.count()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "870a64c4-3164-4b96-b910-fc80b5e44853",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 销售利润下滑诊断分析"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a1e63fa6-018e-4cea-9899-05bc4a4aaae2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"detail_df = pd.read_excel('res/商品销售明细表.xlsx', sheet_name='Sheet1')\n",
|
||||
"outlet_df = pd.read_excel('res/门店信息维度表.xlsx', sheet_name='Sheet1')\n",
|
||||
"commod_df = pd.read_excel('res/商品信息维度表.xlsx', sheet_name='Sheet1')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb430f84-5628-4dc5-a63a-36520cfcf66a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"detail_df.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "41a2f93a-3799-4253-8acd-6f3498283010",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"detail_df.rename(columns={'日期(年月日)': '销售日期'}, inplace=True)\n",
|
||||
"detail_df['销售日期'] = pd.to_datetime(detail_df.销售日期)\n",
|
||||
"detail_df['月份'] = detail_df.销售日期.dt.month\n",
|
||||
"detail_df['利润额'] = detail_df.销售额 - detail_df.成本额\n",
|
||||
"detail_df.head(5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5f94c5f3-c799-470f-a693-7d01afa4f88f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp1 = detail_df.groupby('月份')[['销售额', '利润额']].sum()\n",
|
||||
"temp1['销售月环比'] = temp1.销售额.pct_change()\n",
|
||||
"temp1['利润月环比'] = temp1.利润额.pct_change()\n",
|
||||
"temp1[['销售额', '销售月环比', '利润额', '利润月环比']].style.format(\n",
|
||||
" formatter={\n",
|
||||
" '销售月环比': '{:.2%}',\n",
|
||||
" '利润月环比': '{:.2%}',\n",
|
||||
" },\n",
|
||||
" na_rep='--------'\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "56b4ab4a-aa35-49c5-9387-80b545799cfe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp1.plot(kind='line', figsize=(9, 5), xlabel='', y=['销售额', '利润额'], color=['navy', 'coral'], marker='o')\n",
|
||||
"plt.ylim(0, 1.4e7)\n",
|
||||
"plt.grid(axis='y', linestyle=':', alpha=0.5)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "00ca4494-b03d-4f42-890f-9d8088bb61e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.ticker as tkr\n",
|
||||
"\n",
|
||||
"ax = temp1.销售额.plot(kind='line', figsize=(9, 5), marker='o', color='navy', linestyle='--')\n",
|
||||
"temp1.利润额.plot(ax=ax, kind='line', marker='*', color='darkgreen', linestyle='--', xlabel='')\n",
|
||||
"plt.ylim(0, 14000000)\n",
|
||||
"plt.legend(loc='lower right')\n",
|
||||
"\n",
|
||||
"# 基于ax构建双胞胎坐标系(共享横轴,自己定制纵轴)\n",
|
||||
"ax2 = ax.twinx()\n",
|
||||
"ax2.yaxis.set_major_formatter(tkr.PercentFormatter(xmax=1, decimals=0))\n",
|
||||
"profs_rates = temp1.利润额 / temp1.销售额\n",
|
||||
"profs_rates.plot(ax=ax2, kind='line', marker='^', color='r', linestyle=':', label='毛利率')\n",
|
||||
"plt.ylim(0.45, 0.65)\n",
|
||||
"plt.legend()\n",
|
||||
"plt.grid(axis='y', linestyle=':', alpha=0.5)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "637679a6-f7e1-4de8-a17e-4541790aa99c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 事实表连接维度表\n",
|
||||
"merged_df = pd.merge(detail_df, outlet_df, how='left', on='门店编码')\n",
|
||||
"merged_df = pd.merge(merged_df, commod_df, how='left', on='商品编码')\n",
|
||||
"august_df = merged_df.query('月份 == 8')\n",
|
||||
"august_df"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e49793fb-6149-4366-94f6-2546fd14065e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df2 = august_df.groupby('省份')[['销售额', '成本额']].sum()\n",
|
||||
"temp_df2.nlargest(10, '成本额')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6959bb8b-a2e5-4948-bfc1-c78be4a3d1d9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df2.nlargest(10, '成本额').plot(kind='bar', figsize=(9, 5), xlabel='')\n",
|
||||
"plt.xticks(rotation=0)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e62162ff-af16-4a8f-af56-32b64712f0a5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df3 = august_df.query('省份 == \"湖南省\"').groupby('城市')[['销售额', '成本额']].sum()\n",
|
||||
"temp_df3['利润率'] = (temp_df3.销售额 - temp_df3.成本额) / temp_df3.销售额\n",
|
||||
"temp_df3.nsmallest(3, '利润率').style.format(formatter={'利润率': '{:.2%}'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5626ff61-f8dd-4871-9ad3-28c25910d36b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df4 = august_df.query('省份 == \"湖南省\" and 城市 == \"长沙市\"').groupby('门店名称')[['销售额', '成本额']].sum()\n",
|
||||
"temp_df4['利润率'] = (temp_df4.销售额 - temp_df4.成本额) / temp_df4.销售额\n",
|
||||
"temp_df4.sort_values(by='利润率').style.format(formatter={'利润率': '{:.2%}'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4993f987-37ad-450c-971a-d54ff4f6bc29",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"august_df = august_df.query('省份 == \"湖南省\" and 城市 == \"长沙市\" and 门店名称 == \"长沙梅溪湖店\"')\n",
|
||||
"august_df.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "04dfedf1-e7f1-4493-be54-a32b5e997e0d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df5 = august_df.groupby('商品类别')[['销售额', '成本额']].sum()\n",
|
||||
"temp_df5['利润率'] = (temp_df5.销售额 - temp_df5.成本额) / temp_df5.销售额\n",
|
||||
"temp_df5.sort_values(by='利润率').style.format(formatter={'利润率': '{:.2%}'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3fd3e504-3292-4bab-b3dd-f2f3629f6285",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temp_df6 = august_df.query('商品类别 == \"零食\"').groupby('商品名称')[['销售额', '成本额']].sum()\n",
|
||||
"temp_df6['利润率'] = (temp_df6.销售额 - temp_df6.成本额) / temp_df6.销售额\n",
|
||||
"temp_df6.sort_values(by='利润率').style.format(formatter={'利润率': '{:.2%}'})"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 262 KiB |
|
|
@ -36,7 +36,7 @@ $$
|
|||
|
||||
### 数据集介绍
|
||||
|
||||
接下来为大家隆重介绍一下我们后续会使用到的一个重要的数据集——鸢尾花数据集(iris dataset)。鸢尾花数据集是机器学习领域中最著名、最经典的数据集之一,由英国统计学家 *Ronald A. Fisher* 于 1936 年在他的论文*《The Use of Multiple Measurements in Taxonomic Problems》*中首次引入,被广泛用于机器学习算法的入门和实验。
|
||||
接下来为大家隆重介绍一下我们后续会使用到的一个重要的数据集——鸢尾花数据集(iris dataset)。鸢尾花数据集是机器学习领域中最著名、最经典的数据集之一,由植物学家 *Edgar S. Anderson* 在加拿大魁北克加斯帕半岛采集,由英国统计学家 *Ronald A. Fisher* 于 1936 年在他的论文*《The Use of Multiple Measurements in Taxonomic Problems》*中首次引入,被广泛用于机器学习算法的入门和实验。
|
||||
|
||||
<img src="res/02_iris_dataset.png" style="zoom:38%;">
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ weighted avg 0.45 0.37 0.23 30
|
|||
|
||||
> **注意**:由于创建`MLPClassifier`时没有指定`random_state`参数,所以代码每次执行的结果可能并不相同。
|
||||
|
||||
模型的预测准确率只有`0.37`,大家对这个结果是不是感觉到非常失望,我们煞费苦心构建的模型预测效果竟然如此拉胯。别紧张,上面代码中我们创建神经网络模型时,`hidden_layer_sizes`参数设置的是`(1, )`,它表示我们的网络只有 1 个隐藏层,而且隐藏层只有 1 个神经元。我们只要增加隐藏层和神经元的数量,让模型可以更好的学习特征和目标之间的映射关系,预测的效果就会好起来。下面,我们将`hidden_layer_sizes`参数调整为`(32, 32, 32)`,即模型有三个隐藏层,每层有 32 个神经元,再来看看代码执行的结果。
|
||||
模型的预测准确率只有`0.37`,大家对这个结果是不是感觉到非常失望,我们煞费苦心构建的模型预测效果竟然如此拉胯。别紧张,上面代码中我们创建神经网络模型时,`hidden_layer_sizes`参数设置的是`(1, )`,它表示我们的网络只有 1 个隐藏层,而且隐藏层只有 1 个神经元,这个神经元承受了太多(它真的,我哭死)。接下俩,我们需要增加隐藏层和神经元的数量,让模型可以更好的学习特征和目标之间的映射关系,这样预测的效果就会好起来。下面,我们将`hidden_layer_sizes`参数调整为`(32, 32, 32)`,即模型有三个隐藏层,每层有 32 个神经元,再来看看代码执行的结果。
|
||||
|
||||
```python
|
||||
from sklearn.datasets import load_iris
|
||||
|
|
@ -176,7 +176,7 @@ y_pred = model.predict(X_test)
|
|||
print(classification_report(y_test, y_pred))
|
||||
```
|
||||
|
||||
> **说明**:大家可以试着运行上面的代码,看看有没有获得更好的结果。当然,大家也可以重新设置`hidden_layer_sizes`参数,看看会得到怎样的结果。
|
||||
> **说明**:大家可以试着运行上面的代码,看看有没有获得更好的结果。当然,模型准确率为 1 也未必就值得高兴,因为你可能训练了一个过拟合的模型。无论如何,大家可以试着重新设置`hidden_layer_sizes`参数,看看会得到怎样的结果。
|
||||
|
||||
下面,我们还是对`MLPClassifier`几个比较重要的超参数做一个说明。
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ Test MSE: 8.7226
|
|||
Test R2: 0.8569
|
||||
```
|
||||
|
||||
通过上面的输出可以看到,随着神经网络模型不断的前向传播和反向传播,损失变得越来越小,模型的拟合变得越来越好。在预测的时候,我们利用训练得到的模型参数进行一次正向传播,就完成了从特征到目标值的映射,模型评估的两个指标看起来还不错。目前,神经网络被广泛应用于模式识别、图像处理、语音识别等领域,是深度学习中最核心的技术。对深度学习有兴趣的读者,可以关注我的另一个项目[“深度学习就是大力出奇迹”](https://github.com/jackfrued/Deep-Learning-Is-Nothing),目前该项目仍然在创造更新中。
|
||||
通过上面的输出可以看到,随着神经网络模型不断的前向传播和反向传播,损失变得越来越小,模型的拟合变得越来越好。在预测的时候,我们利用训练得到的模型参数进行一次正向传播,就完成了从特征到目标值的映射,评估回归模型的两个指标 MSE 和 $\small{R^{2}}$ 看起来还不错哟。目前,神经网络被广泛应用于模式识别、图像处理、语音识别等领域,是深度学习中最核心的技术。对深度学习有兴趣的读者,可以关注我的另一个项目[“深度学习就是大力出奇迹”](https://github.com/jackfrued/Deep-Learning-Is-Nothing),目前该项目仍然在创作更新中。
|
||||
|
||||
### 模型优缺点
|
||||
|
||||
|
|
|
|||
|
|
@ -379,9 +379,9 @@ test['FamilySize'] = test['SibSp'] + test['Parch'] + 1
|
|||
# 删除多余特征
|
||||
test.drop(columns=['Name', 'Ticket', 'SibSp', 'Parch'], inplace=True)
|
||||
|
||||
# 逻辑回归模型
|
||||
# 使用逻辑回归模型
|
||||
passenger_id, X_test = test.index, test
|
||||
# XGBoost模型
|
||||
# 使用XGBoost模型
|
||||
# passenger_id, X_test = test.index, xgb.DMatrix(test)
|
||||
|
||||
y_test_pred = model.predict(X_test)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
## Python学习资源汇总
|
||||
|
||||
最近有很多小伙伴在找 Python 的相关学习资源,给大家做一个汇总吧,大家就不需要到处打听了,而且网上的资源良莠不齐,给大家整理一些优质的资源,让大家少走弯路。温馨提示一下,下面的资源选一些适合自己的就行了,并非每个都值得学习和研究。
|
||||
|
||||
### Python学习教程
|
||||
|
||||
#### 图文教程
|
||||
|
||||
1. [《从零开始学Python》](https://www.zhihu.com/column/c_1216656665569013760)- 我自己在知乎创作的专栏,欢迎大家打卡学习
|
||||
2. [《基于Python的数据分析》](https://www.zhihu.com/column/c_1217746527315496960)- 我自己在知乎创作的专栏,欢迎大家学习交流
|
||||
3. [《说走就走的AI之旅》](https://www.zhihu.com/column/c_1628900668109946880)- 我自己在知乎创作的专栏,欢迎大家学习交流
|
||||
4. [《Python - 100天从新手到大师》](https://github.com/jackfrued/Python-100-Days) - 我自己在 GitHub 分享的 Python 学习项目
|
||||
5. [《Python 3教程》](https://www.runoob.com/python3/python3-tutorial.html)- 菜鸟教程上的 Python 课程,上面还有很多其他学习资源
|
||||
6. [《Python教程》](https://liaoxuefeng.com/books/python/introduction/index.html)- 廖雪峰个人网站上的 Python 课程,上面还有一些其他学习资源
|
||||
|
||||
#### 视频教程
|
||||
|
||||
1. [《从零开始学Python》](https://space.bilibili.com/1177252794/lists/1222205)- 我自己分享在 Bilibili 的 Python 入门视频
|
||||
2. [《快速上手Python语言》](https://www.zhihu.com/education/video-course/1491848366791700480)- 在知乎知学堂上传的一套之前讲课的随堂视频
|
||||
3. [《Python进阶课程》](https://space.bilibili.com/1177252794/lists/4128173)- 我自己分享在 Bilibili 的 Python 进阶随堂视频
|
||||
4. [《Python数据分析三剑客》](https://space.bilibili.com/1177252794/lists/502289)- 我自己分享在 Bilibili 的 Python 数据分析随堂视频
|
||||
5. [《AI Python for Beginners》](https://www.deeplearning.ai/short-courses/ai-python-for-beginners/)- 吴恩达(Andrew Ng)老师的 Python 入门课
|
||||
6. [《AI for Everyone》](https://www.deeplearning.ai/courses/ai-for-everyone/)- 吴恩达(Andrew Ng)老师的 AI 通识课
|
||||
7. [《Deep Learning Specilizaiton》](https://www.deeplearning.ai/courses/deep-learning-specialization/)- 吴恩达(Andrew Ng)老师的深度学习专项课程
|
||||
8. [《100 Days of Code: The Complete Python Pro Bootcamp》](https://www.udemy.com/course/100-days-of-code/) - Udemy 上很受欢迎的一整套 Python 课程(付费)
|
||||
9. [《Python for Data Science and Machine Learning Bootcamp》](https://www.udemy.com/course/python-for-data-science-and-machine-learning-bootcamp/) - Udemy 上一套评分很高的数据科学课程(付费)
|
||||
10. [《PyTorch: Deep Learning and Artificial Intelligence》](https://www.udemy.com/course/pytorch-deep-learning/) - Udemy 好评课程(付费)
|
||||
|
||||
> **说明**:吴恩达老师的课程在 YouTube 和 Bilibili 上也有很多人分享,YouTube 上面也有很多免费的 Python 课程曾经让我觉得受益匪浅。这些课程很多都是言简意赅、直击问题的,不像国内很多培训机构,动不动就分享七百集的课程或者八百G的学习资料,让很多人误以为点赞收藏就是学会。国内外各种学习平台也很多,有人喜欢 Udemy,有人喜欢 Coursera,我只是把我自己看过觉得不错的课程分享出来,大家可以根据需要自己去对应的平台查找,当然更重要的是有计划的学习起来。
|
||||
|
||||
#### 资源网站
|
||||
|
||||
1. [Python 官方网站](https://python.org) - 下载 Python 解释器、查看官方文档、了解社区动态等
|
||||
2. [Online Python](<https://www.online-python.com/)、[Python-Fiddle](https://python-fiddle.com/)、[Google Colab](https://colab.research.google.com/) - 在线编写运行 Python 代码
|
||||
3. [Coddy](https://coddy.tech) - 在线学习和练习 Python,有点像学外语的“多邻国”
|
||||
4. [Django](https://www.djangoproject.com/)、[FastAPI](https://fastapi.tiangolo.com/) 官方网站 - Python 服务接口开发框架
|
||||
5. [NumPy](https://numpy.org/)、[Pandas](https://pandas.pydata.org/)、[Matplotlib](https://matplotlib.org/stable/) 官方网站 - Python 数据分析三大神器
|
||||
6. [Polars](https://pola.rs/) 官方网站 - pandas 的高性能替代方案
|
||||
7. [CuPy](https://cupy.dev/)、[cuDF](https://github.com/rapidsai/cudf)、[RAPIDS](https://rapids.ai/) 官方网站 - 用 GPU 加速数学科学
|
||||
8. [Scikit-learn](https://scikit-learn.org/stable/)、[PyTorch](https://pytorch.org/)、[Tensorflow](https://www.tensorflow.org/)、[Keras](https://keras.io/)官方网站 - 机器学习、深度学习框架
|
||||
9. [Hugging Face](https://huggingface.co/) 官方网站 - transformers 库提供了大量的预训练模型,助力深度学习模型开发
|
||||
10. [Kaggle](https://www.kaggle.com/) 官方网站 - 全球知名的数据科学和机器学习平台
|
||||
11. [GitHub](https://github.com/) 官方网站 - 全球最大代码托管平台,上面有很多优质的代码和资源
|
||||
12. [YouTube](https://www.youtube.com/) 网站 - 全球最大的视频分享平台,有很多很棒的学习视频
|
||||
13. [Bilibili](https://www.bilibili.com/) 网站 - 原本是一个二次元平台,现在也是年轻人的学习平台
|
||||
14. [中国大学 MOOC](https://www.icourse163.org/)、[网易云课堂](https://study.163.com/)、[慕课网](https://www.imooc.com/)、[Udemy]()、[Coursera]()、[Udacity]()、[edX](https://www.edx.org/) - 在线学习平台
|
||||
15. [DeepLearning.ai](https://www.deeplearning.ai/) - 吴恩达(Andrew Ng)老师创办的深度学习教育平台
|
||||
16. [力扣](https://leetcode.cn/)、[牛客网](https://www.nowcoder.com/)、[HackerRank](https://www.hackerrank.com/)、[topcoder](https://www.topcoder.com/) - 在线刷题、比赛平台
|
||||
17. [NVIDIA深度学习培训中心](https://link.zhihu.com/?target=https%3A//www.nvidia.cn/training/)、[DataCamp](https://link.zhihu.com/?target=https%3A//www.datacamp.com/) - 有免费和付费的学习资源
|
||||
18. [BecomingHuman.ai](https://link.zhihu.com/?target=https%3A//becominghuman.ai/) - 上面有很多关于 AI 的话题,有一些精美的 Cheat Sheet(知识速查表)
|
||||
|
||||
|
||||
### Python参考书籍
|
||||
|
||||
#### 入门读物
|
||||
|
||||
1. 《Python编程从入门到实践》(*Python Crash Course*)- 著名的蟒蛇书,推荐
|
||||
2. 《Python基础教程》(*Beginning Python From Novice to Professional*)- 入门经典
|
||||
3. 《Python学习手册》(*Learning Python*)- 著名的老鼠书
|
||||
4. 《Python编程导论》(*Introduction to computation and programming using Python*)- 我自己很喜欢这本书
|
||||
|
||||
#### 进阶读物
|
||||
|
||||
1. 《Python Cookbook》- 照着菜谱做,肯定不出错,进阶首选
|
||||
2. 《流畅的Python》(*Fluent Python*)- 成为高手的必经之路
|
||||
3. 《Effective Python:编写高质量Python代码的59个有效方法》(*Effective Python 59 Specific Ways to Write Better Python*)
|
||||
4. 《Python高级编程》(*Expert Python Programming*)- 著名的花书
|
||||
5. 《Python项目开发实战》- 有很多工程化项目开发的知识
|
||||
|
||||
#### 数据采集
|
||||
|
||||
1. 《Python 3网络爬虫开发实战》- 个人推荐
|
||||
2. 《Python网络书籍擦剂》- 著名的穿山甲书
|
||||
|
||||
#### 数据分析
|
||||
|
||||
1. 《利用Python进行数据分析》(*Python for Data Analysis*)- pandas 作者写的书
|
||||
2. 《Python数据科学手册》(*Python Data Science Handbook*)- O'Reilly 动物数系列的鬣蜥书
|
||||
3. 《Python数据分析实战》(*Python Data Analytics With Pandas, NumPy, and Matplotlib*)- 个人推荐
|
||||
4. 《Python数据可视化编程实战》(*Python Data Visualization Cookbook*)- 重点在数据可视化
|
||||
5. 《深入浅出数据科学》(*Principles of Data Science*)- 我自己很喜欢这本书
|
||||
6. 《面向数据科学家的实用统计学》(*Practical Statistics for Data Scientists*)- 很实用的统计学
|
||||
7. 《数据科学入门》(*Data Science from Scratch*)
|
||||
|
||||
#### 机器学习
|
||||
|
||||
1. 《机器学习实战》(*Machine Learning in Aciton*)- 入门推荐
|
||||
2. 《机器学习(鸢尾花数学大系:从加减乘除到机器学习)》- 姜伟生博士非常用心的作品
|
||||
3. 《深度学习入门:基于Python的理论与实现》- 日本获奖书籍,入门推荐
|
||||
4. 《深度学习》(*Deep Learning*)- 深度学习经典神作
|
||||
5. 《动手学深度学习》(*Dive into Deep Learning*)- 阿斯顿·张和李沐强强联合出品
|
||||
6. 《Python深度学习》(*Deep Learning with Python*)- 我自己很喜欢这本书
|
||||
7. 《机器学习实战》(*Hands-On Machine Learning with Scikit-Learn, Keras, and Tensorflow*)- 著名的蜥蜴书,从机器学习到深度学习
|
||||
|
||||
#### 大模型
|
||||
|
||||
1. 《BERT基础教程:Transformer大模型实战》(*Getting Started with Google BERT*)- 五星好评书籍
|
||||
|
||||
2. 《Build a Large Language Model》
|
||||
3. 《Hands-On Large Language Models》
|
||||
4. 《大模型应用开发极简入门:基于GPT-4和ChatGPT》(*Developing Apps with GPT-4 and ChatGPT*)
|
||||
|
||||
#### 测试运维
|
||||
|
||||
1. 《Selenium自动化测试:基于Python语言》(*Learning Selenium Testing Tools with Python*)
|
||||
2. 《pytest测试实战》(*Python Testing with pytest*)
|
||||
3. 《Python自动化运维实战》(*Hands-On Enterprise Automation with Python*)
|
||||
4. 《Python自动化运维技术与最佳实践》
|
||||
Loading…
Reference in New Issue