├── .github └── workflows │ └── issue_to_yuque.yml ├── .travis.yml ├── Python高级编程 ├── README.md ├── 并发编程.md ├── 正则表达式.md ├── 网络编程.md ├── 面向对象.md └── 高级特性.md ├── README.md ├── Web开发 ├── Flask.md └── README.md ├── assets ├── images │ ├── 00.jpg │ ├── 11.jpg │ ├── 117_01.png │ ├── 12.jpg │ ├── 13.jpg │ ├── 131_01.jpg │ ├── 132_01.png │ ├── 133_01.png │ ├── 133_02.png │ ├── 133_03.png │ ├── 133_04.png │ ├── 133_05.jpg │ ├── 133_06.jpg │ ├── 134_01.png │ ├── 134_02.png │ ├── 135_01.png │ ├── 135_02.png │ ├── 135_03.png │ ├── 135_04.png │ ├── 135_05.png │ ├── 137_01.jpg │ ├── 14.jpg │ ├── 146_01.png │ ├── 146_02.png │ ├── 146_03.png │ ├── 146_04.png │ ├── 146_05.png │ ├── 146_06.png │ ├── 146_07.png │ ├── 15.jpg │ ├── 154_01.png │ ├── 21.jpg │ ├── 22.jpg │ ├── 221_01.gif │ ├── 221_02.jpg │ ├── 221_03.gif │ ├── 222_01.png │ ├── 222_02.png │ ├── 222_03.png │ ├── 222_04.png │ ├── 222_05.png │ ├── 223_01.gif │ ├── 226_01.jpg │ ├── 227_01.jpg │ ├── 227_02.png │ ├── 227_03.gif │ ├── 31.jpg │ ├── 311_01.jpg │ ├── 32.jpg │ ├── 321_01.png │ ├── 33.jpg │ ├── 34.jpg │ ├── 35.jpg │ ├── 351_01.png │ ├── 41.jpg │ ├── 412_01.jpg │ ├── 412_02.jpg │ ├── 51.jpg │ ├── 512_01.png │ ├── 512_02.png │ ├── 512_03.png │ ├── 512_04.png │ ├── 513_01.png │ ├── 513_02.png │ ├── 513_03.png │ ├── 513_04.png │ ├── 513_05.png │ ├── 513_06.png │ ├── 516_01.jpg │ ├── 516_02.jpg │ ├── 516_03.png │ ├── 516_04.png │ ├── 516_05.jpg │ ├── 52.jpg │ ├── 53.jpg │ ├── 534_01.jpg │ ├── 534_02.jpg │ ├── 536_01.jpg │ ├── 537_01.png │ ├── 538_01.png │ ├── 55.jpg │ ├── 551_01.png │ ├── 553_01.png │ ├── 553_02.png │ ├── 553_03.jpg │ ├── 56.jpg │ ├── 5610_01.jpg │ ├── 5610_02.jpg │ ├── 564_01.jpg │ ├── 564_02.jpg │ ├── 564_03.jpg │ ├── 566_01.png │ ├── 567_01.png │ ├── 567_02.png │ ├── 567_03.png │ ├── 567_04.png │ ├── 567_05.png │ ├── 569_01.png │ ├── 569_02.png │ ├── 569_03.png │ ├── 569_04.png │ ├── 569_05.png │ ├── 569_06.png │ ├── 61.jpg │ ├── 62.jpg │ ├── 621_01.png │ ├── 621_02.png │ ├── 621_03.png │ ├── 622_01.png │ ├── 63.jpg │ ├── 631_01.png │ ├── 632_01.png │ ├── 632_02.png │ ├── 632_03.png │ ├── 632_04.png │ ├── 632_05.png │ ├── 632_06.png │ ├── 64.jpg │ ├── 641_01.png │ ├── 641_02.png │ ├── 641_03.png │ ├── 642_01.png │ ├── 643_01.png │ ├── 65.jpg │ ├── 66.jpg │ ├── 661_01.png │ ├── 661_02.png │ ├── 664_01.jpg │ ├── 664_02.jpg │ ├── 664_03.jpg │ ├── 664_04.jpg │ ├── 664_05.jpg │ ├── 67.jpg │ ├── 672_01.png │ ├── 672_02.png │ ├── 71.jpg │ ├── 712_01.png │ ├── 713_01.png │ ├── 72.jpg │ ├── 721_01.png │ ├── 73.jpg │ ├── 74.jpg │ ├── 75.jpg │ ├── 751_01.png │ ├── 751_02.png │ ├── 751_03.png │ ├── 751_04.png │ ├── 751_05.png │ ├── 751_06.png │ ├── 751_07.png │ ├── 751_08.png │ ├── 751_09.png │ ├── 751_10.png │ ├── 752_01.png │ ├── 752_02.png │ ├── 752_03.png │ ├── 752_04.png │ ├── 752_05.png │ ├── 752_06.png │ ├── 752_07.png │ ├── 752_08.png │ ├── 81.jpg │ ├── 811_01.png │ ├── 811_02.png │ ├── 811_03.jpg │ ├── 811_04.png │ ├── 82.jpg │ ├── 821_01.png │ ├── 824_01.png │ ├── 824_02.png │ ├── 824_03.png │ ├── 824_04.png │ ├── 824_05.png │ ├── 83.jpg │ ├── 832_01.jpg │ ├── 833_01.jpg │ ├── 834_01.png │ ├── 835_01.jpg │ ├── 84.jpg │ ├── backend_mind.png │ ├── interview_system_01.png │ └── machine_learning.png └── scripts │ ├── 721_01.py │ ├── 751_01.py │ ├── 751_02.py │ ├── 751_03.py │ ├── 751_04.py │ ├── 751_05.py │ ├── 751_06.py │ ├── 751_07.py │ ├── 751_08.py │ ├── 751_09.py │ ├── 751_10.py │ ├── 752_01.py │ ├── 752_02.py │ ├── 752_03.py │ ├── 752_04.py │ ├── 752_05.py │ ├── 752_06.py │ ├── 752_07.py │ ├── 752_08.py │ ├── 821_01.py │ ├── 821_02.py │ ├── 821_02.txt │ ├── 822_01.dot │ ├── 822_01.py │ ├── 822_01.tree │ ├── 822_01.txt │ ├── 823_01.py │ ├── 824_01.py │ ├── 824_01.txt │ ├── 824_02.txt │ ├── 824_03.py │ ├── 824_03.txt │ ├── 832_01.py │ ├── 833_01.py │ ├── 833_01.txt │ ├── 833_02.txt │ ├── 834_01.py │ ├── 834_02.py │ ├── 834_03.py │ ├── 841_01.py │ ├── 841_01.txt │ ├── decision_tree.py │ └── svm.py ├── ci.py ├── issues_to_yuque.py ├── 分布式 ├── README.md ├── 分布式协同与同步.md ├── 分布式存储.md ├── 分布式概述.md ├── 分布式计算模式.md ├── 分布式资源管理和负载调度.md ├── 分布式通信.md └── 分布式高可靠.md ├── 数据分析 ├── NumPy.md ├── Pandas.md ├── README.md ├── 数据分析方法.md ├── 数据可视化.md └── 统计学基础.md ├── 数据库 ├── MongoDB.md ├── MySQL.md ├── README.md ├── Redis.md ├── SQL.md └── 数据库系统原理.md ├── 机器学习 ├── README.md ├── 基础概念.md ├── 监督学习.md ├── 集成学习.md └── 非监督学习.md ├── 算法 ├── README.md ├── 数据结构.md └── 经典算法.md ├── 网络爬虫 ├── HTML内容解析和BeautifulSoup.md ├── README.md ├── Scrapy.md ├── 从输入URL到打开网页.md ├── 动态网页请求.md └── 网络资源请求和Requests.md └── 题目整理 ├── README.md └── 算法与数据结构.md /.github/workflows/issue_to_yuque.yml: -------------------------------------------------------------------------------- 1 | name: issue_to_yuque 2 | 3 | on: 4 | issues: 5 | types: [edited, labeled, deleted] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up Python 3.7 13 | uses: actions/setup-python@v1 14 | with: 15 | python-version: 3.7 16 | - name: Install dependencies 17 | run: | 18 | python -m pip install --upgrade pip 19 | pip install requests 20 | - name: Update yuque repo 21 | env: 22 | ISPUBLIC: 1 23 | YUQUE_REPO: jasonje/notecards 24 | YUQUE_API: https://www.yuque.com/api/v2 25 | YUQUE_TOKEN: ${{ secrets.YUQUE_TOKEN }} 26 | GITHUB_API: https://api.github.com/repos/jasonje/notes/ 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | run: | 29 | python issues_to_yuque.py -t ${{ github.event.action }} 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.6' 4 | install: "pip install requests gitpython" 5 | script: 6 | - git config --global core.quotepath false 7 | - python ci.py 8 | -------------------------------------------------------------------------------- /Python高级编程/README.md: -------------------------------------------------------------------------------- 1 | # 1. Python 高级编程 2 | 3 | ## 1.1 [面向对象](面向对象.md) 4 | 5 | ### 1.1.1 [类和实例](面向对象.md#111-类和实例) 6 | 7 | ### 1.1.2 [`__slots__`属性](面向对象.md#112-__slots__属性) 8 | 9 | ### 1.1.3 [访问控制](面向对象.md#113-访问控制) 10 | 11 | ### 1.1.4 [可管理的属性](面向对象.md#114-可管理的属性) 12 | 13 | ### 1.1.5 [调用父类方法](面向对象.md#115-调用父类方法) 14 | 15 | ### 1.1.6 [定制类](面向对象.md#116-定制类) 16 | 17 | ### 1.1.7 [魔术方法](面向对象.md#117-魔术方法) 18 | 19 | ## 1.2 [正则表达式](正则表达式.md) 20 | 21 | ### 1.2.1 [`re`模块](正则表达式.md#121-re模块) 22 | 23 | ### 1.2.2 [`compile`函数](正则表达式.md#122-compile函数) 24 | 25 | ### 1.2.3 [`group`、`groups`和`groupdict`函数](正则表达式.md#123-groupgroups和groupdict函数) 26 | 27 | ### 1.2.4 [`match`函数](正则表达式.md#124-match函数) 28 | 29 | ### 1.2.5 [`search`函数](正则表达式.md#125-search函数) 30 | 31 | ### 1.2.6 [`findall`和`finditer`函数](正则表达式.md#126-findall和finditer函数) 32 | 33 | ### 1.2.7 [`sub`和`subn`函数](正则表达式.md#127-sub和subn函数) 34 | 35 | ### 1.2.8 [`split`函数](正则表达式.md#128-split函数) 36 | 37 | ### 1.2.9 [正则表达式语法](正则表达式.md#129-正则表达式语法) 38 | 39 | ## 1.3 [网络编程](网络编程.md) 40 | 41 | ### 1.3.1 [计算机网络体系](网络编程.md#131-计算机网络体系) 42 | 43 | ### 1.3.2 [`OSI`和`TCP/IP`的区别](网络编程.md#132-osi和tcpip的区别) 44 | 45 | ### 1.3.3 [`TCP`协议](网络编程.md#133-tcp协议) 46 | 47 | ### 1.3.4 [`UDP`协议](网络编程.md#134-udp协议) 48 | 49 | ### 1.3.5 [`HTTP`协议](网络编程.md#135-http协议) 50 | 51 | ### 1.3.6 [`FTP`和`SMTP`协议](网络编程.md#136-ftp和smtp协议) 52 | 53 | ### 1.3.7 [`DNS`协议](网络编程.md#137-dns协议) 54 | 55 | ### 1.3.8 [`Socket`编程](网络编程.md#138-socket编程) 56 | 57 | ### 1.3.9 [`WSGI`接口和`HTTP`服务](网络编程.md#139-wsgi接口和http服务) 58 | 59 | ### 1.3.10 [`RPC`编程](网络编程.md#1310-rpc编程) 60 | 61 | ## 1.4 [并发编程](并发编程.md) 62 | 63 | ### 1.4.1 [多进程](并发编程.md#142-多进程) 64 | 65 | ### 1.4.2 [多线程](并发编程.md#143-多线程) 66 | 67 | ### 1.4.3 [协程](并发编程.md#145-协程) 68 | 69 | ### 1.4.4 [`GIL`锁](并发编程.md#141-gil锁) 70 | 71 | ### 1.4.5 [计算密集型和`IO`密集型](并发编程.md#145-计算密集型和io密集型) 72 | 73 | ### 1.4.6 [`IO`模型](并发编程.md#146-io模型) 74 | 75 | ### 1.4.7 [`CPython`](并发编程.md#147-cpython) 76 | 77 | ## 1.5 [高级特性](高级特性.md) 78 | 79 | ### 1.5.1 [不可变类型](高级特性.md#151-不可变类型) 80 | 81 | ### 1.5.2 [列表推导式、迭代器、生成器](高级特性.md#152-列表推导式迭代器生成器) 82 | 83 | ### 1.5.3 [返回函数](高级特性.md#153-返回函数) 84 | 85 | ### 1.5.4 [闭包和装饰器](高级特性.md#154-闭包和装饰器) 86 | 87 | ### 1.5.5 [函数式编程](高级特性.md#155-函数式编程) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](./assets/images/00.jpg) 2 | 3 | # :dart: 技术笔记 4 | 5 | ![lastcommit]() 6 | 7 | ## 目录 8 | 9 |
10 | :snake: 1. Python 高级编程 11 | 12 | #### 1.1 [面向对象](Python高级编程/面向对象.md) 13 | 14 | #### 1.2 [正则表达式](Python高级编程/正则表达式.md) 15 | 16 | #### 1.3 [网络编程](Python高级编程/网络编程.md) 17 | 18 | #### 1.4 [并发编程](Python高级编程/并发编程.md) 19 | 20 | #### 1.5 [高级特性](Python高级编程/高级特性.md) 21 | 22 |
23 | 24 |
25 | :books: 2. 算法 26 | 27 | #### 2.1 [数据结构](算法/数据结构.md) 28 | 29 | #### 2.2 [经典算法](算法/经典算法.md) 30 | 31 |
32 | 33 |
34 | :octopus: 3. 网络爬虫 35 | 36 | #### 3.1 [从输入URL到打开网页](网络爬虫/从输入URL到打开网页.md) 37 | 38 | #### 3.2 [网络资源请求和Requests](网络爬虫/网络资源请求和Requests.md) 39 | 40 | #### 3.3 [HTML内容解析和BeautifulSoup](网络爬虫/HTML内容解析和BeautifulSoup.md) 41 | 42 | #### 3.4 [动态网页请求](网络爬虫/动态网页请求.md) 43 | 44 | #### 3.5 [Scrapy](网络爬虫/Scrapy.md) 45 | 46 |
47 | 48 |
49 | :computer: 4. Web开发 50 | 51 | #### 4.1 [Flask](Web开发/Flask.md) 52 | 53 | #### 4.2 Django 54 | 55 |
56 | 57 |
58 | :file_folder: 5. 数据库 59 | 60 | #### 5.1 [数据库系统原理](数据库/数据库系统原理.md) 61 | 62 | #### 5.2 [SQL](数据库/SQL.md) 63 | 64 | #### 5.3 [MySQL](数据库/MySQL.md) 65 | 66 | #### 5.4 PostgreSQL 67 | 68 | #### 5.5 [MongoDB](数据库/MongoDB.md) 69 | 70 | #### 5.6 [Redis](数据库/Redis.md) 71 | 72 |
73 | 74 |
75 | :electric_plug: 6. 分布式 76 | 77 | #### 6.1 [分布式概述](分布式/分布式概述.md) 78 | 79 | #### 6.2 [分布式协同与同步](分布式/分布式协同与同步.md) 80 | 81 | #### 6.3 [分布式资源管理和负载调度](分布式/分布式资源管理和负载调度.md) 82 | 83 | #### 6.4 [分布式计算模式](分布式/分布式计算模式.md) 84 | 85 | #### 6.5 [分布式通信](分布式/分布式通信.md) 86 | 87 | #### 6.6 [分布式存储](分布式/分布式存储.md) 88 | 89 | #### 6.7 [分布式高可靠](分布式/分布式高可靠.md) 90 | 91 |
92 | 93 |
94 | :chart_with_upwards_trend: 7. 数据分析 95 | 96 | #### 7.1 [统计学基础](数据分析/统计学基础.md) 97 | 98 | #### 7.2 [数据分析方法](数据分析/数据分析方法.md) 99 | 100 | #### 7.3 [`Numpy`](数据分析/NumPy.md) 101 | 102 | #### 7.4 [`Pandas`](数据分析/Pandas.md) 103 | 104 | #### 7.5 [数据可视化](数据分析/数据可视化.md) 105 | 106 |
107 | 108 |
109 | :telescope: 8. 机器学习 110 | 111 | #### 8.1 [基础概念](机器学习/基础概念.md) 112 | 113 | #### 8.2 [监督学习](机器学习/监督学习.md) 114 | 115 | #### 8.3 [集成学习](机器学习/集成学习.md) 116 | 117 | #### 8.4 [非监督学习](机器学习/非监督学习.md) 118 | 119 |
120 | 121 |
122 | :thought_balloon: 9. 深度学习 123 | 124 |
125 | 126 | ## 说明 127 | 128 | 部分内容可能未注明出处,如果有未注明出处或者侵权的,请与我联系。 129 | 130 | 笔记大部分是个人整理的,很多内容有误,欢迎提交 `Issue` 或者 `PR`,大家相互学习,万分感谢。 131 | 132 | ## License 133 | 134 |
135 | 136 | 知识共享许可协议 137 | 138 |
139 | -------------------------------------------------------------------------------- /Web开发/README.md: -------------------------------------------------------------------------------- 1 | # 4. Web开发 2 | 3 | ## 4.1 [Flask](Flask.md) 4 | 5 | ### 4.1.1 [简明教程](Flask.md#411-简明教程) 6 | 7 | ### 4.1.2 [上下文和线程安全](Flask.md#412-上下文和线程安全) 8 | 9 | ### 4.1.3 [路由规则](Flask.md#413-路由规则) 10 | 11 | ## 4.2 Django -------------------------------------------------------------------------------- /assets/images/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/00.jpg -------------------------------------------------------------------------------- /assets/images/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/11.jpg -------------------------------------------------------------------------------- /assets/images/117_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/117_01.png -------------------------------------------------------------------------------- /assets/images/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/12.jpg -------------------------------------------------------------------------------- /assets/images/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/13.jpg -------------------------------------------------------------------------------- /assets/images/131_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/131_01.jpg -------------------------------------------------------------------------------- /assets/images/132_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/132_01.png -------------------------------------------------------------------------------- /assets/images/133_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_01.png -------------------------------------------------------------------------------- /assets/images/133_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_02.png -------------------------------------------------------------------------------- /assets/images/133_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_03.png -------------------------------------------------------------------------------- /assets/images/133_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_04.png -------------------------------------------------------------------------------- /assets/images/133_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_05.jpg -------------------------------------------------------------------------------- /assets/images/133_06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/133_06.jpg -------------------------------------------------------------------------------- /assets/images/134_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/134_01.png -------------------------------------------------------------------------------- /assets/images/134_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/134_02.png -------------------------------------------------------------------------------- /assets/images/135_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/135_01.png -------------------------------------------------------------------------------- /assets/images/135_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/135_02.png -------------------------------------------------------------------------------- /assets/images/135_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/135_03.png -------------------------------------------------------------------------------- /assets/images/135_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/135_04.png -------------------------------------------------------------------------------- /assets/images/135_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/135_05.png -------------------------------------------------------------------------------- /assets/images/137_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/137_01.jpg -------------------------------------------------------------------------------- /assets/images/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/14.jpg -------------------------------------------------------------------------------- /assets/images/146_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_01.png -------------------------------------------------------------------------------- /assets/images/146_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_02.png -------------------------------------------------------------------------------- /assets/images/146_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_03.png -------------------------------------------------------------------------------- /assets/images/146_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_04.png -------------------------------------------------------------------------------- /assets/images/146_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_05.png -------------------------------------------------------------------------------- /assets/images/146_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_06.png -------------------------------------------------------------------------------- /assets/images/146_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/146_07.png -------------------------------------------------------------------------------- /assets/images/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/15.jpg -------------------------------------------------------------------------------- /assets/images/154_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/154_01.png -------------------------------------------------------------------------------- /assets/images/21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/21.jpg -------------------------------------------------------------------------------- /assets/images/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/22.jpg -------------------------------------------------------------------------------- /assets/images/221_01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/221_01.gif -------------------------------------------------------------------------------- /assets/images/221_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/221_02.jpg -------------------------------------------------------------------------------- /assets/images/221_03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/221_03.gif -------------------------------------------------------------------------------- /assets/images/222_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/222_01.png -------------------------------------------------------------------------------- /assets/images/222_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/222_02.png -------------------------------------------------------------------------------- /assets/images/222_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/222_03.png -------------------------------------------------------------------------------- /assets/images/222_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/222_04.png -------------------------------------------------------------------------------- /assets/images/222_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/222_05.png -------------------------------------------------------------------------------- /assets/images/223_01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/223_01.gif -------------------------------------------------------------------------------- /assets/images/226_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/226_01.jpg -------------------------------------------------------------------------------- /assets/images/227_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/227_01.jpg -------------------------------------------------------------------------------- /assets/images/227_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/227_02.png -------------------------------------------------------------------------------- /assets/images/227_03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/227_03.gif -------------------------------------------------------------------------------- /assets/images/31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/31.jpg -------------------------------------------------------------------------------- /assets/images/311_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/311_01.jpg -------------------------------------------------------------------------------- /assets/images/32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/32.jpg -------------------------------------------------------------------------------- /assets/images/321_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/321_01.png -------------------------------------------------------------------------------- /assets/images/33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/33.jpg -------------------------------------------------------------------------------- /assets/images/34.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/34.jpg -------------------------------------------------------------------------------- /assets/images/35.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/35.jpg -------------------------------------------------------------------------------- /assets/images/351_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/351_01.png -------------------------------------------------------------------------------- /assets/images/41.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/41.jpg -------------------------------------------------------------------------------- /assets/images/412_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/412_01.jpg -------------------------------------------------------------------------------- /assets/images/412_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/412_02.jpg -------------------------------------------------------------------------------- /assets/images/51.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/51.jpg -------------------------------------------------------------------------------- /assets/images/512_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/512_01.png -------------------------------------------------------------------------------- /assets/images/512_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/512_02.png -------------------------------------------------------------------------------- /assets/images/512_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/512_03.png -------------------------------------------------------------------------------- /assets/images/512_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/512_04.png -------------------------------------------------------------------------------- /assets/images/513_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_01.png -------------------------------------------------------------------------------- /assets/images/513_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_02.png -------------------------------------------------------------------------------- /assets/images/513_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_03.png -------------------------------------------------------------------------------- /assets/images/513_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_04.png -------------------------------------------------------------------------------- /assets/images/513_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_05.png -------------------------------------------------------------------------------- /assets/images/513_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/513_06.png -------------------------------------------------------------------------------- /assets/images/516_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/516_01.jpg -------------------------------------------------------------------------------- /assets/images/516_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/516_02.jpg -------------------------------------------------------------------------------- /assets/images/516_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/516_03.png -------------------------------------------------------------------------------- /assets/images/516_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/516_04.png -------------------------------------------------------------------------------- /assets/images/516_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/516_05.jpg -------------------------------------------------------------------------------- /assets/images/52.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/52.jpg -------------------------------------------------------------------------------- /assets/images/53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/53.jpg -------------------------------------------------------------------------------- /assets/images/534_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/534_01.jpg -------------------------------------------------------------------------------- /assets/images/534_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/534_02.jpg -------------------------------------------------------------------------------- /assets/images/536_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/536_01.jpg -------------------------------------------------------------------------------- /assets/images/537_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/537_01.png -------------------------------------------------------------------------------- /assets/images/538_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/538_01.png -------------------------------------------------------------------------------- /assets/images/55.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/55.jpg -------------------------------------------------------------------------------- /assets/images/551_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/551_01.png -------------------------------------------------------------------------------- /assets/images/553_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/553_01.png -------------------------------------------------------------------------------- /assets/images/553_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/553_02.png -------------------------------------------------------------------------------- /assets/images/553_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/553_03.jpg -------------------------------------------------------------------------------- /assets/images/56.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/56.jpg -------------------------------------------------------------------------------- /assets/images/5610_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/5610_01.jpg -------------------------------------------------------------------------------- /assets/images/5610_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/5610_02.jpg -------------------------------------------------------------------------------- /assets/images/564_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/564_01.jpg -------------------------------------------------------------------------------- /assets/images/564_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/564_02.jpg -------------------------------------------------------------------------------- /assets/images/564_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/564_03.jpg -------------------------------------------------------------------------------- /assets/images/566_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/566_01.png -------------------------------------------------------------------------------- /assets/images/567_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/567_01.png -------------------------------------------------------------------------------- /assets/images/567_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/567_02.png -------------------------------------------------------------------------------- /assets/images/567_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/567_03.png -------------------------------------------------------------------------------- /assets/images/567_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/567_04.png -------------------------------------------------------------------------------- /assets/images/567_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/567_05.png -------------------------------------------------------------------------------- /assets/images/569_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_01.png -------------------------------------------------------------------------------- /assets/images/569_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_02.png -------------------------------------------------------------------------------- /assets/images/569_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_03.png -------------------------------------------------------------------------------- /assets/images/569_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_04.png -------------------------------------------------------------------------------- /assets/images/569_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_05.png -------------------------------------------------------------------------------- /assets/images/569_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/569_06.png -------------------------------------------------------------------------------- /assets/images/61.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/61.jpg -------------------------------------------------------------------------------- /assets/images/62.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/62.jpg -------------------------------------------------------------------------------- /assets/images/621_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/621_01.png -------------------------------------------------------------------------------- /assets/images/621_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/621_02.png -------------------------------------------------------------------------------- /assets/images/621_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/621_03.png -------------------------------------------------------------------------------- /assets/images/622_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/622_01.png -------------------------------------------------------------------------------- /assets/images/63.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/63.jpg -------------------------------------------------------------------------------- /assets/images/631_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/631_01.png -------------------------------------------------------------------------------- /assets/images/632_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_01.png -------------------------------------------------------------------------------- /assets/images/632_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_02.png -------------------------------------------------------------------------------- /assets/images/632_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_03.png -------------------------------------------------------------------------------- /assets/images/632_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_04.png -------------------------------------------------------------------------------- /assets/images/632_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_05.png -------------------------------------------------------------------------------- /assets/images/632_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/632_06.png -------------------------------------------------------------------------------- /assets/images/64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/64.jpg -------------------------------------------------------------------------------- /assets/images/641_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/641_01.png -------------------------------------------------------------------------------- /assets/images/641_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/641_02.png -------------------------------------------------------------------------------- /assets/images/641_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/641_03.png -------------------------------------------------------------------------------- /assets/images/642_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/642_01.png -------------------------------------------------------------------------------- /assets/images/643_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/643_01.png -------------------------------------------------------------------------------- /assets/images/65.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/65.jpg -------------------------------------------------------------------------------- /assets/images/66.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/66.jpg -------------------------------------------------------------------------------- /assets/images/661_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/661_01.png -------------------------------------------------------------------------------- /assets/images/661_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/661_02.png -------------------------------------------------------------------------------- /assets/images/664_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/664_01.jpg -------------------------------------------------------------------------------- /assets/images/664_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/664_02.jpg -------------------------------------------------------------------------------- /assets/images/664_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/664_03.jpg -------------------------------------------------------------------------------- /assets/images/664_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/664_04.jpg -------------------------------------------------------------------------------- /assets/images/664_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/664_05.jpg -------------------------------------------------------------------------------- /assets/images/67.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/67.jpg -------------------------------------------------------------------------------- /assets/images/672_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/672_01.png -------------------------------------------------------------------------------- /assets/images/672_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/672_02.png -------------------------------------------------------------------------------- /assets/images/71.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/71.jpg -------------------------------------------------------------------------------- /assets/images/712_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/712_01.png -------------------------------------------------------------------------------- /assets/images/713_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/713_01.png -------------------------------------------------------------------------------- /assets/images/72.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/72.jpg -------------------------------------------------------------------------------- /assets/images/721_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/721_01.png -------------------------------------------------------------------------------- /assets/images/73.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/73.jpg -------------------------------------------------------------------------------- /assets/images/74.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/74.jpg -------------------------------------------------------------------------------- /assets/images/75.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/75.jpg -------------------------------------------------------------------------------- /assets/images/751_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_01.png -------------------------------------------------------------------------------- /assets/images/751_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_02.png -------------------------------------------------------------------------------- /assets/images/751_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_03.png -------------------------------------------------------------------------------- /assets/images/751_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_04.png -------------------------------------------------------------------------------- /assets/images/751_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_05.png -------------------------------------------------------------------------------- /assets/images/751_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_06.png -------------------------------------------------------------------------------- /assets/images/751_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_07.png -------------------------------------------------------------------------------- /assets/images/751_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_08.png -------------------------------------------------------------------------------- /assets/images/751_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_09.png -------------------------------------------------------------------------------- /assets/images/751_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/751_10.png -------------------------------------------------------------------------------- /assets/images/752_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_01.png -------------------------------------------------------------------------------- /assets/images/752_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_02.png -------------------------------------------------------------------------------- /assets/images/752_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_03.png -------------------------------------------------------------------------------- /assets/images/752_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_04.png -------------------------------------------------------------------------------- /assets/images/752_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_05.png -------------------------------------------------------------------------------- /assets/images/752_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_06.png -------------------------------------------------------------------------------- /assets/images/752_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_07.png -------------------------------------------------------------------------------- /assets/images/752_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/752_08.png -------------------------------------------------------------------------------- /assets/images/81.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/81.jpg -------------------------------------------------------------------------------- /assets/images/811_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/811_01.png -------------------------------------------------------------------------------- /assets/images/811_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/811_02.png -------------------------------------------------------------------------------- /assets/images/811_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/811_03.jpg -------------------------------------------------------------------------------- /assets/images/811_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/811_04.png -------------------------------------------------------------------------------- /assets/images/82.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/82.jpg -------------------------------------------------------------------------------- /assets/images/821_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/821_01.png -------------------------------------------------------------------------------- /assets/images/824_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/824_01.png -------------------------------------------------------------------------------- /assets/images/824_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/824_02.png -------------------------------------------------------------------------------- /assets/images/824_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/824_03.png -------------------------------------------------------------------------------- /assets/images/824_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/824_04.png -------------------------------------------------------------------------------- /assets/images/824_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/824_05.png -------------------------------------------------------------------------------- /assets/images/83.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/83.jpg -------------------------------------------------------------------------------- /assets/images/832_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/832_01.jpg -------------------------------------------------------------------------------- /assets/images/833_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/833_01.jpg -------------------------------------------------------------------------------- /assets/images/834_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/834_01.png -------------------------------------------------------------------------------- /assets/images/835_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/835_01.jpg -------------------------------------------------------------------------------- /assets/images/84.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/84.jpg -------------------------------------------------------------------------------- /assets/images/backend_mind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/backend_mind.png -------------------------------------------------------------------------------- /assets/images/interview_system_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/interview_system_01.png -------------------------------------------------------------------------------- /assets/images/machine_learning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/images/machine_learning.png -------------------------------------------------------------------------------- /assets/scripts/721_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import mpl_toolkits.axisartist as axisartist 4 | 5 | from matplotlib.transforms import Affine2D 6 | 7 | fig = plt.figure(figsize = (10, 10)) 8 | 9 | ax = axisartist.Subplot(fig, 111) 10 | ax.axis[:].set_visible(False) 11 | 12 | ax.axis["x"] = ax.new_floating_axis(0,0) 13 | ax.axis["x"].set_axisline_style("->", size = 1.0) 14 | ax.axis["x"].label.set_text("$x_1$") 15 | 16 | ax.axis["y"] = ax.new_floating_axis(1,0) 17 | ax.axis["y"].set_axisline_style("->", size = 1.0) 18 | ax.axis["y"].label.set_text("$x_2$") 19 | 20 | ax.axis["x"].set_axis_direction("top") 21 | ax.axis["y"].set_axis_direction("right") 22 | 23 | ax.annotate("$y_1$", xy=(5, 5), xytext=(-5, -5),arrowprops=dict(arrowstyle="->")) 24 | ax.annotate("$y_2$", xy=(-5, 5), xytext=(5, -5),arrowprops=dict(arrowstyle="->")) 25 | 26 | x = np.random.uniform(-6, 6, 200) 27 | y = x + np.random.uniform(-3, 3, 200) 28 | ax.scatter(x, y) 29 | 30 | fig.add_axes(ax) 31 | 32 | plt.xlim(-5, 5) 33 | plt.ylim(-5, 5) 34 | 35 | plt.show() 36 | # plt.tight_layout() 37 | # plt.savefig('../images/721_01.png', transparent = True, bbox_inches = 'tight', pad_inches = 0.25) -------------------------------------------------------------------------------- /assets/scripts/751_01.py: -------------------------------------------------------------------------------- 1 | import random 2 | import matplotlib.pyplot as plt 3 | 4 | x = list(range(1, 11)) 5 | y = [random.randrange(1, 20) for i in range(1, 11)] 6 | 7 | x2 = list(range(1, 11)) 8 | y2 = [random.randrange(1, 10) for i in range(1, 11)] 9 | 10 | plt.plot(x, y, label='First Line') # 为线条指定名称 11 | plt.plot(x2, y2, label='Second Line') 12 | 13 | plt.xlabel('Plot Number') # X轴标签 14 | plt.ylabel('Important var') # Y轴标签 15 | plt.title('Line') # 标题 16 | plt.legend() # 生成默认图例 17 | plt.savefig('../images/751_01.png') 18 | plt.show() 19 | -------------------------------------------------------------------------------- /assets/scripts/751_02.py: -------------------------------------------------------------------------------- 1 | import random 2 | import matplotlib.pyplot as plt 3 | 4 | x = list(range(1, 11, 2)) 5 | y = [random.randrange(1, 20) for i in range(1, 6)] 6 | 7 | x2 = list(range(2, 12, 2)) 8 | y2 = [random.randrange(1, 10) for i in range(1, 6)] 9 | 10 | plt.bar(x, y, label="Example one") 11 | plt.bar(x2, y2, label="Example two", color='g') 12 | 13 | plt.xlabel('Bar Number') 14 | plt.ylabel('Bar Height') 15 | plt.title('Bar') 16 | plt.legend() 17 | 18 | plt.savefig('../images/751_02.png') 19 | plt.show() 20 | 21 | 22 | -------------------------------------------------------------------------------- /assets/scripts/751_03.py: -------------------------------------------------------------------------------- 1 | import random 2 | import matplotlib.pyplot as plt 3 | 4 | x = list(range(1, 11)) 5 | y = [random.randrange(1, 20) for i in range(1, 11)] 6 | 7 | plt.scatter(x, y, label='Scatter', color='k', s=25, marker="o") 8 | 9 | plt.xlabel('x') 10 | plt.ylabel('y') 11 | plt.title('Scatter') 12 | plt.legend() 13 | plt.savefig('../images/751_03.png') 14 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_04.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | slices = [7,2,2,13] 4 | activities = ['sleeping','eating','working','playing'] 5 | cols = ['#d091da', '#6477f0', '#264fc9', '#117510'] 6 | 7 | plt.pie(slices, 8 | labels=activities, 9 | colors=cols, 10 | startangle=130, 11 | shadow= True, 12 | explode=(0,0.1,0,0), 13 | autopct='%1.1f%%') 14 | 15 | plt.title('Pie') 16 | plt.savefig('../images/751_04.png') 17 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_05.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | days = [1, 2, 3, 4, 5] 4 | sleeping = [7, 8, 6, 11, 7] 5 | eating = [2, 3, 4, 3, 2] 6 | working = [7, 8, 7, 2, 2] 7 | playing = [8, 5, 7, 8, 13] 8 | 9 | plt.stackplot(days, 10 | sleeping, eating, working, playing, 11 | labels = ['sleeping', 'eating', 'working', 'playing'], 12 | colors = ['#7cb5ec', '#434348', '#90ed7d', '#f7a35c']) 13 | 14 | plt.xlabel('X') 15 | plt.ylabel('Y') 16 | plt.title('Stack') 17 | plt.legend(loc = 'upper left') 18 | plt.savefig('../images/751_05.png') 19 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_06.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | def f(x,y): # 高度函数 5 | return (1 - x / 2 + x**5 + y**3) * np.exp(-x**2 -y**2) 6 | 7 | n = 256 8 | x = np.linspace(-3, 3, n) 9 | y = np.linspace(-3, 3, n) 10 | X,Y = np.meshgrid(x, y) 11 | 12 | plt.contourf(X, Y, f(X, Y), 8, alpha=.75, cmap = plt.cm.hot) # 进行颜色填充 13 | 14 | C = plt.contour(X, Y, f(X, Y), 8, colors='black', linewidth = 0.5) 15 | 16 | plt.clabel(C, inline=True, fontsize=10) # 添加高度数字 17 | 18 | # 隐藏坐标轴 19 | plt.xticks(()) 20 | plt.yticks(()) 21 | plt.title('Contour') 22 | 23 | plt.savefig('../images/751_06.png') 24 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_07.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from mpl_toolkits.mplot3d import Axes3D 4 | 5 | fig = plt.figure() 6 | ax = Axes3D(fig) 7 | 8 | X = np.arange(-4, 4, 0.25) 9 | Y = np.arange(-4, 4, 0.25) 10 | X, Y = np.meshgrid(X, Y) # XY平面的网格 11 | R = np.sqrt(X ** 2 + Y ** 2) 12 | Z = np.sin(R) 13 | 14 | ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap=plt.get_cmap('rainbow')) # 绘制等高线图,rstride 和 cstride 分别代表 row 和 column 的跨度 15 | ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.get_cmap('rainbow')) # XY 平面的投影 16 | ax.set_zlim(-2, 2) 17 | plt.savefig('../images/751_07.png') 18 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_08.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | x = np.linspace(0, 5 * np.pi, 1000) 5 | y = np.sin(x) 6 | y2 = np.sin(2 * x) 7 | 8 | fig = plt.figure() # 创建一个图像窗口 9 | ax = plt.subplot2grid((1, 1), (0, 0)) # 创建 1 个小图,整个图像窗口分成 1 行 1 列 10 | 11 | ax.plot(x, y, label='First Line') 12 | ax.plot(x, y2, label='Second Line') 13 | 14 | # 填充 15 | ax.fill(x, y, color = "g", alpha = 0.3) # 对函数与坐标轴之间的区域进行填充 16 | ax.fill_between(x, y, y2, facecolor = "b", alpha = 0.5) # 填充两个函数之间的区域 17 | 18 | # 坐标轴设置相关 19 | ax.grid(True, color='g', linestyle='--', linewidth = 1) 20 | ax.xaxis.label.set_color('c') # 设置 x 轴标签颜色 21 | ax.yaxis.label.set_color('r') # 设置 y 轴标签颜色 22 | ax.set_yticks([-1, 0, 1]) # 设置 y 轴刻度与范围 23 | 24 | # 注释和标记相关 25 | x0 = np.pi / 2 26 | y0 = np.sin(x0) 27 | plt.annotate(r'$sin(x)$', xy=(x0, y0), xycoords='data', xytext=(+30, -30), textcoords='offset points', fontsize=12, arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=.2")) # xycoords='data' 基于数据的值来选位置, xytext = (+30, -30) xy 偏差值,textcoords='offset points' 对于标注位置的描述,arrowprops 箭头类型设置 28 | plt.text(0, -1.1, r'$Some\ text.$', fontdict={'size': 12, 'color': 'r'}) # 0, -1.1 选取text的位置 29 | 30 | plt.xlabel('X') 31 | plt.ylabel('Y') 32 | plt.title('Style') 33 | plt.legend(loc = 'upper left') 34 | plt.savefig('../images/751_08.png') 35 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_09.py: -------------------------------------------------------------------------------- 1 | import random 2 | import matplotlib.pyplot as plt 3 | import matplotlib.gridspec as gridspec 4 | 5 | fig = plt.figure(figsize=(9, 16)) 6 | 7 | def create_plots(): 8 | xs = [] 9 | ys = [] 10 | 11 | for x in range(10): 12 | y = random.randrange(10) 13 | xs.append(x) 14 | ys.append(y) 15 | return xs, ys 16 | 17 | plt.subplot(10, 2, 1) 18 | plt.plot(*create_plots()) 19 | 20 | plt.subplot(10, 2, 2) 21 | plt.plot(*create_plots()) 22 | 23 | plt.subplot(10, 2, 3) 24 | plt.plot(*create_plots()) 25 | 26 | plt.subplot(10, 2, 4) 27 | plt.plot(*create_plots()) 28 | 29 | #### 30 | plt.subplot(10, 1, 3) 31 | plt.plot(*create_plots()) 32 | 33 | plt.subplot(10, 3, 10) 34 | plt.plot(*create_plots()) 35 | 36 | plt.subplot(10, 3, 11) 37 | plt.plot(*create_plots()) 38 | 39 | plt.subplot(10, 3, 12) 40 | plt.plot(*create_plots()) 41 | 42 | #### 43 | ax1 = plt.subplot2grid((10, 3), (4, 0), colspan=3) 44 | ax1.plot([1, 2], [1, 2]) 45 | ax1.set_title('ax1_title') 46 | ax2 = plt.subplot2grid((10, 3), (5, 0), colspan=2) 47 | ax3 = plt.subplot2grid((10, 3), (5, 2), rowspan=2) 48 | ax4 = plt.subplot2grid((10, 3), (6, 0)) 49 | ax4.scatter([1, 2], [2, 2]) 50 | ax4.set_xlabel('ax4_x') 51 | ax4.set_ylabel('ax4_y') 52 | ax5 = plt.subplot2grid((10, 3), (6, 1)) 53 | 54 | #### 55 | gs = gridspec.GridSpec(10, 3) 56 | ax6 = plt.subplot(gs[7, :]) 57 | ax7 = plt.subplot(gs[8, :2]) 58 | ax8 = plt.subplot(gs[8:, 2]) 59 | ax9 = plt.subplot(gs[-1, 0]) 60 | ax10 = plt.subplot(gs[-1, -2]) 61 | 62 | plt.savefig('../images/751_09.png') 63 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/751_10.py: -------------------------------------------------------------------------------- 1 | import random 2 | import matplotlib.pyplot as plt 3 | 4 | fig = plt.figure() 5 | x = list(range(1, 11)) 6 | y = [random.randrange(1, 20) for i in range(1, 11)] 7 | 8 | #### 绘制大图区域 9 | left, bottom, width, height = 0.1, 0.1, 0.8, 0.8 10 | ax1 = fig.add_axes([left, bottom, width, height]) # 确定大图左下角的位置以及宽高 11 | ax1.plot(x, y, 'r') 12 | ax1.set_xlabel('x') 13 | ax1.set_ylabel('y') 14 | ax1.set_title('title') 15 | 16 | #### 绘制左上角的小图 17 | ax2 = fig.add_axes([0.2, 0.6, 0.25, 0.25]) 18 | ax2.plot(x, y, 'b') 19 | ax2.set_xlabel('x') 20 | ax2.set_ylabel('y') 21 | ax2.set_title('title inside 1') 22 | 23 | #### 绘制右下角的小图,直接往plt里添加新的坐标系 24 | plt.axes([0.6, 0.2, 0.25, 0.25]) 25 | plt.plot(y[::-1], x, 'g') 26 | plt.xlabel('x') 27 | plt.ylabel('y') 28 | plt.title('title inside 2') 29 | plt.savefig('../images/751_10.png') 30 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib as mpl 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | 6 | def sinplot(flip=1): 7 | x = np.linspace(0, 14, 100) 8 | for i in range(1, 7): 9 | plt.plot(x, np.sin(x + i * .5) * (7 - i) * flip) 10 | 11 | # 对两种画图进行比较 12 | fig = plt.figure() 13 | sns.set() # sns.set_style('dark') 预设的主题,一共有五种,darkgrid,whitegrid,dark,white,和ticks 14 | sinplot() 15 | plt.savefig('../images/752_01.png') 16 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_02.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | 5 | x = np.random.randn(200) 6 | 7 | fig = plt.figure(figsize=(14, 5)) 8 | sns.set_style('darkgrid') 9 | 10 | plt.subplot(1, 2, 1) 11 | sns.distplot(x) # 单变量分布 12 | 13 | plt.subplot(1, 2, 2) 14 | sns.distplot(x, hist = False) # 取消直方图显示 15 | 16 | plt.savefig('../images/752_02.png') 17 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_03.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | mean, cov = [0, 1], [(1, .5), (.5, 1)] 7 | data = np.random.multivariate_normal(mean, cov, 200) 8 | df = pd.DataFrame(data, columns=["x", "y"]) 9 | 10 | sns.set_style('darkgrid') 11 | 12 | sns.jointplot(x="x", y="y", data=df) 13 | # sns.jointplot(x="x", y="y", data=df, kind="kde") # 指定绘制的图像类型,scatter, reg, resid, kde, hex 14 | 15 | plt.savefig('../images/752_03.png') 16 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_04.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | sns.set_style('darkgrid') 7 | 8 | iris = sns.load_dataset("iris") 9 | sns.pairplot(iris); 10 | # 对角线化的是单变量的分布 11 | 12 | plt.savefig('../images/752_04.png') 13 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_05.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | sns.set_style('darkgrid') 7 | 8 | tips = sns.load_dataset("tips") 9 | sns.relplot(x = "total_bill", y = "tip", hue = "smoker", style = "smoker", data = tips) # 第 3 维的数据 smoker 列的数据用 hue="smoker" 和 style = "smoker" 用不同颜色和样式表示该维数据 10 | 11 | plt.savefig('../images/752_05.png') 12 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_06.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | sns.set_style('darkgrid') 7 | 8 | fmri = sns.load_dataset("fmri") 9 | sns.relplot(x = "timepoint", y = "signal", hue = "event", style = "event", kind = "line", sort = True, estimator = np.median, data = fmri) 10 | # sort = True 选择对 x 进行排序 11 | # estimator = np.median(np.max, np.min)为了使得线型更加平滑使用的聚合功能,表示对 x 变量的相同值进行多次测量,取平均,并取可信区间 12 | 13 | plt.savefig('../images/752_06.png') 14 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_07.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | tips = sns.load_dataset("tips") 7 | anscombe = sns.load_dataset("anscombe") 8 | 9 | fig = plt.figure(figsize=(12, 12)) 10 | sns.set_style('darkgrid') 11 | 12 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置显示中文 13 | plt.rcParams['axes.unicode_minus'] = False # 正常显示坐标轴的负号 14 | 15 | plt.subplot(3, 2, 1) 16 | sns.regplot(x = "total_bill", y = "tip", data = tips) # 绘制回归直线和 95% 置信区间 17 | 18 | plt.subplot(3, 2, 2) 19 | plt.text(1, 9, u'regplot()对分类模型适应不好', fontdict = {'size': 12, 'color': 'r'}) 20 | sns.regplot(x = "size", y = "tip", data = tips) 21 | 22 | plt.subplot(3, 2, 3) 23 | sns.regplot(x = "x", y = "y", data = anscombe.query("dataset == 'II'"), ci = None) # 默认 1 阶模型进行拟合 24 | 25 | plt.subplot(3, 2, 4) 26 | sns.regplot(x = "x", y = "y", data = anscombe.query("dataset == 'II'"), ci = None, order = 2) # order = 2 使用 2 阶模型进行拟合 27 | 28 | plt.subplot(3, 2, 5) 29 | sns.regplot(x = "x", y = "y", data = anscombe.query("dataset == 'III'"), ci = None) 30 | 31 | plt.subplot(3, 2, 6) 32 | sns.regplot(x = "x", y = "y", data = anscombe.query("dataset == 'III'"), ci = None, robust = True) # 数据中有明显错误的数据点可以进行删除 33 | 34 | fig.tight_layout() 35 | plt.savefig('../images/752_07.png') 36 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/752_08.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | import seaborn as sns 4 | import pandas as pd 5 | 6 | tips = sns.load_dataset("tips") 7 | titanic = sns.load_dataset("titanic") 8 | 9 | fig, ax = plt.subplots(3, 4, figsize=(16, 12)) 10 | sns.set_style('darkgrid') 11 | 12 | plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置显示中文 13 | plt.rcParams['axes.unicode_minus'] = False # 正常显示坐标轴的负号 14 | 15 | ax[0][0].set_title(u'分类散点图1(存在微小抖动)') 16 | sns.catplot(x="day", y="total_bill", data=tips, ax=ax[0][0]) 17 | 18 | ax[0][1].set_title(u'分类散点图2(jitter = False来控制抖动大小)') 19 | sns.catplot(x="day", y="total_bill", jitter = False,data=tips, ax=ax[0][1]) 20 | 21 | ax[0][2].set_title(u'分类散点图3(kind = "swarm"使得图形分布均匀)') 22 | sns.catplot(x="day", y="total_bill", kind="swarm", data=tips, ax=ax[0][2]) 23 | 24 | ax[0][3].set_title(u'分类散点图4(增加第三维度)') 25 | sns.catplot(x="day", y="total_bill", hue="sex", kind="swarm", data=tips, ax=ax[0][3]) 26 | 27 | ax[1][0].set_title(u'箱线图1') 28 | sns.catplot(x="day", y="total_bill", kind="box", data=tips, ax=ax[1][0]) 29 | 30 | ax[1][1].set_title(u'箱线图2(增加第三维度)') 31 | sns.catplot(x="day", y="total_bill", hue="smoker", kind="box", data=tips, ax=ax[1][1]) 32 | 33 | ax[1][2].set_title(u'小提琴图1(密度图和箱型图的结合)') 34 | sns.catplot(x="day", y="total_bill", hue="time",kind="violin", data=tips, ax=ax[1][2]) 35 | 36 | ax[1][3].set_title(u'小提琴图2(增加第三维度,split = True 拆分小提琴)') 37 | sns.catplot(x="day", y="total_bill", hue="sex",kind="violin", split=True, data=tips, ax=ax[1][3]) 38 | 39 | ax[2][0].set_title(u'条形图1(画出每个类别的平均值,黑色表示估计区间)') 40 | sns.catplot(x="sex", y="survived", hue="class", kind="bar", data=titanic, ax=ax[2][0]) 41 | 42 | ax[2][1].set_title(u'条形图2(统计类别数量)') 43 | sns.catplot(x="deck", kind="count", data=titanic, ax=ax[2][1]) 44 | 45 | ax[2][2].set_title(u'点图1(只画出估计值和区间)') 46 | sns.catplot(x="sex", y="survived", hue="class", kind="point", data=titanic, ax=ax[2][2]) 47 | 48 | ax[2][3].set_title(u'点图2') 49 | sns.catplot(x="class", y="survived", hue="sex", 50 | palette={"male": "g", "female": "m"}, 51 | markers=["^", "o"], linestyles=["-", "--"], 52 | kind="point", data=titanic, ax=ax[2][3]) 53 | 54 | # fig.suptitle('标题', fontsize=20) 55 | fig.tight_layout() 56 | fig.savefig('../images/752_08.png') -------------------------------------------------------------------------------- /assets/scripts/821_01.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import scipy 4 | 5 | fig = plt.figure(figsize=(16, 8)) 6 | plt.rcParams['font.sans-serif'] = ['SimHei'] 7 | plt.rcParams['axes.unicode_minus'] = False 8 | 9 | x = np.linspace(-5, 5) 10 | y1 = 1/(1 + np.exp(- x)) 11 | y2 = np.exp(- x)/(1 + np.exp(- x))**2 12 | 13 | plt.subplot(1, 2, 1) 14 | plt.xlabel('x') 15 | plt.ylabel('F(x)') 16 | plt.title(u'$Logistic$ 分布函数') 17 | plt.plot(x, y1, linewidth = 2.0) 18 | 19 | plt.subplot(1, 2, 2) 20 | plt.xlabel('x') 21 | plt.ylabel('f(x)') 22 | plt.title(u'$Logistic$ 密度函数') 23 | plt.plot(x, y2, linewidth = 2.0) 24 | 25 | plt.savefig('../images/821_01.png') 26 | plt.show() -------------------------------------------------------------------------------- /assets/scripts/821_02.py: -------------------------------------------------------------------------------- 1 | #导入numpy和pandas库 2 | import numpy as np 3 | import pandas as pd 4 | 5 | #解析数据文件 6 | def loadDataSet(filename): 7 | dataSet = pd.read_csv(filename, sep = ',', index_col = '编号') 8 | 9 | #哑变量处理 10 | featureDict = [] 11 | new_dataSet = pd.DataFrame() 12 | for i in range(len(dataSet.columns)): 13 | featureList = dataSet[dataSet.columns[i]] 14 | classSet = list(set(featureList)) 15 | count = 0 16 | for feature in classSet: 17 | d = dict() 18 | if isinstance(feature, float):#判断是否为连续变量 19 | continue 20 | else: 21 | featureList[featureList == feature] = count 22 | d[feature] = count 23 | count += 1 24 | featureDict.append(d) 25 | new_dataSet = pd.concat([new_dataSet, featureList], axis = 1) 26 | 27 | dataMat = [list(new_dataSet.loc[i][:-1]) for i in range(1,len(new_dataSet) + 1)] 28 | labelMat = list(new_dataSet[new_dataSet.columns[-1]]) 29 | return dataMat, labelMat 30 | 31 | filename = '821_02.txt' 32 | dataMat, labelMat = loadDataSet(filename) 33 | 34 | import pprint 35 | pprint.pprint(dataMat) 36 | pprint.pprint(labelMat) 37 | 38 | # 定义Sigmoid函数 39 | def sigmoid(inX): 40 | return 1.0/(1 + np.exp(- inX)) 41 | 42 | # 随机的梯度上升法 43 | def gradAscent(dataMatIn, classLabels, numIter = 150): 44 | # 获得行数和列数,即样本数和特征数 45 | m, n = np.shape(dataMatIn) 46 | # 权重初始化 47 | weights = np.ones(n) 48 | for j in range(numIter): 49 | dataIndex = range(m) 50 | for i in range(m): 51 | alpha = 4/(1.0 + j + i) + 0.01 52 | randIndex = int(np.random.uniform(0, len(dataIndex))) 53 | h = sigmoid(sum(dataMatIn[randIndex] * weights)) 54 | error = classLabels[randIndex] - h 55 | weights = weights + np.dot(alpha * error, dataMatIn[randIndex]) 56 | return weights 57 | 58 | weights = gradAscent(dataMat, labelMat) 59 | print(weights) 60 | 61 | def classfy(testdir, weights): 62 | dataMat, labelMat = loadDataSet(testdir) 63 | dataMat = np.mat(dataMat) 64 | weights = np.mat(weights) 65 | h = sigmoid(dataMat * weights.transpose()) 66 | h = h.tolist() 67 | m = len(h) 68 | error = 0.0 69 | for i in range(m): 70 | if h[i][0] > 0.5: 71 | print(int(labelMat[i]),'is classfied as: 1') 72 | if int(labelMat[i])!=1: 73 | error += 1 74 | print('error') 75 | else: 76 | print(int(labelMat[i]),'is classfied as: 0') 77 | if int(labelMat[i])!=0: 78 | error += 1 79 | print('error') 80 | print('error rate is:','%.4f' %(error/m)) 81 | 82 | print(classfy(filename, weights)) 83 | 84 | #### 通过Scikit - Learn库实现Logistic的分类 85 | 86 | from sklearn.linear_model import LogisticRegression 87 | 88 | X, Y = loadDataSet(filename) 89 | 90 | clf = LogisticRegression() 91 | clf.fit(X, Y) 92 | print(clf) 93 | y_pred = clf.predict(X) 94 | accuracy = np.mean(Y == y_pred) 95 | print('准确度为:', accuracy) -------------------------------------------------------------------------------- /assets/scripts/821_02.txt: -------------------------------------------------------------------------------- 1 | 编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖,好瓜 2 | 1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.460,是 3 | 2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,是 4 | 3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,是 5 | 4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,是 6 | 5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,是 7 | 6,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,是 8 | 7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,是 9 | 8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,是 10 | 9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,否 11 | 10,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,否 12 | 11,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,否 13 | 12,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,否 14 | 13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,否 15 | 14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,否 16 | 15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.360,0.37,否 17 | 16,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.593,0.042,否 18 | 17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.719,0.103,否 -------------------------------------------------------------------------------- /assets/scripts/822_01.dot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/scripts/822_01.dot -------------------------------------------------------------------------------- /assets/scripts/822_01.py: -------------------------------------------------------------------------------- 1 | import pandas as pd # 导入pandas库 2 | import numpy as np # 导入numpy库 3 | 4 | data = pd.read_csv('822_01.txt', ',', index_col='编号') 5 | labels = list(data.columns) 6 | dataSet = np.array(data).tolist() # 处理读入数据为list类型,方便后续计算 7 | 8 | #### 实现根结点信息熵的计算 9 | 10 | from math import log 11 | 12 | def calcShannonEnt(dataSet): 13 | numEntries = len(dataSet)#计算样本集的总样本数量 14 | labelCounts = {}#设置一个空的dict类型变量 15 | for featVec in dataSet:#遍历每行样本集 16 | currentLabel = featVec[-1]#选取样本集最后一列,设置为labelCounts变量的key值 17 | if currentLabel not in labelCounts.keys(): 18 | labelCounts[currentLabel] = 0#key对应value初始化 19 | labelCounts[currentLabel] += 1#累计value,即计算同类别样本数 20 | shannonEnt = 0.0#初始化信息熵 21 | for key in labelCounts: 22 | prob = float(labelCounts[key]) / numEntries#计算频率 23 | shannonEnt -= prob * log(prob, 2)#计算信息熵 24 | return shannonEnt 25 | 26 | print(calcShannonEnt(dataSet)) 27 | 28 | #### 计算不同子属性信息熵 29 | 30 | def splitDataSet(dataSet, axis, value): 31 | #dataSet为样本集 32 | #axis为子属性下标,如0代表子属性“色泽” 33 | #value为上述子属性取值 34 | retDataSet = [] 35 | for featVec in dataSet: 36 | if featVec[axis] == value: 37 | reducedFeatVec = featVec[:axis] 38 | reducedFeatVec.extend(featVec[axis + 1:]) 39 | retDataSet.append(reducedFeatVec) 40 | return retDataSet 41 | 42 | newdataSet1=splitDataSet(dataSet, 0, '青绿')#将为“青绿”的样本集合划分出来 43 | newdataSet2=splitDataSet(dataSet, 0, '乌黑')#将为“青绿”的样本集合划分出来 44 | newdataSet3=splitDataSet(dataSet, 0, '浅白')#将为“青绿”的样本集合划分出来 45 | 46 | print(newdataSet1) 47 | print(newdataSet2) 48 | print(newdataSet3) 49 | 50 | print(calcShannonEnt(newdataSet1)) 51 | print(calcShannonEnt(newdataSet2)) 52 | print(calcShannonEnt(newdataSet3)) 53 | 54 | #### 实现信息增益的计算 55 | 56 | numFeatures = len(dataSet[0]) - 1#计算子属性的数量 57 | baseEntropy = calcShannonEnt(dataSet)#计算根结点信息熵 58 | columns=['色泽','根蒂','敲声','纹理','脐部','触感']#子属性 59 | for i in range(numFeatures): 60 | featList = [example[i] for example in dataSet] 61 | uniqueVals = set(featList) 62 | newEntropy = 0.0 63 | for value in uniqueVals: 64 | #根据子属性及其取值划分样本子集 65 | subDataSet = splitDataSet(dataSet, i, value) 66 | prob = len(subDataSet) / float(len(dataSet))#权值 67 | newEntropy += prob * calcShannonEnt(subDataSet) 68 | print(value,'的信息熵为:',calcShannonEnt(subDataSet))#不同取值的信息熵 69 | infoGain = baseEntropy - newEntropy#计算信息增益 70 | print(columns[i],'信息增益为:',infoGain) 71 | print('----------------------------------') 72 | 73 | #### 基于信息增益选择最优划分属性 74 | def chooseBestFeatureToSplit_Gain(dataSet): 75 | numFeatures = len(dataSet[0]) - 1 76 | baseEntropy = calcShannonEnt(dataSet) 77 | bestInfoGain = 0.0#初始最优信息增益 78 | bestFeature = -1#初始最优子属性 79 | for i in range(numFeatures): 80 | featList = [example[i] for example in dataSet] 81 | uniqueVals = set(featList) 82 | newEntropy = 0.0 83 | for value in uniqueVals: 84 | subDataSet = splitDataSet(dataSet, i, value) 85 | prob = len(subDataSet) / float(len(dataSet)) 86 | newEntropy += prob * calcShannonEnt(subDataSet) 87 | infoGain = baseEntropy - newEntropy 88 | if (infoGain > bestInfoGain):#选择最优子属性 89 | bestInfoGain = infoGain 90 | bestFeature = i 91 | return bestFeature 92 | 93 | print(chooseBestFeatureToSplit_Gain(dataSet)) 94 | 95 | #### 基于信息增益率划分最优子属性 96 | 97 | def chooseBestFeatureToSplit_GainRatio(dataSet): 98 | numFeatures = len(dataSet[0]) - 1 99 | baseEntropy = calcShannonEnt(dataSet) 100 | bestGainRatio = 0.0 101 | bestFeature = -1 102 | for i in range(numFeatures): 103 | featList = [example[i] for example in dataSet] 104 | uniqueVals = set(featList) 105 | newEntropy = 0.0 106 | iv = 0.0#初始化“固有值” 107 | GainRatio = 0.0 108 | for value in uniqueVals: 109 | subDataSet = splitDataSet(dataSet, i, value) 110 | prob = len(subDataSet) / float(len(dataSet)) 111 | iv -= prob * log(prob, 2)#计算每个子属性“固有值” 112 | newEntropy += prob * calcShannonEnt(subDataSet) 113 | infoGain = baseEntropy - newEntropy 114 | GainRatio = infoGain / iv#计算信息增益率 115 | if (GainRatio > bestGainRatio):#选择最优节点 116 | bestGainRatio = GainRatio 117 | bestFeature = i 118 | return bestFeature 119 | 120 | print(chooseBestFeatureToSplit_GainRatio(dataSet)) 121 | 122 | #### 实现了基尼指数的计算 123 | 124 | def calcGini(dataSet): 125 | numEntries = len(dataSet) 126 | labelCounts = {} 127 | for featVec in dataSet: 128 | currentLabel = featVec[-1] 129 | if currentLabel not in labelCounts.keys(): 130 | labelCounts[currentLabel] = 0 131 | labelCounts[currentLabel] += 1 132 | Gini = 1.0 133 | for key in labelCounts: 134 | prob = float(labelCounts[key]) / numEntries 135 | Gini -= prob * prob 136 | return Gini 137 | 138 | print(calcGini(dataSet)) # 根结点基尼指数 139 | 140 | #### 基于基尼指数选择最优划分属性(只能对离散型特征进行处理) 141 | def chooseBestFeatureToSplit_Gini(dataSet): 142 | numFeatures = len(dataSet[0]) - 1 143 | bestGini = 100000.0 144 | bestFeature = -1 145 | for i in range(numFeatures): 146 | featList = [example[i] for example in dataSet] 147 | uniqueVals = set(featList) 148 | newGiniIndex = 0.0 149 | for value in uniqueVals: 150 | subDataSet = splitDataSet(dataSet, i, value) 151 | prob = len(subDataSet) / float(len(dataSet)) 152 | newGiniIndex += prob * calcGini(subDataSet) 153 | if (newGiniIndex < bestGini): 154 | bestGini = newGiniIndex 155 | bestFeature = i 156 | return bestFeature 157 | 158 | print(chooseBestFeatureToSplit_Gini(dataSet)) 159 | 160 | #### 创建树 161 | 162 | import operator 163 | 164 | # 选择下一个根结点 165 | def majorityCnt(classList): 166 | classCount = {} 167 | for vote in classList: 168 | if vote not in classCount.keys(): 169 | classCount[vote] = 0#初始化子属性取值的计数 170 | classCount[vote] += 1#累计 171 | #根据第二个域,即dict的value降序排序 172 | sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse = True) 173 | return sortedClassCount[0][0]#返回子属性取值 174 | 175 | # 创建树 176 | def createTree(dataSet, labels, chooseBestFeatureToSplit): 177 | classList = [example[-1] for example in dataSet]#初始化根结点 178 | if classList.count(classList[0]) == len(classList):#只存在一种取值情况 179 | return classList[0] 180 | if len(dataSet[0]) == 1:#样本集只存在一个样本情况 181 | return majorityCnt(classList) 182 | bestFeat = chooseBestFeatureToSplit(dataSet)#最优划分属性选取 183 | bestFeatLabel = labels[bestFeat] 184 | myTree = {bestFeatLabel: {}}#初始化树 185 | del (labels[bestFeat])#删除已划分属性 186 | featValues = [example[bestFeat] for example in dataSet]#初始化下层根结点 187 | uniqueVals = set(featValues) 188 | for value in uniqueVals: 189 | subLabels = labels[:] 190 | #遍历实现树的创建 191 | myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels, chooseBestFeatureToSplit) 192 | return myTree 193 | 194 | chooseBestFeatureToSplit=chooseBestFeatureToSplit_Gain#根据信息增益创建树 195 | # chooseBestFeatureToSplit=chooseBestFeatureToSplit_GainRatio#根据信息增益率创建树 196 | # chooseBestFeatureToSplit=chooseBestFeatureToSplit_Gini#根据基尼指数创建树 197 | myTree = createTree(dataSet, labels, chooseBestFeatureToSplit) 198 | 199 | print(myTree) 200 | 201 | #### 分类器实现 202 | 203 | # 分类测试器 204 | def classify(inputTree, featLabels, testVec): 205 | firstStr = list(inputTree.keys())[0] 206 | secondDict = inputTree[firstStr]#下一层树 207 | featIndex = featLabels.index(firstStr)#将Labels标签转换为索引 208 | for key in secondDict.keys(): 209 | if testVec[featIndex] == key:#判断是否为与分支节点相同,即向下探索子树 210 | if type(secondDict[key]).__name__ == 'dict': 211 | #递归实现 212 | classLabel = classify(secondDict[key], featLabels, testVec) 213 | else: 214 | classLabel = secondDict[key] 215 | return classLabel#返回判断结果 216 | 217 | print(classify(myTree, ['色泽','根蒂','敲声','纹理','脐部','触感'],['乌黑','稍蜷','沉闷','稍糊','稍凹','硬滑'])) 218 | 219 | #### 保存和加载树 220 | 221 | # 保存树 222 | def storeTree(inputTree,filename): 223 | import pickle 224 | fw = open(filename,'wb+') 225 | pickle.dump(inputTree,fw) 226 | fw.close() 227 | 228 | # 加载树 229 | def grabTree(filename): 230 | import pickle 231 | fr = open(filename,'rb') 232 | return pickle.load(fr) 233 | 234 | storeTree(myTree,'822_01.tree') # 保存到822_02.txt文件中 235 | grabTree('822_01.tree') # 加载保存的决策树 236 | 237 | #### 使用Scikit - Learn库实现决策树 238 | 239 | import numpy as np 240 | import pandas as pd 241 | from sklearn import tree, preprocessing 242 | 243 | '''由于在此库中需要使用数值进行运算,这里需要对样本集进行处理''' 244 | data = pd.read_csv('822_01.txt', ',', index_col='编号') 245 | for col in data.columns: 246 | data[col] = preprocessing.LabelEncoder().fit_transform(data[col]) 247 | labels = np.array(data['好瓜']) 248 | dataSet = np.array(data[data.columns[:-1]]) 249 | 250 | clf = tree.DecisionTreeClassifier(criterion = 'entropy')#参数criterion = 'entropy'为基于信息熵,‘gini’为基于基尼指数 251 | clf.fit(dataSet, labels)#训练模型 252 | print(clf) 253 | 254 | with open("822_01.dot", 'w') as f:#将构建好的决策树保存到tree.dot文件中 255 | f = tree.export_graphviz(clf,feature_names = np.array(data.columns[:-1]), out_file = f) -------------------------------------------------------------------------------- /assets/scripts/822_01.tree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JasonJe/notes/d65983ee4f75ebb5ea3b96d4c9d1455897ef0ab6/assets/scripts/822_01.tree -------------------------------------------------------------------------------- /assets/scripts/822_01.txt: -------------------------------------------------------------------------------- 1 | 编号,色泽,根蒂,敲声,纹理,脐部,触感,好瓜 2 | 1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,是 3 | 2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,是 4 | 3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,是 5 | 4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,是 6 | 5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,是 7 | 6,青绿,稍蜷,浊响,清晰,稍凹,软粘,是 8 | 7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,是 9 | 8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,是 10 | 9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,否 11 | 10,青绿,硬挺,清脆,清晰,平坦,软粘,否 12 | 11,浅白,硬挺,清脆,模糊,平坦,硬滑,否 13 | 12,浅白,蜷缩,浊响,模糊,平坦,软粘,否 14 | 13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,否 15 | 14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,否 16 | 15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,否 17 | 16,浅白,蜷缩,浊响,模糊,平坦,硬滑,否 18 | 17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,否 -------------------------------------------------------------------------------- /assets/scripts/823_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | #获取各个类别条件概率 5 | def get_pred(dataSet, inputSimple): 6 | p0classData = []#初始化类别矩阵 7 | p1classData = [] 8 | classLabels = dataSet[dataSet.columns[-1]]#选取类别列 9 | for i in range(len(dataSet.columns) - 1): 10 | columnLabels = dataSet[dataSet.columns[i]]#特征列 11 | pData = pd.concat([columnLabels, classLabels], axis = 1)#拼接特征列和类别列 12 | classSet = list(set(classLabels)) 13 | for pclass in classSet: 14 | filterClass = pData[pData[pData.columns[-1]] == pclass]#根据类别划分数据集 15 | filterClass = filterClass[pData.columns[-2]] 16 | if isinstance(inputSimple[i], float):#判断是否是连续变量 17 | classVar = np.var(filterClass)#方差 18 | classMean = np.mean(filterClass)#均值 19 | pro_l = 1/(np.sqrt(2*np.pi) * np.sqrt(classVar)) 20 | pro_r = np.exp(-(inputSimple[i] - classMean)**2/(2 * classVar)) 21 | pro = pro_l * pro_r#概率 22 | if pclass == '是': 23 | p0classData.append(pro) 24 | else: 25 | p1classData.append(pro) 26 | else: 27 | classNum = np.count_nonzero(filterClass == inputSimple[i])#计算属于样本特征的数量 28 | pro = (classNum + 1)/(len(filterClass) + len(set(filterClass)))#此处进行了拉普拉斯修正 29 | if pclass == '是': 30 | p0classData.append(pro) 31 | else: 32 | p1classData.append(pro) 33 | return p0classData, p1classData 34 | 35 | filename = '821_02.txt' 36 | dataSet = pd.read_csv(filename, sep = ',', index_col = '编号') 37 | inputSimple = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460] 38 | p0classData, p1classData = get_pred(dataSet, inputSimple) 39 | if np.prod(p0classData) > np.prod(p1classData):#计算条件概率的累积 40 | print('该瓜是好瓜!') 41 | else: 42 | print('烂瓜!') 43 | 44 | testData =[list(dataSet.ix[i][:-1]) for i in range(1,len(dataSet) + 1)]#list化 45 | testLabels = [] 46 | for test in testData: 47 | p0classData, p1classData = get_pred(dataSet, test) 48 | if np.prod(p0classData) > np.prod(p1classData): 49 | testLabels.append('是')#保存测试结果 50 | else: 51 | testLabels.append('否') 52 | accuracy = np.mean(testLabels == dataSet[dataSet.columns[-1]]) 53 | print('模型精度为%f' %accuracy) 54 | 55 | #### Sklearn库简单实现朴素贝叶斯 56 | 57 | import pandas as pd 58 | 59 | filename = '821_02.txt' 60 | dataSet = pd.read_csv(filename, sep = ',', index_col = '编号') 61 | 62 | #哑变量处理 63 | featureDict = [] 64 | new_dataSet = pd.DataFrame() 65 | for i in range(len(dataSet.columns)): 66 | featureList = dataSet[dataSet.columns[i]] 67 | classSet = list(set(featureList)) 68 | count = 0 69 | for feature in classSet: 70 | d = dict() 71 | if isinstance(feature, float):#判断是否为连续变量 72 | continue 73 | else: 74 | featureList[featureList == feature] = count 75 | d[feature] = count 76 | count += 1 77 | featureDict.append(d) 78 | new_dataSet = pd.concat([new_dataSet, featureList], axis = 1) 79 | 80 | import numpy as np 81 | from sklearn.naive_bayes import MultinomialNB 82 | 83 | #设置训练数据集 84 | X = [list(new_dataSet.ix[i][:-1]) for i in range(1,len(new_dataSet) + 1)] 85 | Y = list(new_dataSet[new_dataSet.columns[-1]]) 86 | 87 | clf = MultinomialNB()#分类器 88 | clf.fit(X, Y)#训练 89 | print(clf) 90 | predicted = clf.predict(X) 91 | print('精度为:%f ' %np.mean(predicted == Y)) -------------------------------------------------------------------------------- /assets/scripts/824_01.txt: -------------------------------------------------------------------------------- 1 | 3.542485, 1.977398, -1 2 | 3.018896, 2.556416, -1 3 | 7.551510, -1.580030, 1 4 | 2.114999, -0.004466, -1 5 | 8.127113, 1.274372, 1 6 | 7.108772, -0.986906, 1 7 | 8.610639, 2.046708, 1 8 | 2.326297, 0.265213, -1 9 | 3.634009, 1.730537, -1 10 | 0.341367, -0.894998, -1 11 | 3.125951, 0.293251, -1 12 | 2.123252, -0.783563, -1 13 | 0.887835, -2.797792, -1 14 | 7.139979, -2.329896, 1 15 | 1.696414, -1.212496, -1 16 | 8.117032, 0.623493, 1 17 | 8.497162, -0.266649, 1 18 | 4.658191, 3.507396, -1 19 | 8.197181, 1.545132, 1 20 | 1.208047, 0.213100, -1 21 | 1.928486, -0.321870, -1 22 | 2.175808, -0.014527, -1 23 | 7.886608, 0.461755, 1 24 | 3.223038, -0.552392, -1 25 | 3.628502, 2.190585, -1 26 | 7.407860, -0.121961, 1 27 | 7.286357, 0.251077, 1 28 | 2.301095, -0.533988, -1 29 | -0.232542, -0.547690, -1 30 | 3.457096, -0.082216, -1 31 | 3.023938, -0.057392, -1 32 | 8.015003, 0.885325, 1 33 | 8.991748, 0.923154, 1 34 | 7.916831, -1.781735, 1 35 | 7.616862, -0.217958, 1 36 | 2.450939, 0.744967, -1 37 | 7.270337, -2.507834, 1 38 | 1.749721, -0.961902, -1 39 | 1.803111, -0.176349, -1 40 | 8.804461, 3.044301, 1 41 | 1.231257, -0.568573, -1 42 | 2.074915, 1.410550, -1 43 | -0.743036, -1.736103, -1 44 | 3.536555, 3.964960, -1 45 | 8.410143, 0.025606, 1 46 | 7.382988, -0.478764, 1 47 | 6.960661, -0.245353, 1 48 | 8.234460, 0.701868, 1 49 | 8.168618, -0.903835, 1 50 | 1.534187, -0.622492, -1 51 | 9.229518, 2.066088, 1 52 | 7.886242, 0.191813, 1 53 | 2.893743, -1.643468, -1 54 | 1.870457, -1.040420, -1 55 | 5.286862, -2.358286, 1 56 | 6.080573, 0.418886, 1 57 | 2.544314, 1.714165, -1 58 | 6.016004, -3.753712, 1 59 | 0.926310, -0.564359, -1 60 | 0.870296, -0.109952, -1 61 | 2.369345, 1.375695, -1 62 | 1.363782, -0.254082, -1 63 | 7.279460, -0.189572, 1 64 | 1.896005, 0.515080, -1 65 | 8.102154, -0.603875, 1 66 | 2.529893, 0.662657, -1 67 | 1.963874, -0.365233, -1 68 | 8.132048, 0.785914, 1 69 | 8.245938, 0.372366, 1 70 | 6.543888, 0.433164, 1 71 | -0.236713, -5.766721, -1 72 | 8.112593, 0.295839, 1 73 | 9.803425, 1.495167, 1 74 | 1.497407, -0.552916, -1 75 | 1.336267, -1.632889, -1 76 | 9.205805, -0.586480, 1 77 | 1.966279, -1.840439, -1 78 | 8.398012, 1.584918, 1 79 | 7.239953, -1.764292, 1 80 | 7.556201, 0.241185, 1 81 | 9.015509, 0.345019, 1 82 | 8.266085, -0.230977, 1 83 | 8.545620, 2.788799, 1 84 | 9.295969, 1.346332, 1 85 | 2.404234, 0.570278, -1 86 | 2.037772, 0.021919, -1 87 | 1.727631, -0.453143, -1 88 | 1.979395, -0.050773, -1 89 | 8.092288, -1.372433, 1 90 | 1.667645, 0.239204, -1 91 | 9.854303, 1.365116, 1 92 | 7.921057, -1.327587, 1 93 | 8.500757, 1.492372, 1 94 | 1.339746, -0.291183, -1 95 | 3.107511, 0.758367, -1 96 | 2.609525, 0.902979, -1 97 | 3.263585, 1.367898, -1 98 | 2.912122, -0.202359, -1 99 | 1.731786, 0.589096, -1 100 | 2.387003, 1.573131, -1 -------------------------------------------------------------------------------- /assets/scripts/824_02.txt: -------------------------------------------------------------------------------- 1 | -0.214824,0.662756,-1.000000 2 | -0.061569,-0.091875,1.000000 3 | 0.406933,0.648055,-1.000000 4 | 0.223650,0.130142,1.000000 5 | 0.231317,0.766906,-1.000000 6 | -0.748800,-0.531637,-1.000000 7 | -0.557789,0.375797,-1.000000 8 | 0.207123,-0.019463,1.000000 9 | 0.286462,0.719470,-1.000000 10 | 0.195300,-0.179039,1.000000 11 | -0.152696,-0.153030,1.000000 12 | 0.384471,0.653336,-1.000000 13 | -0.117280,-0.153217,1.000000 14 | -0.238076,0.000583,1.000000 15 | -0.413576,0.145681,1.000000 16 | 0.490767,-0.680029,-1.000000 17 | 0.199894,-0.199381,1.000000 18 | -0.356048,0.537960,-1.000000 19 | -0.392868,-0.125261,1.000000 20 | 0.353588,-0.070617,1.000000 21 | 0.020984,0.925720,-1.000000 22 | -0.475167,-0.346247,-1.000000 23 | 0.074952,0.042783,1.000000 24 | 0.394164,-0.058217,1.000000 25 | 0.663418,0.436525,-1.000000 26 | 0.402158,0.577744,-1.000000 27 | -0.449349,-0.038074,1.000000 28 | 0.619080,-0.088188,-1.000000 29 | 0.268066,-0.071621,1.000000 30 | -0.015165,0.359326,1.000000 31 | 0.539368,-0.374972,-1.000000 32 | -0.319153,0.629673,-1.000000 33 | 0.694424,0.641180,-1.000000 34 | 0.079522,0.193198,1.000000 35 | 0.253289,-0.285861,1.000000 36 | -0.035558,-0.010086,1.000000 37 | -0.403483,0.474466,-1.000000 38 | -0.034312,0.995685,-1.000000 39 | -0.590657,0.438051,-1.000000 40 | -0.098871,-0.023953,1.000000 41 | -0.250001,0.141621,1.000000 42 | -0.012998,0.525985,-1.000000 43 | 0.153738,0.491531,-1.000000 44 | 0.388215,-0.656567,-1.000000 45 | 0.049008,0.013499,1.000000 46 | 0.068286,0.392741,1.000000 47 | 0.747800,-0.066630,-1.000000 48 | 0.004621,-0.042932,1.000000 49 | -0.701600,0.190983,-1.000000 50 | 0.055413,-0.024380,1.000000 51 | 0.035398,-0.333682,1.000000 52 | 0.211795,0.024689,1.000000 53 | -0.045677,0.172907,1.000000 54 | 0.595222,0.209570,-1.000000 55 | 0.229465,0.250409,1.000000 56 | -0.089293,0.068198,1.000000 57 | 0.384300,-0.176570,1.000000 58 | 0.834912,-0.110321,-1.000000 59 | -0.307768,0.503038,-1.000000 60 | -0.777063,-0.348066,-1.000000 61 | 0.017390,0.152441,1.000000 62 | -0.293382,-0.139778,1.000000 63 | -0.203272,0.286855,1.000000 64 | 0.957812,-0.152444,-1.000000 65 | 0.004609,-0.070617,1.000000 66 | -0.755431,0.096711,-1.000000 67 | -0.526487,0.547282,-1.000000 68 | -0.246873,0.833713,-1.000000 69 | 0.185639,-0.066162,1.000000 70 | 0.851934,0.456603,-1.000000 71 | -0.827912,0.117122,-1.000000 72 | 0.233512,-0.106274,1.000000 73 | 0.583671,-0.709033,-1.000000 74 | -0.487023,0.625140,-1.000000 75 | -0.448939,0.176725,1.000000 76 | 0.155907,-0.166371,1.000000 77 | 0.334204,0.381237,-1.000000 78 | 0.081536,-0.106212,1.000000 79 | 0.227222,0.527437,-1.000000 80 | 0.759290,0.330720,-1.000000 81 | 0.204177,-0.023516,1.000000 82 | 0.577939,0.403784,-1.000000 83 | -0.568534,0.442948,-1.000000 84 | -0.011520,0.021165,1.000000 85 | 0.875720,0.422476,-1.000000 86 | 0.297885,-0.632874,-1.000000 87 | -0.015821,0.031226,1.000000 88 | 0.541359,-0.205969,-1.000000 89 | -0.689946,-0.508674,-1.000000 90 | -0.343049,0.841653,-1.000000 91 | 0.523902,-0.436156,-1.000000 92 | 0.249281,-0.711840,-1.000000 93 | 0.193449,0.574598,-1.000000 94 | -0.257542,-0.753885,-1.000000 95 | -0.021605,0.158080,1.000000 96 | 0.601559,-0.727041,-1.000000 97 | -0.791603,0.095651,-1.000000 98 | -0.908298,-0.053376,-1.000000 99 | 0.122020,0.850966,-1.000000 100 | -0.725568,-0.292022,-1.000000 -------------------------------------------------------------------------------- /assets/scripts/824_03.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.svm import SVC 3 | from sklearn.metrics import accuracy_score 4 | 5 | def load_dataset(filepath): 6 | data_mat, label_mat = [], [] 7 | f = open(filepath) 8 | for line in f.readlines(): 9 | line_list = line.split(',') 10 | data_mat.append([float(line_list[0]), float(line_list[1])]) 11 | label_mat.append(float(line_list[2])) 12 | return data_mat, label_mat 13 | 14 | if __name__ == "__main__": 15 | data_mat, label_mat = load_dataset('824_02.txt') 16 | 17 | clf = SVC(C = 200, gamma = 1.3, tol = 0.0001, max_iter = 100) 18 | clf.fit(data_mat, label_mat) 19 | print(clf) 20 | y_train_pred = clf.predict(data_mat) 21 | print(accuracy_score(label_mat, y_train_pred, normalize = False)) 22 | 23 | test_data_mat, test_label_mat = load_dataset('824_03.txt') 24 | y_pred = clf.predict(test_data_mat) 25 | print(accuracy_score(label_mat, y_pred, normalize = False)) 26 | 27 | 28 | -------------------------------------------------------------------------------- /assets/scripts/824_03.txt: -------------------------------------------------------------------------------- 1 | 0.676771, -0.486687, -1.000000 2 | 0.008473, 0.186070, 1.000000 3 | -0.727789, 0.594062, -1.000000 4 | 0.112367, 0.287852, 1.000000 5 | 0.383633, -0.038068, 1.000000 6 | -0.927138, -0.032633, -1.000000 7 | -0.842803, -0.423115, -1.000000 8 | -0.003677, -0.367338, 1.000000 9 | 0.443211, -0.698469, -1.000000 10 | -0.473835, 0.005233, 1.000000 11 | 0.616741, 0.590841, -1.000000 12 | 0.557463, -0.373461, -1.000000 13 | -0.498535, -0.223231, -1.000000 14 | -0.246744, 0.276413, 1.000000 15 | -0.761980, -0.244188, -1.000000 16 | 0.641594, -0.479861, -1.000000 17 | -0.659140, 0.529830, -1.000000 18 | -0.054873, -0.238900, 1.000000 19 | -0.089644, -0.244683, 1.000000 20 | -0.431576, -0.481538, -1.000000 21 | -0.099535, 0.728679, -1.000000 22 | -0.188428, 0.156443, 1.000000 23 | 0.267051, 0.318101, 1.000000 24 | 0.222114, -0.528887, -1.000000 25 | 0.030369, 0.113317, 1.000000 26 | 0.392321, 0.026089, 1.000000 27 | 0.298871, -0.915427, -1.000000 28 | -0.034581, -0.133887, 1.000000 29 | 0.405956, 0.206980, 1.000000 30 | 0.144902, -0.605762, -1.000000 31 | 0.274362, -0.401338, 1.000000 32 | 0.397998, -0.780144, -1.000000 33 | 0.037863, 0.155137, 1.000000 34 | -0.010363, -0.004170, 1.000000 35 | 0.506519, 0.486619, -1.000000 36 | 0.000082, -0.020625, 1.000000 37 | 0.057761, -0.155140, 1.000000 38 | 0.027748, -0.553763, -1.000000 39 | -0.413363, -0.746830, -1.000000 40 | 0.081500, -0.014264, 1.000000 41 | 0.047137, -0.491271, 1.000000 42 | -0.267459, 0.024770, 1.000000 43 | -0.148288, -0.532471, -1.000000 44 | -0.225559, -0.201622, 1.000000 45 | 0.772360, -0.518986, -1.000000 46 | -0.440670, 0.688739, -1.000000 47 | 0.329064, -0.095349, 1.000000 48 | 0.970170, -0.010671, -1.000000 49 | -0.689447, -0.318722, -1.000000 50 | -0.465493, -0.227468, -1.000000 51 | -0.049370, 0.405711, 1.000000 52 | -0.166117, 0.274807, 1.000000 53 | 0.054483, 0.012643, 1.000000 54 | 0.021389, 0.076125, 1.000000 55 | -0.104404, -0.914042, -1.000000 56 | 0.294487, 0.440886, -1.000000 57 | 0.107915, -0.493703, -1.000000 58 | 0.076311, 0.438860, 1.000000 59 | 0.370593, -0.728737, -1.000000 60 | 0.409890, 0.306851, -1.000000 61 | 0.285445, 0.474399, -1.000000 62 | -0.870134, -0.161685, -1.000000 63 | -0.654144, -0.675129, -1.000000 64 | 0.285278, -0.767310, -1.000000 65 | 0.049548, -0.000907, 1.000000 66 | 0.030014, -0.093265, 1.000000 67 | -0.128859, 0.278865, 1.000000 68 | 0.307463, 0.085667, 1.000000 69 | 0.023440, 0.298638, 1.000000 70 | 0.053920, 0.235344, 1.000000 71 | 0.059675, 0.533339, -1.000000 72 | 0.817125, 0.016536, -1.000000 73 | -0.108771, 0.477254, 1.000000 74 | -0.118106, 0.017284, 1.000000 75 | 0.288339, 0.195457, 1.000000 76 | 0.567309, -0.200203, -1.000000 77 | -0.202446, 0.409387, 1.000000 78 | -0.330769, -0.240797, 1.000000 79 | -0.422377, 0.480683, -1.000000 80 | -0.295269, 0.326017, 1.000000 81 | 0.261132, 0.046478, 1.000000 82 | -0.492244, -0.319998, -1.000000 83 | -0.384419, 0.099170, 1.000000 84 | 0.101882, -0.781145, -1.000000 85 | 0.234592, -0.383446, 1.000000 86 | -0.020478, -0.901833, -1.000000 87 | 0.328449, 0.186633, 1.000000 88 | -0.150059, -0.409158, 1.000000 89 | -0.155876, -0.843413, -1.000000 90 | -0.098134, -0.136786, 1.000000 91 | 0.110575, -0.197205, 1.000000 92 | 0.219021, 0.054347, 1.000000 93 | 0.030152, 0.251682, 1.000000 94 | 0.033447, -0.122824, 1.000000 95 | -0.686225, -0.020779, -1.000000 96 | -0.911211, -0.262011, -1.000000 97 | 0.572557, 0.377526, -1.000000 98 | -0.073647, -0.519163, -1.000000 99 | -0.281830, -0.797236, -1.000000 100 | -0.555263, 0.126232, -1.000000 -------------------------------------------------------------------------------- /assets/scripts/832_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from collections import Counter 4 | 5 | def _calc_gini(data_set): 6 | ''' 7 | 计算基尼指数 8 | $gini = 1 - \sum_{k = 1}^{K} p_k^2$ 9 | $k$为类别 10 | ''' 11 | gini = 1 12 | labels = Counter(data_set[:, -1].tolist()) # 标签列 13 | for amount in labels.values(): 14 | prob = amount / data_set.shape[0] # 类别 amount 的概率 15 | gini -= np.power(prob, 2) 16 | return gini 17 | 18 | def _bootstrap(data_set): 19 | ''' 20 | 自助法进行采样 21 | ''' 22 | m = data_set.shape[0] 23 | choosed_feature = np.random.choice(m, m, replace = True) # 可重复采样 24 | train_data = data_set[choosed_feature, :] 25 | return train_data 26 | 27 | def _split(data_set, feature, value): 28 | ''' 29 | 分离数据集,只针对离散型数据集 30 | ''' 31 | left = data_set[np.nonzero(data_set[:, feature] == value)[0], :] 32 | right = data_set[np.nonzero(data_set[:, feature] != value)[0], :] 33 | return left, right 34 | 35 | def _choose_best_feature(data_set, max_features): 36 | ''' 37 | 基于基尼指数选取最优特征 38 | ''' 39 | best_feature = -1 40 | best_value = 0 41 | min_gini = np.inf 42 | split_gini = 0 43 | n = data_set.shape[1] - 1 44 | 45 | rand_feature = np.random.choice(n, max_features, replace = False) # 随机选择特征,最多 max_features 个 46 | 47 | for feature in rand_feature: 48 | values = np.unique(data_set[:, feature]) # 获取该特征的唯一值列表 49 | for value in values: 50 | left, right = _split(data_set, feature, value) # 按照该特征进行划分 51 | split_gini = left.shape[0] / data_set.shape[0] * _calc_gini(left) + right.shape[0] / data_set.shape[0] * _calc_gini(right) 52 | if split_gini < min_gini: 53 | min_gini = split_gini 54 | best_feature = feature 55 | best_value = value 56 | 57 | return best_feature, best_value 58 | 59 | def _create_tree(data_set, max_features): 60 | if data_set.shape[0] == 0: 61 | return 62 | if np.unique(data_set[:, -1]).shape[0] == 1: 63 | return data_set[0, -1] 64 | 65 | best_feature, best_value = _choose_best_feature(data_set, max_features) 66 | 67 | tree = {} 68 | tree['feature'] = best_feature 69 | tree['value'] = best_value 70 | left, right = _split(data_set, best_feature, best_value) 71 | tree['left'] = _create_tree(left, max_features) 72 | tree['right'] = _create_tree(right, max_features) 73 | return tree 74 | 75 | def fit(data_set, n_estimators, max_features): 76 | data_set = np.array(data_set) 77 | rand_forests = [] 78 | for i in range(n_estimators): 79 | train_data = _bootstrap(data_set) 80 | tree = _create_tree(train_data, max_features) 81 | rand_forests.append(tree) 82 | 83 | return rand_forests 84 | 85 | def _predict_by_tree(tree, test_data): 86 | if not isinstance(tree, dict): 87 | return tree 88 | feature = tree['feature'] 89 | value = tree['value'] 90 | if test_data[feature] == value: 91 | return _predict_by_tree(tree['left'], test_data) 92 | else: 93 | return _predict_by_tree(tree['right'], test_data) 94 | 95 | def predict(rand_forests, test_data): 96 | test_data = np.array(test_data) 97 | prediction = [] 98 | for data in test_data: 99 | temp = [] 100 | if isinstance(data, np.ndarray): 101 | for tree in rand_forests: 102 | temp.append(_predict_by_tree(tree, data)) 103 | prediction.append(Counter(temp).most_common(1)[0][0]) 104 | else: 105 | for tree in rand_forests: 106 | temp.append(_predict_by_tree(tree, test_data)) 107 | prediction.append(Counter(temp).most_common(1)[0][0]) 108 | break 109 | return prediction 110 | 111 | if __name__ == "__main__": 112 | from sklearn.datasets import make_classification # 生成200个2分类的样本,特征数量为100 113 | data, lables = make_classification(n_samples = 200, n_features = 100,n_classes = 2) 114 | data_set = np.concatenate((data, lables.reshape(200, 1)), axis=1) 115 | np.random.shuffle(data_set) # 随机打乱数据 116 | 117 | train_data_set = data_set[:150, :] # 选取 75% 数据进行训练 118 | rand_forests = fit(train_data_set, n_estimators = 4, max_features = 20) 119 | prediction = predict(rand_forests, train_data_set[:, : -1]) 120 | correct = [1 if a == b else 0 for a, b in zip(prediction, train_data_set[:, -1])] 121 | print('训练集的准确率:%.3f%%' % (correct.count(1) / 150 * 100)) 122 | 123 | test_data_set = data_set[150:, : -1] # 选取 25% 数据进行测试 124 | test_labels = data_set[150:, -1] 125 | 126 | prediction = predict(rand_forests, test_data_set) 127 | correct = [1 if a == b else 0 for a, b in zip(prediction, test_labels)] 128 | print('测试集的准确率:%.3f%%' % (correct.count(1) / 50 * 100)) 129 | 130 | from sklearn.ensemble import RandomForestClassifier # 使用 Scikit-Learn 内置的随机森林分类模块进行分类 131 | 132 | rf = RandomForestClassifier(max_features = 20, n_estimators = 4) 133 | rf.fit(train_data_set[:, :-1], train_data_set[:, -1]) 134 | print(rf) 135 | 136 | prediction = rf.predict(train_data_set[:, :-1]) 137 | correct = [1 if a == b else 0 for a, b in zip(prediction, train_data_set[:, -1])] 138 | print('训练集的准确率:%.3f%%' % (correct.count(1) / 150 * 100)) 139 | 140 | prediction = rf.predict(test_data_set) 141 | correct = [1 if a == b else 0 for a, b in zip(prediction, test_labels)] 142 | print('测试集的准确率:%.3f%%' % (correct.count(1) / 50 * 100)) -------------------------------------------------------------------------------- /assets/scripts/833_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def load_dataset(filepath): 4 | ''' 5 | 加载数据集,并转化为矩阵 6 | ''' 7 | data_mat, label_mat= [], [] 8 | f = open(filepath) 9 | for line in f.readlines(): 10 | line_list = line.split(',') 11 | data_mat.append([float(i) for i in line_list[:-1]]) 12 | label_mat.append(float(line_list[-1])) 13 | data = np.mat(data_mat) 14 | labels = np.mat(label_mat).T 15 | return data, labels 16 | 17 | def _weak_classifier(data, feature, thresh, thresh_inequal): 18 | ''' 19 | 弱分类器定义,基于阈值对类别进行划分 20 | ''' 21 | result = np.ones((data.shape[0], 1)) 22 | if thresh_inequal == 'lt': 23 | result[data[:, feature] <= thresh] = -1.0 24 | else: 25 | result[data[:, feature] > thresh] = -1.0 26 | return result 27 | 28 | def _find_best_classifier(data, labels, D): 29 | ''' 30 | 找到最优的分类器,选择能在两类中使得误差降到最低的特征 31 | ''' 32 | m, n = data.shape 33 | num_steps = 10.0 34 | best_classifier = {} 35 | best_classification_result = np.mat(np.zeros((m, 1))) 36 | min_error = np.inf # 初始化最小误差为无穷大 37 | 38 | for i in range(n): # 遍历数据集的所有特征 39 | min_feature = data[:, i].min() # 每列特征中的最小值 40 | max_feature = data[:, i].max() # 每列特征中的最大值 41 | step = (max_feature - min_feature) / num_steps # 步长 42 | for j in range(-1, int(num_steps) + 1): # 43 | for ineuqal in ['lt', 'gt']: 44 | thresh = (min_feature + float(j) * step) # 计算阈值 45 | prediction = _weak_classifier(data, i, thresh, ineuqal) # 弱分类器预测的结果 46 | error = np.mat(np.ones((m, 1))) 47 | error[prediction == labels] = 0 # 计算误差 48 | weighted_error = D.T * error # 计算权重 49 | 50 | if weighted_error < min_error: # 更新最小误差 51 | min_error = weighted_error 52 | best_classification_result = prediction.copy() 53 | best_classifier['feature'] = i 54 | best_classifier['thresh'] = thresh 55 | best_classifier['ineq'] = ineuqal 56 | return best_classifier, min_error, best_classification_result 57 | 58 | def adaboost_train(data, labels, max_iter = 40): 59 | weak_classifier = [] 60 | m = data.shape[0] 61 | D = np.mat(np.ones((m ,1)) / m) # 样本权重向量 62 | alpha_classification_result = np.mat(np.zeros((m, 1))) 63 | 64 | for i in range(max_iter): # 迭代 max_iter 次 65 | best_classifier, error, classification_result = _find_best_classifier(data, labels, D) # 获取该次迭代的最优弱分类器 66 | 67 | alpha = float(0.5 * np.log((1.0 - error) / max(error, 1e-16))) 68 | best_classifier['alpha'] = alpha # 计算 alpha,防止分母为零,使用 max(error, 1e-16) 69 | 70 | weak_classifier.append(best_classifier) 71 | 72 | D = np.multiply(D, np.exp(np.multiply(-1 * alpha * labels, classification_result))) 73 | D = D / D.sum() # 更新权重矩阵 74 | 75 | alpha_classification_result += alpha * classification_result # 投票法更新预测结果 76 | e_m = np.multiply(np.sign(alpha_classification_result) != labels, np.ones((m ,1))) # 计算错误个数 77 | 78 | error_rate = e_m.sum() / m # 计算错误率 79 | if error_rate == 0.0: 80 | break 81 | return weak_classifier, alpha_classification_result # 返回每轮迭代的最优弱分类器和对应权重 82 | 83 | def predict(data, weak_classifier): 84 | m = data.shape[0] 85 | alpha_classification_result = np.mat(np.zeros((m, 1))) 86 | for classifier in weak_classifier: 87 | result = _weak_classifier(data, classifier['feature'], classifier['thresh'], classifier['ineq']) 88 | alpha_classification_result += classifier['alpha'] * result # 投票法更新预测结果 89 | return np.sign(alpha_classification_result) 90 | 91 | if __name__ == "__main__": 92 | data, labels = load_dataset('833_01.txt') 93 | weak_classifier, alpha_classification_result = adaboost_train(data, labels) 94 | prediction = predict(data, weak_classifier) 95 | error = np.mat(np.ones((data.shape[0], 1))) 96 | print('训练集的准确率:%.3f%%' % float(100 - error[prediction != labels].sum() / data.shape[0] * 100)) 97 | 98 | test_data, test_labels = load_dataset('833_02.txt') 99 | prediction = predict(test_data, weak_classifier) 100 | error = np.mat(np.ones((test_data.shape[0], 1))) 101 | print('测试集的准确率:%.3f%%' % float(100 - error[prediction != test_labels].sum() / test_data.shape[0] * 100)) 102 | 103 | from sklearn.ensemble import AdaBoostClassifier # 使用 Scikit-Learn 内置的 AdaBoost 分类模块进行分类 104 | 105 | clf = AdaBoostClassifier(n_estimators = 40, random_state = 0) 106 | clf.fit(data, labels) 107 | print(clf) 108 | 109 | print('训练集的准确率:%.3f%%' % (clf.score(data, labels) * 100)) 110 | print('测试集的准确率:%.3f%%' % (clf.score(test_data, test_labels) * 100)) -------------------------------------------------------------------------------- /assets/scripts/834_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from collections import Counter 3 | 4 | from decision_tree import DecisionTreeRegressor 5 | 6 | class GBDT(object): 7 | def __init__(self, n_estimators, learning_rate, min_samples_split, min_impurity, max_depth, is_regression): 8 | ''' 9 | n_estimators, int 树的数量 10 | learning_rate, float 梯度下降的学习率 11 | min_samples_split, int 内部节点需要的最小样本数 12 | min_impurity, float 计算阈值,选取最优划分特征 13 | max_depth, int 每棵子树的最大层数 14 | is_regression, bool 是否是回归问题 15 | ''' 16 | self.n_estimators = n_estimators 17 | self.learning_rate = learning_rate 18 | self.min_samples_split = min_samples_split 19 | self.min_impurity = min_impurity 20 | self.max_depth = max_depth 21 | self.is_regression = is_regression 22 | 23 | self.trees = [] 24 | for i in range(self.n_estimators): 25 | self.trees.append(DecisionTreeRegressor(min_impurity = self.min_impurity, max_depth = self.max_depth, min_samples_split = self.min_samples_split)) 26 | 27 | def fit(self, X, y): 28 | ''' 29 | 预测 30 | 31 | X, numpy.array 样本数组 32 | y, numpy.array 类别数组、 33 | ''' 34 | self.trees[0].fit(X, y) # 第一棵数去拟合数据,获取首个预测值 35 | y_pred = self.trees[0].predict(X) 36 | for i in range(1, self.n_estimators): # 不断拟合,让下一棵树去你和上一棵树的残差,即梯度,或者说是下一棵子树的导数 37 | if self.is_regression: 38 | gradient = - (y - y_pred) 39 | else: 40 | gradient = y - y_pred 41 | self.trees[i].fit(X, gradient) 42 | y_pred -= np.multiply(self.learning_rate, self.trees[i].predict(X)) # 学习率与预测值相乘,防止模型过拟合,对应公式中的系数 $\epsilon$ 43 | 44 | def predict(self, X): 45 | ''' 46 | 预测 47 | 48 | X, numpy.array 测试数据集 49 | ''' 50 | y_pred = self.trees[0].predict(X) 51 | for i in range(1, self.n_estimators): 52 | y_pred -= np.multiply(self.learning_rate, self.trees[i].predict(X)) 53 | 54 | if not self.is_regression: 55 | y_pred = np.exp(y_pred) / np.expand_dims(np.sum(np.exp(y_pred), axis = 1), axis = 1) 56 | y_pred = np.argmax(y_pred, axis = 1) 57 | return y_pred 58 | 59 | class GBDTRegressor(GBDT): 60 | ''' 61 | GBDT回归树 62 | ''' 63 | def __init__(self, n_estimators = 200, learning_rate = 0.5, min_samples_split = 2, min_impurity = 1e-7, max_depth = 4): 64 | ''' 65 | n_estimators, int 树的数量 66 | learning_rate, float 梯度下降的学习率 67 | min_samples_split, int 内部节点需要的最小样本数 68 | min_impurity, float 计算阈值,选取最优划分特征 69 | max_depth, int 每棵子树的最大层数 70 | is_regression, bool 是否是回归问题 71 | ''' 72 | super().__init__(n_estimators = n_estimators, 73 | learning_rate = learning_rate, 74 | min_samples_split = min_samples_split, 75 | min_impurity = min_impurity, 76 | max_depth = max_depth, 77 | is_regression = True) 78 | 79 | class GBDTClassifier(GBDT): 80 | def __init__(self, n_estimators = 200, learning_rate = .5, min_samples_split = 2, min_impurity = 1e-7, max_depth = 2): 81 | ''' 82 | n_estimators, int 树的数量 83 | learning_rate, float 梯度下降的学习率 84 | min_samples_split, int 内部节点需要的最小样本数 85 | min_impurity, float 计算阈值,选取最优划分特征 86 | max_depth, int 每棵子树的最大层数 87 | is_regression, bool 是否是回归问题 88 | ''' 89 | super().__init__(n_estimators = n_estimators, 90 | learning_rate = learning_rate, 91 | min_samples_split = min_samples_split, 92 | min_impurity = min_impurity, 93 | max_depth = max_depth, 94 | is_regression = False) 95 | 96 | def _one_hot(self, x, n_col = None): 97 | ''' 98 | 独热编码 99 | 100 | y, numpy.array 类别数据集 101 | n_col, int 类别数 102 | ''' 103 | if not n_col: 104 | n_col = np.amax(x) + 1 # np.amax 一维数组中的最大值 105 | one_hot = np.zeros((x.shape[0], n_col)) 106 | one_hot[np.arange(x.shape[0]), x] = 1 107 | return one_hot 108 | 109 | def fit(self, X, y): 110 | ''' 111 | 训练模型 112 | 113 | X, numpy.array 样本数组 114 | y, numpy.array 类别数组 115 | ''' 116 | y = np.array([i[0] for i in y.tolist()]) 117 | y = self._one_hot(y) 118 | super().fit(X, y) 119 | 120 | if __name__ == "__main__": 121 | import pandas as pd 122 | import matplotlib.pyplot as plt 123 | from sklearn import tree, preprocessing, datasets 124 | from sklearn.model_selection import train_test_split 125 | from sklearn.preprocessing import StandardScaler 126 | from sklearn.metrics import accuracy_score, mean_squared_error 127 | 128 | # =========== GBDT Classification Tree =========== 129 | X, y = datasets.make_classification(n_samples = 100, n_features = 10, n_classes = 2) # 生成100个2分类的样本,特征数量为100 130 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3) 131 | y_train = y_train.reshape(X_train.shape[0], 1) 132 | y_test = y_test.reshape(X_test.shape[0], 1) 133 | 134 | clf = GBDTClassifier() 135 | clf.fit(X_train, y_train) 136 | y_pred = clf.predict(X_test) 137 | print("Accuracy is: ", accuracy_score(y_test, y_pred)) 138 | 139 | # =========== GBDT Regression Tree =========== 140 | X, y = datasets.make_regression(n_samples=100, n_features=1,n_targets=1, noise=2) 141 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3) 142 | y_train = y_train.reshape(X_train.shape[0], 1) 143 | y_test = y_test.reshape(X_test.shape[0], 1) 144 | 145 | clf = GBDTRegressor() 146 | clf.fit(X_train, y_train) 147 | y_pred = clf.predict(X_test) 148 | 149 | mse = mean_squared_error(y_test, y_pred) 150 | print("Mse is: ", mse) 151 | 152 | cmap = plt.get_cmap('viridis') 153 | test = plt.scatter(366 * X_test, y_test, color = cmap(0.5), s=10) 154 | pred = plt.scatter(366 * X_test, y_pred, color = 'red', s=10) 155 | plt.suptitle("GBDT Regression Tree") 156 | plt.title("Mse: %.2f" % mse, fontsize=10) 157 | plt.xlabel('X') 158 | plt.ylabel('y') 159 | plt.legend((test, pred), ("Test data", "Prediction"), loc='lower right') 160 | plt.show() 161 | -------------------------------------------------------------------------------- /assets/scripts/834_02.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from collections import Counter 3 | 4 | from decision_tree import DecisionTree 5 | 6 | ''' 7 | XGBoost 的简单实现 8 | ''' 9 | 10 | class XGBoostRegressor(DecisionTree): 11 | def __init__(self, impurity = None, leaf_value = None, min_impurity = 1e-7, max_features = None, max_depth = np.inf, min_samples_split = 2): 12 | super().__init__(impurity = impurity, leaf_value = leaf_value) # 继承自决策树 13 | 14 | def _divide(self, y): 15 | ''' 16 | 分割上次迭代预测值与 真实值,为后续服务 17 | 18 | y, numpy.array 真实值和预测值的数组 19 | ''' 20 | col = int(np.shape(y)[1]/2) 21 | y, y_pred = y[:, :col], y[:, col:] 22 | return y, y_pred 23 | 24 | def _gain(self, y, y_pred): 25 | ''' 26 | 计算树结构的分数 Obj 27 | 28 | y, numpy.array 真实值类别数组 29 | y_pred, numpy.array 上次迭代预测值 30 | ''' 31 | nominator = np.power((y - y_pred).sum(), 2) 32 | denonminator = np.ones_like(y).sum() # numpy.ones_like() 返回一个跟输入形状和类型一致的数组 33 | return 0.5 * (nominator / denonminator) 34 | 35 | def _gain_by_taylor(self, y, y1, y2): 36 | ''' 37 | 计算收益 Gain 38 | 39 | y, numpy.array 需要进行计算的数据集 40 | y1, numpy.array 需要进行计算的左子树数据集 41 | y2, numpy.array 需要进行计算的右子树数据集 42 | ''' 43 | y, y_pred = self._divide(y) 44 | y1, y1_pred = self._divide(y1) 45 | y2, y2_pred = self._divide(y2) 46 | 47 | true_gain = self._gain(y1, y1_pred) # 左子树 48 | false_gain = self._gain(y2, y2_pred) # 右子树 49 | gain = self._gain(y, y_pred) 50 | return true_gain + false_gain - gain 51 | 52 | def _approximate_update(self, y): 53 | ''' 54 | 计算近似概率 55 | 56 | y, numpy.array 类别数组 57 | ''' 58 | y, y_pred = self._divide(y) 59 | gradient = np.sum((y - y_pred), axis = 0) 60 | hessian = np.sum(np.ones_like(y), axis = 0) 61 | update_approximation = gradient / hessian 62 | return update_approximation 63 | 64 | def fit(self, X, y): 65 | ''' 66 | 训练 67 | 68 | X, numpy.array 样本数组 69 | y, numpy.array 类别数组 70 | ''' 71 | self.impurity_func = self._gain_by_taylor 72 | self.leaf_value_func = self._approximate_update 73 | 74 | self.n_features = X.shape[1] 75 | data_set = np.concatenate((X, y), axis=1) 76 | self.tree = self._create_tree(data_set, max_features = None) 77 | 78 | class XGBoost(object): 79 | def __init__(self, n_estimators = 200, learning_rate = 0.5, min_samples_split = 2, min_impurity = 1e-7, max_depth = 4): 80 | ''' 81 | n_estimators, int 树的数量 82 | learning_rate, float 梯度下降的学习率 83 | min_samples_split, int 内部节点需要的最小样本数 84 | min_impurity, float 计算阈值,选取最优划分特征 85 | max_depth, int 每棵子树的最大层数 86 | ''' 87 | self.n_estimators = n_estimators 88 | self.learning_rate = learning_rate 89 | self.min_samples_split = min_samples_split 90 | self.min_impurity = min_impurity 91 | self.max_depth = max_depth 92 | 93 | self.trees = [] 94 | for i in range(self.n_estimators): # 进行 n_estimators 次迭代,生成 n_estimators 个决策树 95 | self.trees.append(XGBoostRegressor(min_impurity = self.min_impurity, max_depth = self.max_depth, min_samples_split = self.min_samples_split)) 96 | 97 | def fit(self, X, y): 98 | ''' 99 | 训练,遍历 n_estimators 次 100 | 101 | X, numpy.array 样本数组 102 | y, numpy.array 类别数组 103 | ''' 104 | m = X.shape[0] 105 | y = np.reshape(y, (m, -1)) 106 | y_pred = np.zeros(np.shape(y)) 107 | for i in range(self.n_estimators): 108 | tree = self.trees[i] 109 | y_and_pred = np.concatenate((y, y_pred), axis = 1) 110 | tree.fit(X, y_and_pred) 111 | update_pred = tree.predict(X) 112 | update_pred = np.reshape(update_pred, (m, -1)) 113 | y_pred += update_pred 114 | 115 | def predict(self, X): 116 | ''' 117 | 预测 118 | 119 | X, numpy.array 测试数据集 120 | ''' 121 | y_pred = None 122 | m = X.shape[0] 123 | for tree in self.trees: 124 | update_pred = tree.predict(X) 125 | update_pred = np.reshape(update_pred, (m, -1)) 126 | if y_pred is None: 127 | y_pred = np.zeros_like(update_pred) 128 | y_pred += update_pred 129 | return y_pred 130 | 131 | 132 | if __name__ == "__main__": 133 | import pandas as pd 134 | import matplotlib.pyplot as plt 135 | from sklearn import tree, preprocessing, datasets 136 | from sklearn.model_selection import train_test_split 137 | from sklearn.preprocessing import StandardScaler 138 | from sklearn.metrics import accuracy_score, mean_squared_error 139 | 140 | # =========== XGBoost =========== 141 | X, y = datasets.make_classification(n_samples = 100, n_features = 10, n_classes = 2) # 生成100个2分类的样本,特征数量为100 142 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3) 143 | y_train = y_train.reshape(X_train.shape[0], 1) 144 | y_test = y_test.reshape(X_test.shape[0], 1) 145 | 146 | clf = XGBoost() 147 | clf.fit(X_train, y_train) 148 | y_pred = clf.predict(X_test) 149 | print("Accuracy is: ", accuracy_score(y_test, y_pred)) 150 | 151 | -------------------------------------------------------------------------------- /assets/scripts/834_03.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import xgboost as xgb 4 | import lightgbm as lgb 5 | 6 | from sklearn import datasets 7 | from sklearn.model_selection import train_test_split 8 | from sklearn.metrics import accuracy_score 9 | from sklearn.ensemble import GradientBoostingClassifier 10 | from xgboost import XGBClassifier 11 | 12 | 13 | # 生成二分类使用的数据集 14 | X, y = datasets.make_classification(n_samples = 1000, n_features = 10, n_classes = 2) # 生成100个2分类的样本,特征数量为100 15 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3) 16 | y_train = y_train.reshape(X_train.shape[0], 1) 17 | y_test = y_test.reshape(X_test.shape[0], 1) 18 | 19 | ###### GBDT 训练与测试,基于 sklearn 20 | gbc = GradientBoostingClassifier() # 基于默认参数进行学习 21 | ''' 22 | class sklearn.ensemble.GradientBoostingClassifier( 23 | loss='deviance', 24 | learning_rate=0.1, 25 | n_estimators=100, 26 | subsample=1.0, 27 | criterion='friedman_mse', 28 | min_samples_split=2, 29 | min_samples_leaf=1, 30 | min_weight_fraction_leaf=0.0, 31 | max_depth=3, 32 | min_impurity_decrease=0.0, 33 | min_impurity_split=None, 34 | init=None, 35 | random_state=None, 36 | max_features=None, 37 | verbose=0, 38 | max_leaf_nodes=None, 39 | warm_start=False, 40 | presort='auto' 41 | ) 42 | ''' 43 | gbc.fit(X_train,y_train) 44 | gbc_score = gbc.score(X_test, y_test) 45 | print("GBDT Accuracy is: ", gbc_score) 46 | 47 | ###### 原生实现 XGBoost 48 | dtrain = xgb.DMatrix(X_train, y_train) 49 | dtest = xgb.DMatrix(X_test , y_test) 50 | 51 | params = { 52 | 'booster' : 'gbtree', 53 | 'objective' : 'multi:softmax', # 多分类问题 54 | 'num_class' : 2, # 类别数,与multi softmax并用 55 | 'gamma' : 0.1, # 用于控制是否后剪枝的参数,越大越保守,一般0.1 0.2的样子 56 | 'max_depth' : 12, # 构建树的深度,越大越容易过拟合 57 | 'lambda' : 2, # 控制模型复杂度的权重值的L2 正则化项参数,参数越大,模型越不容易过拟合 58 | 'subsample' : 0.7, # 随机采样训练样本 59 | 'colsample_bytree': 0.1, # 这个参数默认为1,是每个叶子里面h的和至少是多少,对于正负样本不均衡时的0-1分类而言,假设h在0.01附近,min_child_weight为1,意味着叶子节点中最少需要包含100个样本。这个参数非常影响结果,控制叶子节点中二阶导的和的最小值,该参数值越小,越容易过拟合 60 | 'silent' : 0, # 设置成1 则没有运行信息输入,最好是设置成0 61 | 'eta' : 0.007, # 如同学习率 62 | 'seed' : 1000, 63 | 'nthread' : 4, # CPU线程数 64 | 'eval_metric' : 'mlogloss' # 自定义测评函数 65 | } 66 | xgbc = xgb.train( 67 | params = params, # 训练中的参数关键字和对应的值 68 | dtrain = dtrain, # 训练的数据 69 | num_boost_round = 10, # 指提升迭代的个数 70 | evals = [(dtrain, 'train')], # 对训练过程中进行评估列表中的元素 71 | obj = None, # 自定义目的函数 72 | feval = None, # 自定义评估函数 73 | maximize = False, # 是否对评估函数进行最大化 74 | early_stopping_rounds = None, # 停止迭代的参数,假设为100,验证集的误差迭代到一定程度在100次内不能再继续降低,就停止迭代。 75 | evals_result = None, # 存储在 evals 中的元素的评估结果 76 | verbose_eval = True, # 如果为True,则对evals中元素的评估结果会输出在结果中;如果输入数字,假设为5,则每隔5个迭代输出一次。 77 | learning_rates = None, # 每一次提升的学习率的列表 78 | xgb_model = None # 训练之前用于加载的xgb_model 79 | ) 80 | 81 | y_pred = xgbc.predict(xgb.DMatrix(X_test)) 82 | print("XGBoost Accuracy is: ", accuracy_score(y_test, y_pred)) 83 | 84 | ###### sklearn 接口实现 XGBoost 85 | xgbc2 = XGBClassifier( 86 | learning_rate = 0.007, # 学习率 87 | n_estimators = 10, # 树的个数 88 | max_depth = 12, # 树的深度 89 | min_child_weight = 0.1, # 叶子节点最小权重 90 | gamma = 0.1, # 惩罚项中叶子结点个数前的参数 91 | subsample = 0.7, # 随机选择70%样本建立决策树 92 | colsample_btree = 0.1, # 随机选择10%特征建立决策树 93 | objective = 'multi:softmax', # 指定损失函数 94 | scale_pos_weight = 1, # 解决样本个数不平衡的问题 95 | random_state = 1000, # 随机数 96 | num_class = 2 # 类别数 97 | ) 98 | 99 | xgbc2.fit( 100 | X_train, 101 | y_train, 102 | eval_set = [(X_train, y_train)], # 对训练过程中进行评估列表中的元素 103 | eval_metric = "mlogloss", # 自定义测评函数 104 | early_stopping_rounds = 10, # 停止迭代的参数 105 | verbose = True # 是否打印信息 106 | ) 107 | y_pred = xgbc2.predict(X_test) 108 | print("Sklearn XGBoost Accuracy is: ", accuracy_score(y_test, y_pred)) 109 | 110 | 111 | ###### LightGBM 原生实现 112 | lgb_train = lgb.Dataset(X_train, y_train.ravel()) 113 | lgb_eval = lgb.Dataset(X_train, y_train.ravel(), reference = lgb_train) 114 | params = { 115 | 'task' : 'train', 116 | 'boosting_type' : 'gbdt', # 设置提升类型 117 | 'objective' : 'binary', # 目标函数 118 | 'metric' : {'binary_logloss', 'auc'}, # 评估函数 119 | 'num_leaves' : 2, # 叶子节点数 120 | 'max_depth' : 12, # 树的深度 121 | 'learning_rate' : 0.007, # 学习速率 122 | 'feature_fraction': 0.7, # 建树的特征选择比例 123 | 'bagging_fraction': 0.1, # 建树的样本采样比例 124 | 'verbose' : 1 # <0 显示致命的, =0 显示错误 (警告), >0 显示信息 125 | } 126 | lgbc = lgb.train( 127 | params, 128 | lgb_train, 129 | num_boost_round = 10, # 树的个数,迭代次数 130 | valid_sets = [lgb_eval], # 对训练过程中进行评估列表中的元素 131 | early_stopping_rounds = 5 # 停止迭代的参数 132 | ) 133 | y_pred_c = lgbc.predict(X_test, num_iteration = lgbc.best_iteration) 134 | y_pred = [1 if i > 0.5 else 0 for i in y_pred_c] 135 | print("LightGBM Accuracy is: ", accuracy_score(y_test, y_pred)) 136 | -------------------------------------------------------------------------------- /assets/scripts/841_01.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import operator 3 | 4 | filename = '822_01.txt' 5 | def factor2dummy_variable(filename): 6 | fr = open(filename,encoding = 'utf-8')#以utf-8读取文件 7 | dataColumns = fr.readline()#去除首行 8 | arrayLines = fr.readlines()#读取所有行 9 | lines = np.array([line.replace('\n','').split(',') for line in arrayLines]).T#按行指定分隔符,并进行转置 10 | lines = lines[1:,:]#实际使用的数据部分 11 | setFactors = [set(line) for line in lines]#set操作,只保存一种分类的集合 12 | k = 0 13 | for i in setFactors: 14 | dummy_num = 0 15 | line = lines[k] 16 | for j in i: 17 | line[line == j] = dummy_num#哑变量转换 18 | dummy_num += 1 19 | k += 1 20 | lines = lines.T#转置 21 | return lines 22 | 23 | lines = factor2dummy_variable(filename) 24 | dataSet = lines 25 | filename = '841_01.txt' 26 | def data2txt(dataSet,filename): 27 | fw = open(filename,'w',encoding='utf-8')#以utf-8编码写入 28 | for line in dataSet: 29 | for element in line: 30 | fw.write(element) 31 | fw.write(',')#tab键分割符号 32 | fw.write('\n')#换行 33 | fw.close() 34 | 35 | data2txt(dataSet, filename) 36 | 37 | filename = '841_01.txt' 38 | def file2matrix(filename): 39 | fr = open(filename) 40 | arrayOLines = fr.readlines()#读取所有行 41 | numberOfLines = len(arrayOLines)#计算记录数量 42 | numberOfcloumns = len(arrayOLines[0].replace(',\n','').split(',')) - 1#计算变量数量 43 | returnMat = np.zeros((numberOfLines, numberOfcloumns)) 44 | classLabelVector = [] 45 | index = 0 46 | for line in arrayOLines: 47 | line = line.strip()#去除空格 48 | listFromLine = line.split(',')#按tab键分割 49 | returnMat[index, :] = listFromLine[:-2]#得到分类变量数组 50 | classLabelVector.append(int(listFromLine[-2]))#类别变量数组 51 | index += 1 52 | return returnMat, classLabelVector 53 | 54 | def autoNorm(dataSet): 55 | minValue = dataSet.min(0)#得到每列的最小值 56 | maxValue = dataSet.max(0)#每列最大值 57 | ranges = maxValue - minValue#分母 58 | normDataSet = np.zeros(np.shape(dataSet)) 59 | m = dataSet.shape[0]#行数 60 | normDataSet = dataSet - np.tile(minValue, (m,1))#分子 61 | normDataSet = normDataSet/np.tile(ranges, (m,1)) 62 | return normDataSet, ranges, minValue 63 | 64 | def classify0(inX, dataSet, labels, k): 65 | dataSetSize = dataSet.shape[0]#得到行数 66 | diffMat = np.tile(inX, (dataSetSize,1)) - dataSet#计算输入向量inX与训练样本的差 67 | sqDiffMat = diffMat**2#计算差值的平方 68 | sqDistances = sqDiffMat.sum(axis = 1)#距离平方和 69 | distances = sqDistances**0.5#开方得到距离 70 | sortedDistIndicies = distances.argsort()#距离进行排序,得到排序的下标 71 | classCount = {} 72 | for i in range(k):#确定前k个距离中最小元素所属分类 73 | voteIlabel = labels[sortedDistIndicies[i]] 74 | classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1#对出现的label进行计数 75 | sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)#按照计数值进行降序排序 76 | #operator.itemgetter(1)确定一个函数取出classCount中的第一个域的值,即将value取出 77 | return sortedClassCount[0][0]#返回最大的计数值的分类 78 | 79 | dataLines, datalabels = file2matrix('841_01.txt') 80 | i=0 81 | errorCount = 0.0 82 | for line in dataLines: 83 | print('记录%s的原始分类是:%d,划分分类是:%d' %(str(line), datalabels[i], classify0(line, dataLines ,datalabels, 1))) 84 | if (datalabels[i] != classify0(line, dataLines ,datalabels, 1)): 85 | errorCount += 1.0 86 | i += 1 87 | print('错误率为: %f' %(errorCount/float(len(dataLines)))) 88 | 89 | #### Sklearn 实现kNN过程 90 | import numpy as np 91 | from sklearn import neighbors 92 | 93 | data = [] 94 | labels = [] 95 | with open('841_01.txt') as ifile: 96 | for line in ifile: 97 | tokens = line.replace(',\n','').split(',') 98 | data.append([float(tk) for tk in tokens[:-1]]) 99 | labels.append(tokens[-1]) 100 | x = np.array(data) 101 | y = np.array(labels) 102 | 103 | clf = neighbors.KNeighborsClassifier(algorithm = 'kd_tree', n_neighbors = 1) 104 | clf.fit(x,y) 105 | 106 | answer = clf.predict(x) 107 | print('准确率为:%f' % float(np.mean(answer == y)))#正确率 -------------------------------------------------------------------------------- /assets/scripts/841_01.txt: -------------------------------------------------------------------------------- 1 | 2,2,2,2,1,0,0, 2 | 0,2,0,2,1,0,0, 3 | 0,2,2,2,1,0,0, 4 | 2,2,0,2,1,0,0, 5 | 1,2,2,2,1,0,0, 6 | 2,1,2,2,0,1,0, 7 | 0,1,2,0,0,1,0, 8 | 0,1,2,2,0,0,0, 9 | 0,1,0,0,0,0,1, 10 | 2,0,1,2,2,1,1, 11 | 1,0,1,1,2,0,1, 12 | 1,2,2,1,2,1,1, 13 | 2,1,2,0,1,0,1, 14 | 1,1,0,0,1,0,1, 15 | 0,1,2,2,0,1,1, 16 | 1,2,2,1,2,0,1, 17 | 2,2,0,0,0,0,1, 18 | -------------------------------------------------------------------------------- /assets/scripts/svm.py: -------------------------------------------------------------------------------- 1 | import random 2 | import numpy as np 3 | from matplotlib import pyplot as plt 4 | 5 | class SVM(object): 6 | def __init__(self, data_mat, label_mat, C = 1, toler = 0.01, max_iter = 1000, kernel = 'rbf', sigma = None, degree = 3, theta = 0.2): 7 | self.data_mat = np.mat(data_mat) 8 | self.label_mat = np.mat(label_mat).transpose() 9 | 10 | self.C = C 11 | self.toler = toler 12 | self.max_iter = max_iter 13 | 14 | self.kernel = kernel 15 | self.sigma = sigma 16 | self.degree = degree 17 | self.theta = theta 18 | 19 | self.b = 0 20 | self.m, self.n = np.shape(data_mat) 21 | self.alphas = np.mat(np.zeros((self.m, 1))) 22 | self.error_cache = np.mat(np.zeros((self.m,2))) 23 | 24 | self.K = np.mat(np.zeros((self.m, self.m))) 25 | for i in range(self.m): 26 | self.K[:, i] = self._kernel_map(self.data_mat, self.data_mat[i,:]) 27 | 28 | def _kernel_map(self, X, A): 29 | m, n = np.shape(X) 30 | K = np.mat(np.zeros((m, 1))) 31 | 32 | if not self.sigma: 33 | self.sigma = 1 / m 34 | 35 | if self.kernel == 'linear': 36 | K = X * A.T 37 | elif self.kernel == 'rbf': 38 | for j in range(m): 39 | delta_row = X[j, :] - A 40 | K[j] = delta_row * delta_row.T 41 | K = np.exp(K/(-1 * self.sigma ** 2)) 42 | elif self.kernel == 'laplace': 43 | for j in range(m): 44 | delta_row = X[j, :] - A 45 | K[j] = delta_row * delta_row.T 46 | K[j] = np.sqrt(K[j]) 47 | K = np.exp(- K/self.sigma) 48 | elif self.kernel == 'poly': 49 | K = X * A.T 50 | for j in range(m): 51 | K[j] = K[j] ** self.degree 52 | elif self.kernel == 'sigmoid': 53 | K = X * A.T 54 | for j in range(m): 55 | K[j] = np.tanh(self.sigma * K[j] + self.theta) 56 | else: 57 | raise NameError('核函数无法识别') 58 | return K 59 | 60 | def _calc_Ek(self, k): 61 | return float(np.multiply(self.alphas, self.label_mat).T * self.K[:, k] + self.b) - float(self.label_mat[k]) 62 | 63 | def _update_Ek(self, k): 64 | Ek = self._calc_Ek(k) 65 | self.error_cache[k] = [1, Ek] 66 | return self.error_cache 67 | 68 | def _select_rand_j(self, i): 69 | j = i 70 | while (j == i): 71 | j = int(random.uniform(0, self.m)) 72 | return j 73 | 74 | def _select_j(self, i, Ei): 75 | max_k = -1 76 | max_delta_E = 0 77 | Ej = 0 78 | self.error_cache[i] = [1, Ei] 79 | valid_error_cache_list = np.nonzero(self.error_cache[:, 0].A)[0] 80 | if (len(valid_error_cache_list)) > 1: 81 | for k in valid_error_cache_list: 82 | if k == i: 83 | continue 84 | Ek = self._calc_Ek(k) 85 | delta_E = abs(Ei - Ek) 86 | if (delta_E > max_delta_E): 87 | max_k = k 88 | max_delta_E = delta_E 89 | Ej = Ek 90 | return max_k, Ej 91 | else: 92 | j = self._select_rand_j(i) 93 | Ej = self._calc_Ek(j) 94 | return j, Ej 95 | 96 | def _clip_alpha(self, aj, H, L): 97 | if aj > H: 98 | aj = H 99 | if L > aj: 100 | aj = L 101 | return aj 102 | 103 | def _smo_iter(self, i): 104 | Ei = self._calc_Ek(i) 105 | 106 | if ((self.label_mat[i] * Ei < - self.toler) and (self.alphas[i] < self.C)) or ((self.label_mat[i] * Ei > self.toler) and (self.alphas[i] > 0)): 107 | 108 | j, Ej = self._select_j(i, Ei) 109 | 110 | alpha_old_i = self.alphas[i].copy() 111 | alpha_old_j = self.alphas[j].copy() 112 | 113 | if (self.label_mat[i] != self.label_mat[j]): 114 | L = max(0, self.alphas[j] - self.alphas[i]) 115 | H = min(self.C, self.C + self.alphas[j] - self.alphas[i]) 116 | else: 117 | L = max(0, self.alphas[j] + self.alphas[i] - self.C) 118 | H = min(self.C, self.alphas[j] + self.alphas[i]) 119 | if L==H: return 0 120 | 121 | eta = 2.0 * self.K[i, j] - self.K[i, i] - self.K[j, j] 122 | if eta >= 0: return 0 123 | 124 | self.alphas[j] -= self.label_mat[j]*(Ei - Ej)/eta 125 | 126 | self.alphas[j] = self._clip_alpha(self.alphas[j], H, L) 127 | self.error_cache = self._update_Ek(j) 128 | if (abs(self.alphas[j] - alpha_old_j) < 0.00001): return 0 129 | 130 | self.alphas[i] += self.label_mat[j] * self.label_mat[i] * (alpha_old_j - self.alphas[j]) 131 | self.error_cache = self._update_Ek(i) 132 | 133 | b1 = self.b - Ei - self.label_mat[i] * (self.alphas[i] - alpha_old_i) * self.K[i, i] - self.label_mat[j] * (self.alphas[j] - alpha_old_j) * self.K[i, j] 134 | b2 = self.b - Ej - self.label_mat[i] * (self.alphas[i] - alpha_old_i)* self.K[i, j] - self.label_mat[j] * (self.alphas[j] - alpha_old_j) * self.K[j, j] 135 | 136 | if (0 < self.alphas[i]) and (self.C > self.alphas[i]): 137 | self.b = b1 138 | elif (0 < self.alphas[j]) and (self.C > self.alphas[j]): 139 | self.b = b2 140 | else: 141 | self.b = (b1 + b2)/2.0 142 | return 1 143 | else: 144 | return 0 145 | 146 | def train(self): 147 | iter_num = 0 148 | alpha_pairs_changed = 0 149 | entire_set = True 150 | 151 | while (iter_num < self.max_iter) and ((alpha_pairs_changed > 0) or entire_set): # 遍历整个数据集都alpha也没有更新或者超过最大迭代次数,则退出循环 152 | alpha_pairs_changed = 0 153 | if entire_set: 154 | for i in range(self.m): 155 | is_alpha_pairs_changed = self._smo_iter(i) 156 | alpha_pairs_changed += is_alpha_pairs_changed 157 | print("全样本遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num, i, alpha_pairs_changed)) 158 | iter_num += 1 159 | else: 160 | non_bound_Is = np.nonzero((self.alphas.A > 0) * (self.alphas.A < self.C))[0] 161 | for i in non_bound_Is: 162 | is_alpha_pairs_changed = self._smo_iter(i) 163 | alpha_pairs_changed += is_alpha_pairs_changed 164 | print("非边界遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num, i, alpha_pairs_changed)) 165 | iter_num += 1 166 | 167 | if entire_set: 168 | entire_set = False 169 | elif (alpha_pairs_changed == 0): 170 | entire_set = True 171 | print("迭代次数: %d" % iter_num) 172 | 173 | def eval(self): 174 | self._predict() 175 | 176 | error_count = 0 177 | for i in range(self.m): 178 | kernel_eval = self._kernel_map(self.support_vectors, self.data_mat[i, :]) 179 | predict_ = kernel_eval.T * np.multiply(self.label_support_vectors, self.alphas[self.support_vector_index]) + self.b 180 | if np.sign(predict_) != np.sign(self.label_mat[i]): 181 | error_count += 1 182 | return float(error_count) /self.m 183 | 184 | def _predict(self): 185 | self.support_vector_index = np.nonzero(self.alphas.A > 0)[0] 186 | self.support_vectors = self.data_mat[self.support_vector_index] 187 | self.label_support_vectors = self.label_mat[self.support_vector_index] 188 | 189 | def predict(self, data_mat, label_mat): 190 | self._predict() 191 | 192 | m, n = np.shape(data_mat) 193 | error_count = 0 194 | for i in range(m): 195 | kernel_eval = self._kernel_map(self.support_vectors, data_mat[i, :]) 196 | predict_ = kernel_eval.T * np.multiply(self.label_support_vectors, self.alphas[self.support_vector_index]) + self.b 197 | if np.sign(predict_) != np.sign(label_mat[i]): 198 | error_count += 1 199 | return float(error_count) / m 200 | 201 | def load_dataset(filepath): 202 | data_mat, label_mat= [], [] 203 | f = open(filepath) 204 | for line in f.readlines(): 205 | line_list = line.split(',') 206 | data_mat.append([float(line_list[0]), float(line_list[1])]) 207 | label_mat.append(float(line_list[2])) 208 | return data_mat, label_mat 209 | 210 | if __name__ == "__main__": 211 | train_data, train_label = load_dataset('824_02.txt') 212 | svc = SVM(train_data, train_label, C = 200, toler = 0.0001, max_iter = 100, kernel = 'rbf', sigma = 1.3) 213 | svc.train() 214 | 215 | test_data, test_label = load_dataset('824_03.txt') 216 | data_mat = np.mat(test_data) 217 | label_mat = np.mat(test_label).transpose() 218 | 219 | error_count = svc.eval() 220 | print("训练集错误率: %.2f%%" % (error_count * 100)) 221 | 222 | error_count = svc.predict(data_mat, label_mat) 223 | print("测试集错误率: %.2f%%" % (error_count * 100)) -------------------------------------------------------------------------------- /ci.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import requests 4 | import urllib 5 | from git import Repo 6 | 7 | path = './' 8 | r = Repo(path) 9 | api_url = "https://www.yuque.com/api/v2" 10 | 11 | repo_id = os.environ.get('_YUQUE_REPO_ID_') 12 | token = os.environ.get('_YUQUE_TOKEN_') 13 | github_token = os.environ.get('_GITHUB_TOKEN_') 14 | 15 | def get_repos(route): 16 | url = api_url + route 17 | headers = { 18 | 'x-auth-token': token 19 | } 20 | response = requests.request("GET", url, headers=headers) 21 | return response.json().get('data', []) 22 | 23 | def get_repo_detail(id_or_namespace): 24 | url = api_url + '/repos/' + id_or_namespace 25 | headers = { 26 | 'x-auth-token': token 27 | } 28 | response = requests.request("GET", url, headers=headers) 29 | return response.json().get('data', []) 30 | 31 | def get_repo_docs_list(id_or_namespace): 32 | url = api_url + '/repos/' + id_or_namespace + '/docs' 33 | headers = { 34 | 'x-auth-token': token 35 | } 36 | response = requests.request("GET", url, headers=headers) 37 | return response.json().get('data', []) 38 | 39 | def get_doc_detail(id_or_namespace, slug_or_id): 40 | url = api_url + '/repos/' + id_or_namespace + '/docs/' + slug_or_id 41 | headers = { 42 | 'x-auth-token': token 43 | } 44 | response = requests.request("GET", url, headers=headers) 45 | return response.json() 46 | 47 | def create_new_doc(id_or_namespace, title, body, slug = "", public = 0, format_ = "markdown"): 48 | data = "title=%s&slug=%s&public=%s&format=%s&body=%s" % (urllib.parse.quote(title), slug, str(public), format_, urllib.parse.quote(body)) 49 | url = api_url + '/repos/' + id_or_namespace + '/docs' 50 | headers = { 51 | 'x-auth-token': token, 52 | 'content-type': "application/x-www-form-urlencoded", 53 | } 54 | response = requests.request("POST", url, headers=headers, data=data, timeout=5000) 55 | return response.json() 56 | 57 | def update_doc(id_or_namespace, doc_id, title, body, slug = "", public = 0): 58 | data = "title=%s&slug=%s&public=%s&body=%s&format=markdown" % (urllib.parse.quote(title), slug, str(public), urllib.parse.quote(body)) 59 | url = api_url + '/repos/' + id_or_namespace + '/docs/' + doc_id 60 | headers = { 61 | 'x-auth-token': token, 62 | 'content-type': "application/x-www-form-urlencoded", 63 | } 64 | response = requests.request("PUT", url, headers=headers, data=data, timeout=5000) 65 | return response.json() 66 | 67 | def get_repo_toc_data(id_or_namespace): 68 | url = api_url + '/repos/' + id_or_namespace + '/toc' 69 | headers = { 70 | 'x-auth-token': token, 71 | 'content-type': "application/x-www-form-urlencoded", 72 | } 73 | response = requests.request("GET", url, headers=headers) 74 | return response.json() 75 | 76 | def generate_toc_text(toc_data): 77 | template = '{}- [{}]({})\n' 78 | result = '' 79 | for i in toc_data: 80 | result += template.format(" " * (i['depth'] - 1) * 2, i['title'], i['slug'] if i['slug'] != "#" else "") 81 | return result 82 | 83 | def update_repos_toc(id_or_namespace, toc_text): 84 | data = "toc=%s" % (urllib.parse.quote(toc_text)) 85 | url = api_url + '/repos/' + id_or_namespace 86 | headers = { 87 | 'x-auth-token': token, 88 | 'content-type': "application/x-www-form-urlencoded", 89 | } 90 | response = requests.request("PUT", url, headers=headers, data=data, timeout=5000) 91 | return response.json() 92 | 93 | def generate_toc_data(index_file): 94 | with open(index_file, 'r') as f: 95 | index_body = f.read() 96 | doc_list = [] 97 | for i in re.findall('(\d\..*<\/strong><\/summary>|#{4}.*)', index_body): 98 | if '' in i: 99 | doc_list.append({ 100 | 'slug': '#', 101 | 'depth': 1, 102 | 'title': i.replace('', ''), 103 | 'file_path': '' 104 | }) 105 | else: 106 | slug_repx = re.match('\d+\.\d+', i.replace('#### ', '')) 107 | if slug_repx is not None: 108 | file_path_repx = re.match('.*\.md', i) 109 | slug = i.replace('#### ', '')[slug_repx.span()[0] : slug_repx.span()[1]] 110 | doc_list.append({ 111 | 'slug': slug, 112 | 'depth': 2, 113 | 'title': slug + ' ' + i.replace('#### ', '').split('[')[1].split(']')[0].replace('`', '') if '[' in i else i.replace('#### ', '').replace('`', ''), 114 | 'file_path': os.path.join(path, i[file_path_repx.span()[0]: file_path_repx.span()[1]].rsplit('(')[-1]) if file_path_repx is not None else '' 115 | }) 116 | return doc_list[:-1] 117 | 118 | def diff_repo_and_local(docs_list, toc_data): 119 | doc_set = set([i['title'] for i in docs_list]) 120 | toc_set = set([i['title'] for i in toc_data if i['depth'] != 1]) 121 | return toc_set - doc_set 122 | 123 | def list_mkdfiles(): 124 | files = [] 125 | for i in os.walk(path): 126 | if i[2] != []: 127 | files.extend([os.path.join(i[0], j) for j in i[2] if j.rsplit(r'.')[-1].lower() == 'md' and 'README' not in j]) 128 | return files 129 | 130 | def list_commit_hexsha(): 131 | hexshas = [] 132 | for i in r.iter_commits(): 133 | hexshas.append(i.hexsha) 134 | return hexshas 135 | 136 | def diff_commit_files(old_commit_hexsha): 137 | change_files = r.git.diff(old_commit_hexsha, name_only = True) 138 | return [os.path.join(path, i) for i in change_files.split('\n') if i.rsplit(r'.')[-1].lower() == 'md'] 139 | 140 | if __name__ == "__main__": 141 | index_file = os.path.join(path, 'README.md') 142 | toc_data = generate_toc_data(index_file) 143 | toc_text = generate_toc_text(toc_data) 144 | resp = update_repos_toc(repo_id, toc_text) 145 | print('Update toc: ', resp) 146 | image_base_url = 'https://raw.githubusercontent.com/' 147 | for url in r.remote().urls: 148 | image_base_url = url.replace('.git', '').replace('https://github.com/', image_base_url) 149 | 150 | docs_list = get_repo_docs_list(repo_id) 151 | diff_docs = diff_repo_and_local(docs_list, toc_data) 152 | print('Diff doc between repo and local is: ', diff_docs) 153 | 154 | for i in toc_data: 155 | if i['title'] in diff_docs and i['file_path'] != '': 156 | body = '' 157 | with open(i['file_path'], 'r') as f: 158 | body = f.read() 159 | body = body.replace('../assets/images/', image_base_url + '/master/assets/images/') 160 | body = body.replace("## " + i['title'] + "\n", "") 161 | resp = create_new_doc(repo_id, i['title'], body, slug = i['slug'], public = 1) 162 | print('Create new doc response: ', i['title']) 163 | 164 | hexshas = list_commit_hexsha() 165 | repo_hexsha = hexshas[1] 166 | update_files = diff_commit_files(repo_hexsha) 167 | print("Update files: ", update_files) 168 | 169 | update_files_slug = [] 170 | for i in toc_data: 171 | if i['file_path'] in update_files: 172 | update_files_slug.append(i) 173 | 174 | for i in update_files_slug: 175 | doc_detail = get_doc_detail(repo_id, i['slug']) 176 | doc_id = str(doc_detail['data']['id']) 177 | body = '' 178 | with open(i['file_path'], 'r') as f: 179 | body = f.read() 180 | body = body.replace('../assets/images/', image_base_url + '/master/assets/images/') 181 | body = body.replace("## " + i['title'] + "\n", "") 182 | resp = update_doc(repo_id, doc_id, i['title'], body, slug = i['slug'], public = 1) 183 | print('Update doc: ', i['title']) 184 | -------------------------------------------------------------------------------- /分布式/README.md: -------------------------------------------------------------------------------- 1 | # 6. 分布式 2 | 3 | ## 6.1 [分布式概述](分布式概述.md) 4 | 5 | ### 6.1.1 [什么是分布式](分布式概述.md#611-什么是分布式) 6 | 7 | ### 6.1.2 [分布式发展历程](分布式概述.md#612-分布式发展历程) 8 | 9 | ### 6.1.3 [分布式系统指标](分布式概述.md#613-分布式系统指标) 10 | 11 | ## 6.2 [分布式协同与同步](分布式协同与同步.md) 12 | 13 | ### 6.2.1 [分布式互斥](分布式协同与同步.md#621-分布式互斥) 14 | 15 | ### 6.2.2 [分布式选举](分布式协同与同步.md#622-分布式选举) 16 | 17 | ### 6.2.3 [分布式共识](分布式协同与同步.md#623-分布式共识) 18 | 19 | ### 6.2.4 [分布式事务](分布式协同与同步.md#624-分布式事务) 20 | 21 | ### 6.2.5 [分布式锁](分布式协同与同步.md#625-分布式锁) 22 | 23 | ## 6.3 [分布式资源管理和负载调度](分布式资源管理和负载调度.md) 24 | 25 | ### 6.3.1 [分布式体系结构](分布式资源管理和负载调度.md#631-分布式体系结构) 26 | 27 | ### 6.3.2 [分布式调度架构](分布式资源管理和负载调度.md#632-分布式调度架构) 28 | 29 | ## 6.4 [分布式计算模式](分布式计算模式.md) 30 | 31 | ### 6.4.1 [分而治之计算模式](分布式计算模式.md#641-分而治之计算模式) 32 | 33 | ### 6.4.2 [流计算模式](分布式计算模式.md#642-流计算模式) 34 | 35 | ### 6.4.3 [`Actor` 计算模式](分布式计算模式.md#643-actor计算模式) 36 | 37 | ### 6.4.4 [流水线计算模式](分布式计算模式.md#644-流水线计算模式) 38 | 39 | ## 6.5 [分布式通信](分布式通信.md) 40 | 41 | ### 6.5.1 [远程调用](分布式通信.md#651-远程调用) 42 | 43 | ### 6.5.2 [发布订阅](分布式通信.md#652-发布订阅) 44 | 45 | ### 6.5.3 [消息队列](分布式通信.md#653-消息队列) 46 | 47 | ## 6.6 [分布式存储](分布式存储.md) 48 | 49 | ### 6.6.1 [`CAP`理论](分布式存储.md#661-cap理论) 50 | 51 | ### 6.6.2 [数据的生产和消费](分布式存储.md#662-数据的生产和消费) 52 | 53 | ### 6.6.3 [数据分片和数据复制](分布式存储.md#663-数据分片和数据复制) 54 | 55 | ### 6.6.4 [分布式缓存](分布式存储.md#664-分布式缓存) 56 | 57 | ## 6.7 [分布式高可靠](分布式高可靠.md) 58 | 59 | ### 6.7.1 [负载均衡](分布式高可靠.md#671-负载均衡) 60 | 61 | ### 6.7.2 [流量控制](分布式高可靠.md#672-流量控制) 62 | 63 | ### 6.7.3 [故障隔离](分布式高可靠.md#673-故障隔离) -------------------------------------------------------------------------------- /分布式/分布式概述.md: -------------------------------------------------------------------------------- 1 | ## 6.1 分布式概述 2 | 3 | >date: 2019-12-09 4 | 5 | ![](../assets/images/61.jpg) 6 | 7 | ### 6.1.1 什么是分布式 8 | 9 | 分布式就是将相同或相关的程序运行在多台服务器上,从而实现特定目标的一种计算方式。 10 | 11 | 分布式系统是作为单个完整服务展现在终端用户面前的一组协同工作服务器。组中的服务器共享状态、同步操作,并且任意某个服务器独立故障时都不会影响整个系统的正常运行。 12 | 13 | * **分布式**和**集群**的区别: 14 | 15 | **分布式**:将一个业务拆分成不同的子业务,分布在不同的服务器上执行; 16 | 17 | **集群**:多台服务器集中在一起,实现同一业务或功能。 18 | 19 | ### 6.1.2 分布式发展历程 20 | 21 | 1. 单机模式 22 | 23 | 所有的应用程序和数据均部署在一台服务器上,由一台服务器完成所有的处理。 24 | 25 | **缺点**:所有资源共用一台服务器,性能受限,存在单点失效问题。 26 | 27 | 2. 数据并行或数据分布式 28 | 29 | 为了解决单台服务器存在性能和可用性的问题,出现了数据并行的模式,其可以看做分成两个阶段进行。 30 | 31 | a. 应用和数据的分离,分别部署在不同的服务器上; 32 | 33 | b. 对数据进行拆分,将同一类型的数据拆分到两个或更多的数据库中,应用针对不同的功能去相应的数据库上取用数据,不同任务针对不同类型的数据就能实现并行处理。 34 | 35 | 多台服务器并行处理多个任务,解决单机模式的性能瓶颈。 36 | 37 | **需要考虑的问题:** 38 | 39 | * 部署在不同服务器上的相同的应用,需要考虑均衡接收任务并处理的问题; 40 | 41 | * 数据库的读写频繁时候,数据库的`IO`是瓶颈,数据库读写分离,需要考虑**读**和**写**之间的效率平衡,同时要考虑数据同步的一致性问题; 42 | 43 | * 热点数据的频繁访问,会导致数据库的压力增大,需要考虑使用缓存机制来减小压力并提升查询效率。 44 | 45 | **缺点**:针对上面需要考虑的问题,如果单个任务执行时间过长,需要较多资源时,针对提高执行效率和性能问题,这个模式无法解决。 46 | 47 | 3. 任务并行或任务分布式 48 | 49 | 针对数据并行时候,无法提高单个任务的执行性能问题,出现了任务并行模式。 50 | 51 | 其实现原理就是将单个复杂任务拆分成多个子任务,将子任务分散到不同的服务器上并行执行,只要一个复杂任务中的任意子任务的执行时间变短了,那么这个业务的整体执行时间也就变短了。 52 | 53 | **缺点**:这种模式自然能带来更好的性能、扩展性、可维护性,但是如何设计任务的并行执行,不仅关乎任务并行的设计,还关乎如何对一些大型业务的拆分。 54 | 55 | ### 6.1.3 分布式系统指标 56 | 57 | 分布式的目的是使用更多的服务器,处理更多的数据和更复杂的任务,所以**性能**、**资源**、**可用性**和**可扩展性**是验证一个分布式系统能否达到上述要求的重要指标。 58 | 59 | * **性能** 60 | 61 | **性能**主要用于衡量一个系统处理各种任务的能力。 62 | 63 | 常见的性能指标,包括**吞吐量**(`Throughput`)、**响应时间**(`Response Time`)和**完成时间**(`Turnaround Time`)。 64 | 65 | - * **吞吐量**:系统在一定时间内可以处理的任务数。常见的吞吐量指标有 `QPS`(`Queries Per Second`)、`TPS`(`Transactions Per Second`)和 `BPS`(`Bits Per Second`)。 66 | 67 | `QPS`:查询数每秒,用于衡量一个系统每秒处理的查询数。这个指标通常用于读操作,越高说明对读操作的支持越好。如果应用主要是读操作,那么需要重点考虑如何提高 `QPS`,来支持高频的读操作。 68 | 69 | `TPS`:事务数每秒,用于衡量一个系统每秒处理的事务数。这个指标通常对应于写操作,越高说明对写操作的支持越好。如果应用主要是写操作,那么需要重点考虑如何提高 `TPS`,来支持高频写操作。 70 | 71 | `BPS`:比特数每秒,用于衡量一个系统每秒处理的数据量。不同的事务之间的处理的数据量大小不同,针对这种处理数据较多的系统,不能简单地按照请求数或事务数来衡量其性能,这种情况下,`BPS` 更能客观地反应系统的吞吐量。 72 | 73 | - * **响应时间**:指系统响应一个请求或事务所需花费的时间。直接影响到用户的体验,对一些时延敏感的业务很重要。 74 | 75 | - * **完成时间**:系统真正完成一个请求或处理需要花费的时间。任务并行模式出现的其中一个目的,就是缩短整个任务的完成时间。当需要计算海量数据或处理大规模任务时,这个指标很重要。 76 | 77 | 78 | * **资源占用** 79 | 80 | **资源占用**指的是一个系统提供正常能力需要占用的硬件资源。 81 | 82 | 一个系统在没有任何负载时的资源占用,叫做**空载资源占用**,体现了这个系统自身的资源占用情况。对于同样的功能,空载资源占用越少,说明系统设计越优秀,负载处理事务时候的资源也越足。 83 | 84 | 一个系统满额负载时的资源占用,叫做**满载资源占用**,体现了这个系统全力运行时占用资源的情况,也体现了系统的处理能力。同样的硬件配置上,运行的业务越多,资源占用越少,说明这个系统设计得越好。 85 | 86 | * **可用性** 87 | 88 | **可用性**通常指的是系统在面对各种异常时可以正确提供服务的能力。可用性是分布式系统的一项重要指标,衡量了系统的鲁棒性,是系统容错能力的体现。 89 | 90 | 系统的可用性可以用**系统停止服务的时间与总的时间之比衡量**,还可以用**某功能的失败次数与总的请求次数之比来衡量**。 91 | 92 | * **可扩展性** 93 | 94 | **可扩展性**指的是分布式系统通过扩展集群机器规模提高系统性能 (吞吐、响应时间、 完成时间)、存储容量、计算能力的特性,是分布式系统的特有性质。 95 | 96 | 当任务的需求随着具体业务不断提高时,除了升级系统的性能做**垂直/纵向扩展**外,另一个做法就是通过增加服务器的方式去**水平/横向扩展**系统规模。 97 | 98 | 好的分布式系统总在追求**线性扩展性**,也就是说系统的某一指标可以随着集群中的机器数量呈线性增长。 99 | 100 | 衡量系统可扩展性的常见指标是**加速比**(`Speedup`),也就是一个系统进行扩展后相对扩展前的性能提升。 -------------------------------------------------------------------------------- /分布式/分布式计算模式.md: -------------------------------------------------------------------------------- 1 | ## 6.4 分布式计算模式 2 | 3 | >date: 2019-12-16 4 | 5 | ![](../assets/images/64.jpg) 6 | 7 | ### 6.4.1 分而治之计算模式 8 | 9 | **分而治之**就是将一个复杂、难以直接解决的大问题,分割成一些规模较小的、可以比较简单的问题或可以直接求解的子问题,这些子问题之间相互独立并且与原问题形式相同,递归地求解这些子问题,然后将子问题的解合并得到原问题的解。 10 | 11 | **适合的问题**: 12 | 13 | - * 问题规模比较大或复杂,且问题可以分解为几个规模较小的、简单的同类型问题进行求解; 14 | 15 | - * 子问题之间相互独立,不包含公共子问题; 16 | 17 | - * 子问题的解可以合并得到原问题的解。 18 | 19 | **核心步骤**: 20 | 21 | - 1) **分解原问题**:将原问题分解为若干个规模较小,相互独立,且与原问题形式相同的子问题; 22 | 23 | - 2) **求解子问题**:若子问题的规模较小且容易被解决则直接求解,否则递归地求解各个子问题; 24 | 25 | - 3) **合并解**:将各个子问题的解合并为原问题的解。 26 | 27 | * **`MapReduce` 模型** 28 | 29 | - * 抽象模型 30 | 31 | `MapReduce` 分为 `Map` 和 `Reduce` 两个核心阶段,其中 `Map` 对应**分**,即将复杂任务分解为若干个简单的任务;`Reduce` 对应着**合**,即将 `Map` 阶段的结果汇总。 32 | 33 | ![MapReduce 模型](../assets/images/641_01.png) 34 | 35 | - * 工作原理 36 | 37 | ![MapReduce 工作原理](../assets/images/641_02.png) 38 | 39 | - 1) `Master`,也就是 `MRAppMaster`,该模块负责分配任务,协调任务的运行,并为 `Mapper` 分配 `map()` 函数操作、为 `Reducer` 分配 `reduce()` 函数操作; 40 | 41 | - 2) `Mapper worker`,负责 `Map` 函数功能,即负责执行子任务。 42 | 43 | - 3) `Reducer worker`,负责 `Reduce` 函数功能,即负责汇总各个子任务的结果。 44 | 45 | - * 工作流程 46 | 47 | ![MapReduce 工作流程](../assets/images/641_03.png) 48 | 49 | - 1) `step1`:`User Program` 将任务下发到 `MRAppMaster` 中。然后,`MRAppMaster` 执行任务拆分步骤,把 `User Program` 下发的任务划分成 `M` 个子任务(`M` 是用户自定义的数值); 50 | 51 | - 2) `step2`:`MRAppMaster` 分别为 `Mapper` 和 `Reducer` 分配相应的 `Map` 和 `Reduce` 作业。`Map` 和 `Reduce` 作业的数量就是划分后的子任务数量; 52 | 53 | - 3) `step3`:被分配了 `Map` 作业的 `Worker`,开始读取子任务的输入数据,并从输入数据中抽取出 `` 键值对,每一个键值对都作为参数传递给 `map()` 函数; 54 | 55 | - 4) `step4`:`map()` 函数的输出结果存储在环形缓冲区 `kvBuffer` 中,这些 `Map` 结果会被定期写入本地磁盘中,被存储在 `R` 个不同的磁盘区。这里的 `R` 表示 `Reduce` 作业的数量,也是由用户定义的。此外,每个 `Map` 结果的存储位置都会上报给 `MRAppMaster`。 56 | 57 | - 5) `step5`:`MRAppMaster` 通知 `Reducer` 它负责的作业在哪一个分区,`Reducer` 远程读取相应的 `Map` 结果,即中间键值对。当 `Reducer` 把它负责的所有中间键值对都读过来后,首先根据键值对的 `key` 值对中间键值对进行排序,将相同 `key` 值的键值对聚集在一起,从而有利于 `Reducer` 对 `Map` 结果进行统计。 58 | 59 | - 6) `step6`:`Reducer` 遍历排序后的中间键值对,将具有相同 `key` 值的键值对合并,并将统计结果作为输出文件存入负责的分区中。 60 | 61 | 整个 `MapReduce` 的工作流程主要可以概括为 `5` 个阶段,即:`Input`(输入)、`Splitting`(拆分)、`Mapping`(映射)、`Reducing`(化简)以及 `Final Result`(输出)。 62 | 63 | **特点**:可以进行大规模扩展,适合大型计算机集群;拆分后的任务,可以扩多个计算机执行,并且各个小任务之间不会相互通信。 64 | 65 | ### 6.4.2 流计算模式 66 | 67 | **流数据**:如流水般涌现的,需要实时处理的数据。流数据具有以下的特点: 68 | 69 | 1) 数据如流水般持续,快速地到达; 70 | 71 | 2) 海量数据规模,数据量可达 `TB` 级甚至 `PB` 级别; 72 | 73 | 3) 对实时性要求高,随着时间流逝,数据的价值会答复降低; 74 | 75 | 4) 数据顺序无法保证,系统无法控制将要处理的数据元素的顺序。 76 | 77 | 在分布式领域,处理流数据的计算模式叫做**流计算**,也叫** `Stream` **。 78 | 79 | 流计算一般用于处理数据密集型的应用。 80 | 81 | * **`Stream` 工作原理** 82 | 83 | 流计算强调实时性,数据一旦产生就会被立即处理,当一条数据被处理完成后,会序列化存储到缓存中,然后立即通过网络传输到下一个节点,由下一个节点继续处理。 84 | 85 | 流计算中不会存储任何数据,属于持续性、低时延、事件驱动型的计算作业。 86 | 87 | 流计算的过程一般包括 `3` 个步骤: 88 | 89 | ![流计算步骤](../assets/images/642_01.png) 90 | 91 | - 1) **提交流式计算作业**:常驻服务进行流式计算作业,由于收集的是同一类型的数据,执行相同的工作,且不提供数据存储服务,所以流式计算的处理逻辑不可以更改,并且之前计算完成的数据无法重新再次计算; 92 | 93 | - 2) **加载流式数据进行计算**:作业一旦启动,就一直处于等待时间触发的状态,一有数进入流式数据存储,系统立即执行计算逻辑并迅速得到结果。 94 | 95 | - 3) **持续输出计算结果**:流式计算不提供流式数据的存储服务,数据是持续流动的,在计算完后就丢弃。对数据处理有较高的实时性要求,所以需要流计算框架必须是低延迟、可扩展、高可靠的。 96 | 97 | ### 6.4.3 `Actor` 计算模式 98 | 99 | * **`Actor` 模型** 100 | 101 | 一种分布式并行计算模型,规定了 `Actor` 内部的计算逻辑和多个 `Actor` 之间的通信规则。多个 `Actor` 之间通过消息进行通信,`Actor` 接收到消息后,根据消息去执行计算操作,`Actor` 相当于系统的一个组件,都是基本的计算单元。 102 | 103 | `Actor` 通过消息通信,采用异步的方式,能够克服类似 `OOP` 中同步访问时,出现的死锁、竞争等问题,适合高并发的分布式系统。 104 | 105 | * **`Actor` 计算模型** 106 | 107 | ![Actor 计算模型](../assets/images/643_01.png) 108 | 109 | `Actor` 模型的三要素是**状态、行为、消息**,即 `Actor` 模型 = (状态 + 行为) + 消息。 110 | 111 | - * **状态(`State`)**:`Actor` 的状态指的是 `Actor` 组件本身的信息,相当于 `OOP` 对象中的属性。`Actor` 的状态会受 `Actor` 自身行为的影响,且只能被自己修改。 112 | 113 | - * **行为(`Behavior`)**:`Actor` 的行为指的是 `Actor` 的计算处理操作,相当于 `OOP` 对象中的成员函数。`Actor` 之间不能直接调用其他 `Actor` 的计算逻辑。`Actor` 只有收到消息才会触发自身的计算行为。 114 | 115 | - * **消息(`Mail`)**:`Actor` 的消息以邮件形式在多个 `Actor` 之间通信传递,每个 `Actor` 会有一个自己的邮箱(`MailBox`),用于接收来自其他 `Actor` 的消息,因此 `Actor` 模型中的消息也称为**邮件**。一般情况下,对于邮箱里面的消息,`Actor` 是按照消息达到的**先后顺序(`FIFO`)**进行读取和处理的。 116 | 117 | * **`Actor` 关键特征** 118 | 119 | - * **实现了更高级的抽象**:`Actor` 封装了状态和行为,`Actor` 之间是异步通信的,多个 `Actor` 可以独立运行且不会被干扰,解决了 `OOP` 存在的竞争问题。 120 | 121 | - * **非阻塞性**:`Actor` 之间是异步通信的,所以当一个 `Actor `发送信息给另外一个 `Actor` 之后,无需等待响应,发送完信息之后可以在本地继续运行其他任务,即通过消息传递机制,从而避免了阻塞。 122 | 123 | - * **无需使用锁**:`Actor` 从 `MailBox` 中一次只能读取一个消息,也就是说,`Actor` 内部只能同时处理一个消息,是一个**天然的互斥锁**,所以无需额外对代码加锁。 124 | 125 | - * **并发度高**:每个 `Actor` 只需处理本地 `MailBox` 的消息,因此多个 `Actor` 可以并行地工作,从而提高整个分布式系统的并行处理能力。 126 | 127 | - * **易扩展**:每个 `Actor` 都可以创建多个 `Actor`,从而减轻单个 `Actor` 的工作负载。当本地 `Actor` 处理不过来的时候,可以在远程节点上启动 `Actor` 然后转发消息过去。 128 | 129 | * **`Actor` 模型不足** 130 | 131 | - * 提供了模块和封装,但缺少继承和分层。即使多个 `Actor` 之间有公共逻辑或代码部分,都必须在每个 `Actor` 中重写这部分代码,重用性小,业务逻辑的改变会导致整体代码的重写。 132 | 133 | - * `Actor` 可以动态创建多个 `Actor`,使得整个 `Actor` 模型的行为不断变化,因此在工程中不易实现 `Actor` 模型。此外,增加 `Actor` 的同时,也会增加系统开销。 134 | 135 | - * `Actor` 模型不适用于对消息处理顺序有严格要求的系统。因为在 `Actor` 模型中,消息均为异步消息,无法确定每个消息的执行顺序。虽然可以通过阻塞 `Actor` 去解决顺序问题,但会严重影响 `Actor` 模型的任务处理效率。 136 | 137 | ### 6.4.4 流水线计算模式 138 | 139 | **流水线(`Pipeline`)**是将每条指令拆分为多个步骤,多个指令的不同步骤重叠操作,从而实现几条指令并行处理的技术。现代的`CPU`指令就是采用流水线设计,将一条`CPU`指令分为取指(`IF`)、译码(`ID`)、执行(`EX`)、访存(`MEM`)、回写(`WB`)五级流水线来执行。 140 | 141 | 分布式领域中,**流水线计算模式**也类似流水线设计,将大任务拆分成多个步骤执行,不同的步骤可以采用不同的进程执行,使得不同任务可以并行执行,从而提高系统效率。 142 | 143 | * **流水线计算模式** 144 | 145 | 流水线模式常见于数据处理中,即`ETL`,包含数据提取、转换、加载`3`个步骤: 146 | 147 | * **提取(Extract)**:通过多种途径采集/获取数据; 148 | 149 | * **转换(Transform)**:使用 `CPU` 处理器对输入的数据进行解析以及预处理操作,包括混合重排(`shuffling`)、批处理(`batching`), 以及一些特定的转换; 150 | 151 | * **加载(Load)**:将转换后的数据加载到业务或功能处理流程中。 152 | 153 | 其中第`N+1`个样本正在处理阶段的时候,第`N`个样本已经在进行数据转换了,而第`N-1`个样本在进行加载。 154 | 155 | 这样做能最大限度地缩短数据从提取到加载使用所需的时间,避免系统资源闲置,加速业务流程。 156 | 157 | - * 与`MapReduce`对比 158 | 159 | * `MapReduce` 以**任务为粒度**,将大的任务划分成多个小任务,每个任务都需要执行完整的、相同的步骤,**同一任务能被并行执行**,可以说是任务并行的一种计算模式; 160 | 161 | `MapReduce` 中,各个子任务可以独立执行,互不干扰,多个子任务执行完后,进行结果合并得到整个任务的结果,因此要求子任务之间是没有依赖关系的; 162 | 163 | * 流水线计算模式以**步骤为粒度**,一个任务拆分为多个步骤,每个步骤执行的是不同的逻辑,多个同类型任务**通过步骤重叠以实现不同任务的并行计算**,可说是数据并行的一种模式。 164 | 165 | 流水线模式中,多个子任务之间是具有依赖关系的,前一个子任务的输出是后一个子任务的输入。 -------------------------------------------------------------------------------- /分布式/分布式资源管理和负载调度.md: -------------------------------------------------------------------------------- 1 | ## 6.3 分布式资源管理和负载调度 2 | 3 | >date: 2019-12-15 4 | 5 | ![](../assets/images/63.jpg) 6 | 7 | ### 6.3.1 分布式体系结构 8 | 9 | #### 集中式结构 10 | 11 | **集中式结构**(也称为 `Master/Slave` 架构)就是由一台或多台服务器组成中央服务器,系统内的所有数据都存储在中央服务器中,系统内所有的业务也均先由中央服务器处理。 12 | 13 | 多个节点服务器与中央服务器连接,并将自己的信息汇报给中央服务器,由中央服务器统一进行资源和任务调度:中央服务器根据这些信息,将任务下达给节点服务器;节点服务器执行任务,并将结果反馈给中央服务器。 14 | 15 | **特点**:**部署结构简单**,中央服务器进行统一管理和调度任务,无需考虑对任务的多节点部署,而节点服务器之间无需通信和协作,只要与中央服务器通信协作即可。 16 | 17 | ![集中式架构](../assets/images/631_01.png) 18 | 19 | 常见**集中式集群管理系统**:`Google Borg`、`Kubernetes`、`Apache Mesos`。 20 | 21 | #### 非集中式结构 22 | 23 | **非集中式结构**将服务的执行和数据的存储分散到不同的服务器集群,服务器集群间通过消息传递进行通信和协调。 24 | 25 | 在这结构中,没有中央服务器和节点服务器之分,所有的服务器地位都是平等的。 26 | 27 | 相比于集中式结构,非集中式结构降低了某一个或莫一簇计算机集群的压力,在解决单点瓶颈和单点故障问题的同时,还提升了系统的并发度。 28 | 29 | * `Gossip` 协议 30 | 31 | **`Gossip` 协议** 也叫 `Epidemic Protocol`(流行病协议)、流言算法、疫情传播算法等。 32 | 33 | `Gossip` 的原理是每个节点周期性地从自己维护的集群节点列表中,随机选择 `k` 个节点,将自己存储的数据信息发给这 `k` 个节点,接收到该信息的节点基于某些**共识原则**,对收到的数据和本地数据进行合并。这样迭代几个周期后,集群中所有节点上的数据信息就一致了。 34 | 35 | 这个过程可能需要一定的时间,由于不能保证某个时刻所有节点都收到消息,但是理论上最终所有节点都会收到消息,因此它是一个**最终一致性**协议。 36 | 37 | 常见的**非集中式架构系统**:`Akka` 集群、`Redis` 集群和 `Cassandra` 集群。 38 | 39 | ### 6.3.2 分布式调度架构 40 | 41 | 为用户任务寻找合适的服务器这个过程,在分布式领域中叫作**调度**。在分布式系统架构中,**调度器**就是一个非常重要的组件,它通常会提供多种调度策略,负责完成具体的调度工作。 42 | 43 | #### 单体调度 44 | 45 | **单体调度**是指一个集群中只有一个节点运行调度进程,该节点对集群中的其他节点具有访问权限,可以搜集其他节点的资源信息、节点状态等进行统一管理,同时根据下发的任务对资源的需求,在调度器中进行任务与资源匹配,然后根据匹配结果将任务指派给其他节点。 46 | 47 | **单体调度器拥有全局资源视图和全局任务,可以很容易地实现对任务的约束并实施全局性的调度策略**。目前如 `Google Borg`、`Kubernetes` 等很多集群管理系统采用了单体调度设计。 48 | 49 | ![单体调度框架](../assets/images/632_01.png) 50 | 51 | 上图是一个典型的单体调度框架。其中 `Master` 节点上运行了调度进程,其负责资源管理、`Tasks` 和资源匹配等工作。 52 | 53 | 而 `Node1`、`Node2`、`...`、`NodeN` 对应着 `Master/Slave` 架构中的 `Slave` 节点。 54 | 55 | `Slave` 节点会将 `Node State` 上报给 `Master` 节点中的 `Cluster State` 模块,`Cluster State` 模块用于管理集群中节点的资源等状态,并将节点的资源状态传送给 `Scheduling Logic` 模块,以便 `Scheduling Logic` 模块进行 `Tasks` 与资源匹配,并根据匹配结果将 `Task `发送给匹配到的节点。 56 | 57 | * **单体调度设计** 58 | 59 | 在集群管理中,单体调度模块称为 `Scheduler` 或**单体调度器**。单体调度器也叫作**集中式调度器**,指的是使用中心化的方式去管理资源和调度任务。 60 | 61 | 调度器本身在系统中以**单实例**形式存在,所有的资源请求和任务调度都通过这个实例进行。**集中式调度器模型**中,资源的使用状态和任务的执行状态都**由调度器进行管理**。 62 | 63 | ![集中式调度器模型](../assets/images/632_02.png) 64 | 65 | **特点**:单体调度器拥有全局资源视图和全局任务,可以容易地实现对任务的约束并实施全局性的调度策略。但是其同样存在**单点瓶颈**和**单点故障**的问题。 66 | 67 | #### 两层调度 68 | 69 | 单体调度架构会随着任务类型的增加而变得越来越复杂,最终出现扩展瓶颈。为了提升调度效率并支持多种类型的任务,就出现了两层调度。 70 | 71 | **两层调度架构**就是将资源了任务管理分开调度,即一层调度其只负责**资源管理和分配**,另一层调度器**负责任务和资源的匹配**。 72 | 73 | 资源的使用状态同时由中央调度器和第二层调度器管理,中央调度器从整体上进行资源的管理与分配,将资源分配到第二层调度器;再由第二层调度器负责将资源与具体的任务配对,因此第二层调度可以有多个调度器,以支持不同的任务类型。 74 | 75 | 如下图所示,`Scheduler-1` 表示第一层调度,负责收集和管理集群中的资源信息;`Scheduler-2` 表示第二层调度,`Scheduler-1` 会将集群资源发送给 `Scheduler-2`,然后 `Scheduler-2` 根据任务的资源需求和 `Scheduler-1` 发送的资源信息进行任务匹配和调度。 76 | 77 | ![两层调度架构](../assets/images/632_03.png) 78 | 79 | 两层调度器中的第一层调度器仍是一个经简化的中央调度器,通常放在分布式集群管理系统中,而第二层调度则是由各个应用程序框架完成。 80 | 81 | 两层调度器的职责分别是:第一层调度器负责管理资源并向框架分配资源,第二层调度器接收分布式集群管理系统中第一层调度器分配的资源,然后根据任务和接收到的资源进行匹配。 82 | 83 | 采用两层调度结构的集群管理系统有很多,典型代表是 `Apache Mesos` 和` Hadoop YARN`。 84 | 85 | * **资源分配算法** 86 | 87 | - * **最大最小公平算法(`Max-min Fairness`,`MMF`)** 88 | 89 | 这个算法有 `3` 个主要原则: 90 | 91 | - 1) 按照用户对资源需求量递增的顺序进行空闲资源分配; 92 | 93 | - 2) 不存在用户得到的资源超过自己需求的情况; 94 | 95 | - 3) 对于分配的资源不满足需求的用户,所获得的资源是相等的。 96 | 97 | 在执行资源分配时,最大最小公平算法按照上述 `3` 条原则进行多次迭代,每次迭代中资源均平均分配,如果还有剩余资源,就进入下一次迭代,一直到所有用户资源得到满足或集群资源分配完毕,迭代结束。 98 | 99 | ![最大最小公平算法执行流程](../assets/images/632_04.png) 100 | 101 | 最大最小公平算法采用了绝对公平的方式分配资源,会导致大量的资源浪费。 102 | 103 | 比如用户需求量为 `35` 和 `45` 的用户 `A` 和用户 `D`,均分配了 `32.5` 的空闲资源,但由于资源不满足需求,这两个用户均无法使用。 104 | 105 | - * **主导资源公平算法(`Dominant Resource Fairness`,`DRF`)** 106 | 107 | 主导资源公平算法在考虑用户公平性的前提下,还考虑了用户对不同资源类型的需求,以尽可能地合理分配资源,即尽可能地满足更多的用户。 108 | 109 | 针对多种资源的需求,主导资源公平算法首先计算已经分配给用户的每一种资源的占用率(`Resource Share`),比如已经分配的 `CPU` 占总资源量的多少,已经分配的内存占总资源量的多少。所有资源占用率中的最大值称作该用户的**主导资源占用率**,而主导资源占用率对应的资源就是用户的主导资源。 110 | 111 | 如下图所示,假设系统中的资源共包括 `18` 个 `CPU` 和 `36 GB` 内存,有两个 `Framework`(`Framework A` 和 `Framework B`)分别运行了两种任务,假设 `Framework A` 运行内存密集型任务,`Framework B` 运行 `CPU` 密集型任务,且每个任务所需要的资源量是一致的,分别是 `<2 CPU, 8 GB>` 和 `<6 CPU, 2 GB>`。 112 | 113 | ![主导资源公平算法执行流程](../assets/images/632_05.png) 114 | 115 | - 1) 计算资源分配量。 116 | 117 | 假设 `x` 和 `y` 分别是 `Framework A` 和 `Framework B` 分配的任务数,那么 `Framework A` 消耗的资源为`{2x CPU,8x GB}`,`Framework B` 消耗的资源数为`{6y CPU,2y GB}`,分配给两个 `Framework` 的总资源量为 `2x+6y` 个 `CPU` 和 `8x+2y GB` 内存。 118 | 119 | - 2) 确定主导资源。 120 | 121 | 对于 `Framework A` 来说,每个任务要消耗总 `CPU` 资源的 `2/18`,总内存资源的 `8/36`,**所以 `Framework A` 的主导资源为内存**;对于 `Framework B` 来说,每个任务要消耗总 `CPU` 资源的` 6/18` 和总内存资源的 `2/36`,**因而 `Framework B` 的主导资源为 `CPU`**。 122 | 123 | - 3) `DRF` 算法的核心是平衡所有用户的主导资源占用率,尽可能试图最大化所有用户中最小的主导资源占用率。 124 | 125 | 通过求解公式 `8x/36=6y/18`,可以计算出 `Framework A` 和 `Framework B` 分配的任务数,并且要在满足公式的条件下,使得 `x` 和 `y` 越大越好。 126 | 127 | 通过求解可以得出:`x=3`,即 `Framework A` 可以运行 `3` 个任务;`y=2`,即 `Framework B` 可以运行 `2` 个任务。这样分配的话,每个 `Framework` 获取了相同比例的主导资源,即:`A` 获取了 `2/3` 的内存,`B` 获取了 `2/3` 的 `CPU`,从而在主导资源上体现了调度算法的公平性。 128 | 129 | 在实际任务分配过程中,主导资源率是根据已经分配给 `Framework` 的资源,占集群中总资源量的多少进行计算的,并且在每次分配过程中,会选择主导资源最小的 `Framework` 进行分配,也就是试图最大化所有用户中最小的主导资源占用率。 130 | 131 | 最大最小公平算法适用于**单一类型的资源分配场景**,而主导资源公平算法适用于**多种类型资源混合的场景**。并且,最大最小公平算法**从公平的角度出发**,为每个用户分配不多于需求量的资源;而主导资源公平算法**从任务的角度出发**,目的在于尽量充分利用资源使得能够执行的任务越多越好。 132 | 133 | #### 共享状态调度 134 | 135 | 集群中需要管理的对象主要包括两种:资源的分配和使用状态;任务的调度和执行状态。 136 | 137 | **单体调度**中,这两种对象都是由单体调度器管理的,因此可以比较容易地保证全局状态的一致性,但问题是**可扩展性较差**(支持业务类型受限),且存在**单点瓶颈**问题。 138 | 139 | **两层调度**中,这两种对象分别由第一层中央调度器和第二层 `Framework` 调度器管理,由于 `Framework` 调度器只能看到部分资源,因此**不能保证全局状态的一致性**,也**不容易实现全局最优的调度**。 140 | 141 | **共享状态调度器**沿袭了单体调度器的模式,通过将多个单体调度器分解为多个调度器,每个调度器都有全局的资源状态信息,从而实现最优的任务调度。在支持多种任务类型的同时,还能拥有全局的资源状态信息。 142 | 143 | ![共享状态调度器](../assets/images/632_06.png) 144 | 145 | 共享状态调度架构为了提供高可用性和可扩展性,将集群状态之外的功能抽出来作为独立的服务。具体来说就是: 146 | 147 | - * `State Storage` 模块(资源维护模块)负责存储和维护资源及任务状态,以便 Scheduler 查询资源状态和调度任务; 148 | 149 | - * `Resource Pool` 即为多个节点集群,接收并执行 Scheduler 调度的任务; 150 | 151 | - * `Scheduler` 只包含任务调度操作,而不是像单体调度器那样还需要管理集群资源等。 152 | 153 | 共享状态调度也支持多种任务类型,但**与两层调度架构相比**,主要有两个不同之处: 154 | 155 | - * 存在多个调度器,每个调度器都可以拥有集群全局的资源状态信息,可以根据该信息进行任务调度; 156 | 157 | - * 共享状态调度是**乐观并发调度**,在执行了任务匹配算法后,调度器将其调度结果提交给 `State Storage`,由其决定是否进行本次调度,从而解决竞争同一种资源而引起的冲突问题,实现全局最优调度。而两层调度是**悲观并发调度**,在执行任务之前避免冲突,无法实现全局最优匹配。 158 | 159 | **优点**:解决了单体调度架构中,中央服务器的单点瓶颈问题;解决了两层调度中任务匹配无法达到全局最优的问题,可扩展性强。 160 | 161 | **缺点**:存在潜在的资源冲突问题,实现复杂。 -------------------------------------------------------------------------------- /分布式/分布式通信.md: -------------------------------------------------------------------------------- 1 | ## 6.5 分布式通信 2 | 3 | >date: 2019-12-22 4 | 5 | ![](../assets/images/65.jpg) 6 | 7 | ### 6.5.1 远程调用 8 | 9 | **远程调用**相较于本地调用中进程内的函数调用,就是进程间函数的相互调用,是进程间**`IPC`**(`Inter-Process Communication`)的一种方式。 10 | 11 | 根据进程是否部署在同一台机器上,远程调用又可以分成**本地过程调用(`Local Procedure Call`,`LPC`)**和**远程过程调用(`Remote Procedure Call`, `RPC`)**。 12 | 13 | - * **本地过程调用**:指运行在同一台机器上的进程之间互相通信,在多进程操作系统中,运行不同的进程之间可以通过`LPC`进行函数调用; 14 | 15 | - * **远程过程调用**:指不同机器中运行的进程之间的相互通信,某一机器上运行的进程在不知道底层通信细节的情况下,就像访问本地服务一样,去调用远程机器上的服务。 16 | 17 | * **远程调用原理** 18 | 19 | 常见的两种远程调用机制有**远程过程调用`RPC`**和**远程方法调用`RMI`**。 20 | 21 | - * **远程过程调用** 22 | 23 | `RPC` 就是调用方采用参数传递的方式,通过调用本机器上的一个函数或方法,去执行远程机器上的函数或方法(可以统称为服务),并返回结果。在整个过程中 `RPC` 会隐藏具体的通信细节。 24 | 25 | 调用方进程并不需要知道底层是如何传输的,在调用方和用户眼里,**远程过程调用和调用一次本地服务没什么不同**。 26 | 27 | **`RPC` 和本地调用的区别**: 28 | 29 | - 1) **调用 `ID` 和函数的映射** 30 | 31 | 在本地调用中,进程内可共享内存地址空间,因此程序可直接通过函数名来调用函数。而函数名的本质就是一个函数指针,可以看成函数在内存中的地址。 32 | 33 | 但在 `RPC` 中,只通过函数名来调用函数是不行的,因为不同进程的地址空间是不一样的。 34 | 35 | 所以在 `RPC` 中,所有函数必须通过一个调用 `ID` 来做唯一标识。一个机器上运行的进程在做远程过程调用是,必须带上这个调用 `ID`。而进行通信的两台机器都需要维护一个函数与调用 `ID` 的映射表。 36 | 37 | 当调用方进程需要进行远程调用时候,先查询本地映射表,找到对应函数的映射 `ID`,然后将其传到远程机器上,通过映射表确定需要执行的函数。执行完后返回结果到调用方。 38 | 39 | - 2) **序列化** 40 | 41 | 在本地调用中,不同进程间可以共享内存,因此参数的传递只需压入栈,然后需要使用时,出栈即可。 42 | 43 | 而 `RPC` 需要使用网络传输来进行参数的传递,网络传输的内容是**二进制流**,无法直接传输参数的类型。 44 | 45 | 这时候就需要调用方和被调用方之间协调一个参数协议,双方基于这个协议将参数转成二进制流或将二进制流转回相应的参数格式。这个过程就是**序列化**和**反序列化**。 46 | 47 | - 3) **网络传输协议** 48 | 49 | `RPC` 参数基于网络进行传输的,如果想要序列化后的数据能在网络中高效且顺利地传输,就需要相应的网络协议来保障。 50 | 51 | 同时在一个系统中,如果服务提供方和服务调用方越来越多的时候,服务间的调用关系就会愈加复杂。假设服务提供方有 `n` 个, 服务调用方有 `m` 个,则调用关系可达 `n*m`,这会导致系统的通信量很大。 52 | 53 | 这时候就出现了**服务注册中心**,对服务提供方提供的服务信息进行存储和管理,对服务调用方提供服务地址和相关的服务信息等。 54 | 55 | - * **远程方法调用** 56 | 57 | `RMI` 是一个基于 `Java` 环境的应用编程接口,能够让本地 `Java` 虚拟机上运行的对象,像调用本地对象一样调用远程 `Java` 虚拟机上的对象。 58 | 59 | `RMI` 可以说是 `RPC` 的一种具体形式,其原理与 `RPC` 基本一致,唯一不同的是 `RMI` 是**基于对象的,充分利用了面向对象的思想去实现整个过程,其本质就是一种基于对象的 `RPC` 实现**。 60 | 61 | `RMI` 通过对象作为远程接口来进行远程方法的调用,返回的结果也是对象形式,可以是 `Java` 对象类型,也可以是基本数据类型。 62 | 63 | ### 6.5.2 发布订阅 64 | 65 | **发布订阅**中,**生产者**负责产生数据放到**消息中心**,**消费者**向消息中心**订阅**需要的消息,当发布者推送数据到消息中心后,消息中心根据消费者订阅情况将相关数据推送给对应的订阅者。 66 | 67 | * **发布订阅工作原理** 68 | 69 | - * **点对点** 70 | 71 | 生产者将消息发送到消息中心,然后消费者从消息中心取出对应的消息进行消费。消息被消费后,消息中心**不再存储该消息**,因此其他消费者无法再消费该消息。 72 | 73 | 即**点对点模式**虽然支持多个消费者,但**一个消息只能被一个消费者消费,不允许重复消费**。 74 | 75 | - * **发布订阅** 76 | 77 | 生产者可以发送消息到消息中心,而消息中心通常以主题(`Topic`)进行划分,每条消息都会有相应的主题,消息会被存储到自己所属的主题中,订阅该主题的所有消费者均可获得该消息进行消费。 78 | 79 | 与点对点模式相比,**发布订阅模式中一个消息可以被多个消费者进行消费,这也是和点对点模式的本质区别**。 80 | 81 | * **发布订阅模式的关键特征** 82 | 83 | - * **系统解耦,易于维护**: 84 | 85 | 发布者只负责消息的发布,不需要知道订阅者的数量,也不需要知道订阅者获取消息的用途,而订阅者也不需要知道发布者什么时候会发布消息。 86 | 87 | 发布者和订阅者互相独立,进而实现了系统解耦,每个部分可以单独维护,减少了因为生产者和消费者的耦合引入的一些相互影响,降低了维护的复杂度。 88 | 89 | - * **异步执行,避免高负载**: 90 | 91 | 发布者发布消息到消息中心,当消息超过消息中心可以存储的容量后,消息中心会丢弃掉超出的消息,这样系统就不会因为消息数量多而导致系统故障。 92 | 93 | ### 6.5.3 消息队列 94 | 95 | **消息队列**就是将消息或数据放到一个队列里,服务如果需要使用消息或数据,就去队列里面取。 96 | 97 | 消息队列是**基于队列实现**的,**存储具有特定格式的消息数据**,比如定义一个包含消息类型、标志消息唯一性的 `ID`、消息内容的一个结构体作为消息数据的特定格式。 98 | 99 | 消息以特定格式放入这个队列的尾部后可以直接返回,并不需要系统马上处理,之后会有其他进程从队列头部开始读取消息,按照消息放入的顺序逐一处理。 100 | 101 | * **消息队列原理** 102 | 103 | 消息队列模式也是包括 `3` 个核心部分: 104 | 105 | - * **生产者**:生产者产生消息或数据,并将消息或数据插入到消息队列中。 106 | 107 | - * **消息队列**:一种具有先进先出特点的数据结构,用于存储消息。 108 | 109 | - * **消费者**:从消息队列中获取消息或数据,进行相关处理。 110 | 111 | 具体流程是,生产者将发送的消息插入消息队列,也就是入队,之后会有一个消费者从消息队列中逐次取出消息进行处理,完成出队。在分布式系统中,上游应用可以不用等待下游应用处理是否完成,只需关系消息队列中年是否有数据即可,这样可以提高响应速度,以及实现组件间的解耦。 112 | 113 | * **与发布订阅模式对比** 114 | 115 | **数据结构**: 116 | 117 | - * 发布订阅模式采用了消息中心,消息队列模式采用了消息队列中心,它们均用来存储生产者发布的数据,并均有主题、`Broker` 等概念; 118 | 119 | - * 消息队列模式中采用了具有先进先出特征的队列结构进行存储,发布订阅采用了 `map` 或数组等方式存储。 120 | 121 | **解耦方式**: 122 | 123 | - * **消息队列模式**中,生产者发布数据到消息队列中心,消息队列中心存储数据,等待消费者按需获取数据。生产者和消费者不直接通信,实现了生产者和消费者的解耦。对于消息队列模式,消息队列中心**无需提前获取消费者信息**,因此对消费者比较灵活,适合消费者为临时用户的场景。 124 | 125 | - * **发布订阅模式**中,消费者需要提前向消息中心订阅需要的数据,待生产者发布数据到消息中心后,消息中心根据订阅者订阅信息将数据主动推送给消费者,实现了消费者和生产者的解耦。发布订阅模式,需要消费者提前向消息中心订阅消息,也就是说消息中心需要提前获取消费者信息,比较适合消费者为长驻进程或服务的场景。 -------------------------------------------------------------------------------- /分布式/分布式高可靠.md: -------------------------------------------------------------------------------- 1 | ## 6.7 分布式高可靠 2 | 3 | >date: 2019-12-29 4 | 5 | ![](../assets/images/67.jpg) 6 | 7 | ### 6.7.1 负载均衡 8 | 9 | 负载均衡 (`Load Balance`),其意思就是将负载(工作任务)进行平衡、分摊到多个操作单元上进行执行 10 | 11 | 分布式系统中,服务请求的负载均衡是指,当处理大量用户请求时,请求应尽量均衡地分配到多台服务器进行处理,每台服务器处理其中一部分而不是所有的用户请求,以完成高并发的请求处理,避免因单机处理能力的上限,导致系统崩溃而无法提供服务的问题。 12 | 13 | 比如,有 `N` 个请求、`M` 个节点,负载均衡就是将 `N` 个请求,均衡地转发到这 `M` 个节点进行处理。 14 | 15 | 通常情况下,计算机领域中,在不同层有不同的负载均衡方法。比如,从网络层的角度,通常有基于 `DNS`、`IP` 报文等的负载均衡方法;在中间件层,常见的负载均衡策略主要包括**轮询策略**、**随机策略**、**哈希和一致性哈希**等策略,下面也是着重介绍中间件层的策略。 16 | 17 | * **轮询策略** 18 | 19 | - * **顺序轮询** 20 | 21 | 顺序轮流进行请求一次每个服务器,并循环进行该过程。 22 | 23 | 例如:假设有 `6` 个请求,编号为请求 `1~6`,有 `3` 台服务器可以处理请求,编号为服务器 `1~3`,如果采用顺序轮询策略,则会按照服务器 `1`、`2`、`3` 的顺序轮流进行请求。最终的处理结果是,服务器 `1` 处理请求 `1` 和请求 `4`,服务器 `2` 处理请求 `2` 和请求 `5`,服务器 `3` 处理请求 `3` 和请求 `6`。 24 | 25 | - * **加权轮询** 26 | 27 | 为每个服务器设置了优先级,每次请求过来时会挑选优先级最高的服务器进行处理。 28 | 29 | 例如:假设服务器 `1~3` 分配了优先级`{4,1,1}`,一共有 `6` 个请求到来: 30 | 31 | - 1) 请求 `1` 由优先级最高的服务器 `1` 处理,服务器 `1` 的优先级相应减 `1`,此时各服务器优先级为`{3,1,1}`; 32 | 33 | - 2) 请求 `2` 由目前优先级最高的服务器 `1` 进行处理,服务器 `1` 优先级相应减 `1`,此时各服务器优先级为`{2,1,1}`。 34 | 35 | - 3) 以此类推,直到处理完这 `6` 个请求。每个请求处理完后,相应服务器的优先级会减 `1`。最终的处理结果是,服务器 `1` 处理请求 `1~4`,服务器 `2` 处理请求 `5`,服务器 `3` 会处理请求 `6`。 36 | 37 | `Nginx` 默认的负载均衡策略就是一种改进的加权轮询策略。 38 | 39 | **优点**:实现简单,且对于请求所需开销差不多时,负载均衡效果比较明显,同时加权轮询策略还考虑了服务器节点的异构性,即可以让性能更好的服务器具有更高的优先级,从而可以处理更多的请求,使得分布更加均衡。 40 | 41 | **缺点**:每次请求到达的目的节点不确定,不适用于有状态请求的场景。并且,轮询策略主要强调请求数的均衡性,所以不适用于处理请求所需开销不同的场景。 42 | 43 | * **随机策略** 44 | 45 | 当用户请求到来时,随机分发到某个服务节点进行处理,即让请求尽可能分散到不同节点,防止有请求放在同一节点或少量几个节点上。 46 | 47 | **优点**:实现简单。 48 | 49 | **缺点**:每次请求到达的目的节点不确定,不适用于有状态的场景,而且没有考虑到处理请求所需开销。没有考虑服务器节点的异构性,即性能差距较大的服务器可能处理的请求差不多。 50 | 51 | **随机策略**与**轮询策略**相同,适用于集群中服务器节点处理能力相差不大,**用户请求所需资源比较接近的场景**。 52 | 53 | * **哈希和一致性哈希策略** 54 | 55 | **随机策略**和**轮询策略**都无法保证一个客户端的多次请求都落在同一个服务器,如果这是一个请求缓存服务器的请求,那么就很可能对缓存同步带来很大的挑战。 56 | 57 | 如果无法保证结果都来自同一台缓存服务器,在系统繁忙的时候,主从延迟带来同步缓慢会导致同一客户端两次相同的请求的到不同的结果。 58 | 59 | 使用**哈希与一致性哈希策略**的目的就是让数据的存储均匀和数据请求的均匀。 60 | 61 | **优点**:哈希函数设置合理的话,负载会比较均衡。而且,相同 `key` 的请求会落在同一个服务节点上,可以用于有状态请求的场景。除此之外,带虚拟节点的一致性哈希策略还可以解决服务器节点异构的问题。 62 | 63 | **缺点**:当某个节点出现故障时,采用**哈希策略**会出现数据大规模迁移的情况,采用**一致性哈希策略**可能会造成一定的数据倾斜问题。同时,这两种策略也没考虑请求开销不同造成的不均衡问题。 64 | 65 | ### 6.7.2 流量控制 66 | 67 | 在一些高并发、大流量的场景下,服务器的处理能力成为了整个的系统的瓶颈,如果处理不好就会导致系统崩溃,服务不可用,这时候**流量控制**就十分关键了。 68 | 69 | **分布式流量控制**就是在分布式系统下,控制每个服务器接收的请求数,以保证服务器来得及处理这些请求,也就是说尽可能保证用户请求持续地被处理,而不是让大量的用户请求**阻塞**在服务器中,等待被执行。 70 | 71 | * **消息队列** 72 | 73 | 这也是一种**流量控制**的方法,通过一个队列来存放用户请求,然后服务器到消息队列中逐个消费,可以避免消息过多时服务处理压力过大的问题。 74 | 75 | * **漏桶策略** 76 | 77 | **漏桶策略**(`Leaky Bucket`)主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。 78 | 79 | ![漏桶](../assets/images/672_01.png) 80 | 81 | 其先将请求先进入到漏桶里,漏桶以一定的速度出水,当水请求过大会直接溢出。这样能强行限制数据的传输速率,突发流量可以被整形以便为网络提供一个稳定的流量。这是一种**宽进严出**的策略。 82 | 83 | 漏桶策略**适用于间隔性突发流量且流量不用即时处理的场景**,即可以在**流量较小时的空闲期,处理大流量时流入漏桶的流量**。 84 | 85 | **不适合流量需要即时处理的场景**,即突发流量时可以放入桶中,但缺乏效率,始终以固定速率进行处理。 86 | 87 | * **令牌桶策略** 88 | 89 | **令牌桶策略**(`Token Bucket`)是网络流量整形(`Traffic Shaping`)和速率限制(`Rate Limiting`)中最常使用的一种算法。 90 | 91 | 典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。 92 | 93 | ![令牌桶](../assets/images/672_02.png) 94 | 95 | 首先存在一个固定容量的桶存放令牌,以固定的速率往桶中放入令牌,而当桶满的收就会丢弃多余的令牌。当请求到来时,必须先从桶汇总取出一个令牌才能被服务器处理。 96 | 97 | 当有**突发大流量**时,只要令牌桶里有足够多的令牌,请求就会被迅速执行。通常情况下,**令牌桶容量的设置,可以接近服务器处理的极限**,这样就可以有效利用服务器的资源。 98 | 99 | 令牌桶策略**适用于有突发特性的流量,且流量需要即时处理的场景**。 100 | 101 | ### 6.7.3 故障隔离 102 | 103 | 在分布式系统中,**故障隔离**就是采用一定的策略,以实现当某个模块故障时,不会影响其他模块继续提供服务,以**保证整个系统的可用性**。 104 | 105 | 故障隔离,可以避免分布式系统出现大规模的故障,甚至是瘫痪,降低损失。 106 | 107 | * 分布式故障隔离策略 108 | 109 | - 1) 以系统功能模块为粒度进行隔离 110 | 111 | 通过系统功能/服务进行划分,将系统分为多个功能/服务模块,各个功能/模块之间实现松耦合,当一个功能/服务出现故障时候,不会影响其他功能/服务模块。 112 | 113 | 根据功能模块/服务是由线程执行或进程执行的,通常分为线程级隔离、进程级隔离。 114 | 115 | - 2) 通过资源隔离来实现 116 | 117 | 系统中各个模块拥有自己独立的资源,不会发生资源争抢,从而大大提升系统性能。 118 | 119 | 根据资源所属粒度,通常分为进程级隔离(比如采用容器隔离)、虚拟机隔离、服务器隔离和机房隔离等。 120 | 121 | * 线程级隔离 122 | 123 | 线程级故障隔离,是指使用不同的线程池处理不同的请求任务。当某种请求任务出现故障时,负责其他请求任务的线程池不会受到影响,即会继续提供服务,从而实现故障的隔离。 124 | 125 | 线程级的故障隔离策略,在生产环境中较为常用,尤其对于单体应用(单进程多线程的应用)。在单体应用场景下,应用被单个进程执行,但单进程中包括多个线程,因此该场景下,只需要实现线程级隔离即可,实现简单、效果好,因此是一种很常用的方式。 126 | 127 | 系统实现线程级隔离后,线程间的通信通常使用**共享变量**来实现。 128 | 129 | * 进程级隔离 130 | 131 | 将系统按照功能分为不同的进程,分布到相同或不同的机器中。 132 | 133 | 如果系统的进程分布到不同机器上的话,从资源的角度来看,也可以说成是主机级的故障隔离。 134 | 135 | 因为系统分布在不同的机器上,当某个机器出现故障时,不会对其他机器造成影响。 136 | 137 | 系统实现进程级隔离后,进程间的协同必须通过进程间通信(`IPC`)来实现。如果进程都在同一台机器上,则可以通过管道、消息队列、信号量、共享内存等方式,来实现;如果进程分布在不同机器上,则可以通过远程调用来实现。 138 | 139 | * 资源隔离 140 | 141 | 资源隔离就是将分布式系统的所有资源分成几个部分,每部分资源负责一个模块,这样系统各个模块就不会争抢资源,即资源之间互不干扰。这种方式不仅可以提高硬件资源利用率,也便于系统的维护与管理,可以大幅提升系统性能。 142 | 143 | 微服务就是一个典型的例子,在微服务的理念中,是尽可能将服务最小化,服务与服务之间进行解耦合,包括运行环境的相互隔离等。在微服务中,一个服务通常对应一个容器,而一个容器其实就是操作系统中一个进程,不同容器负责不同的服务,类似不同进程负责系统不同的功能模块。 144 | 145 | 与进程级隔离不同的是,微服务框架采用容器进行故障隔离。容器虽然本质上是操作系统的一个进程,**但具备普通进程不具备的特性,比如资源隔离**。 146 | 147 | 容器可以实现资源限制,让每个容器占用的资源都有一个上限,比如 `CPU`、内存,均会设置一个上限值,这个上限值限定了该容器的处理能力,就好比一台服务器具有资源上限值一样。 148 | 149 | 因此,一个容器使用的资源不会影响其他容器的资源,从而避免资源争抢,提高性能。 150 | 151 | 容器是一种**虚拟化技术**,可以为应用提供一整套运行环境,其通过限制自身使用的资源来实现资源隔离。 152 | 153 | * 其它隔离方式 154 | 155 | **虚拟机级别的隔离**也是资源隔离的一种常用手段,一台物理机可以安装多个虚拟机,每个虚拟机都会分配一定的资源,即进行资源隔离。 156 | 157 | **主机级别的隔离**也可以说是一种资源隔离,每台机器的资源是独享的,不会与其他机器发生资源争夺,从而做到资源隔离。 158 | 159 | **集群隔离、机房隔离**等也是一些更粗力度的隔离策略,这些策略主要是跨集群或跨地域的隔离策略。这些粗粒度的隔离策略,不仅可以根据系统功能/服务等维度对系统进行划分,比如每个功能/服务由一个集群或一个机房单独负责,而且也是一种资源隔离策略,即集群间或机房间资源互相隔离,不会发生资源争夺,互不影响。 -------------------------------------------------------------------------------- /数据分析/README.md: -------------------------------------------------------------------------------- 1 | # 7. 数据分析 2 | 3 | ## 7.1 [统计学基础](统计学基础.md) 4 | 5 | ### 7.1.1 [描述性统计分析](统计学基础.md#711-描述性统计分析) 6 | 7 | ### 7.1.2 [数理统计](统计学基础.md#712-数理统计) 8 | 9 | ### 7.1.3 [抽样估计](统计学基础.md#713-抽样估计) 10 | 11 | ### 7.1.4 [假设检验](统计学基础.md#714-假设检验) 12 | 13 | ### 7.1.5 [方差分析](统计学基础.md#715-方差分析) 14 | 15 | ### 7.1.6 [相关与回归分析](统计学基础.md#716-相关与回归分析) 16 | 17 | ### 7.1.7 [时间序列](统计学基础.md#717-时间序列) 18 | 19 | ## 7.2 [数据分析方法](数据分析方法.md) 20 | 21 | ### 7.2.1 [主成分分析与典型相关分析](数据分析方法.md#721-主成分分析与典型相关分析) 22 | 23 | ### 7.2.2 [因子分析](数据分析方法.md#722-因子分析) 24 | 25 | ### 7.2.3 [判别分析](数据分析方法.md#723-判别分析) 26 | 27 | ### 7.2.4 [聚类分析](数据分析方法.md#724-聚类分析) 28 | 29 | ### 7.2.5 [`Bayes`统计模型](数据分析方法.md#725-Bayes统计模型) 30 | 31 | ## 7.3 [`NumPy`](NumPy.md) 32 | 33 | ### 7.3.1 [多维数组对象](NumPy.md#731-多维数组对象) 34 | 35 | ### 7.3.2 [通用函数](NumPy.md#732-通用函数) 36 | 37 | ### 7.3.3 [线性代数](NumPy.md#733-线性代数) 38 | 39 | ### 7.3.4 [随机数](NumPy.md#734-随机数) 40 | 41 | ### 7.3.5 [`IO`操作](NumPy.md#735-IO操作) 42 | 43 | ### 7.3.6 [广播](NumPy.md#736-广播) 44 | 45 | ### 7.3.7 [`matrix`类](NumPy.md#737-matrix类) 46 | 47 | ## 7.4 [`Pandas`](Pandas.md) 48 | 49 | ### 7.4.1 [基本数据结构](Pandas.md#741-基本数据结构) 50 | 51 | ### 7.4.2 [基本操作](Pandas.md#742-基本操作) 52 | 53 | ### 7.4.3 [汇总和计算描述统计](Pandas.md#743-汇总和计算描述统计) 54 | 55 | ### 7.4.4 [`IO`操作](Pandas.md#744-io操作) 56 | 57 | ### 7.4.5 [数据准备](Pandas.md#745-数据准备) 58 | 59 | ### 7.4.6 [聚合和分组](Pandas.md#746-聚合和分组) 60 | 61 | ### 7.4.7 [时间序列](Pandas.md#747-时间序列) 62 | 63 | ## 7.5 [数据可视化](数据可视化.md) 64 | 65 | ### 7.5.1 [`Matplotlib`入门](数据可视化.md#751-matplotlib入门) 66 | 67 | ### 7.5.2 [`Seaborn`入门](数据可视化.md#752-seaborn入门) -------------------------------------------------------------------------------- /数据库/README.md: -------------------------------------------------------------------------------- 1 | # 5. 数据库 2 | 3 | ## 5.1 [数据库系统原理](数据库系统原理.md) 4 | 5 | ### 5.1.1 [事务](数据库系统原理.md#511-事务) 6 | 7 | ### 5.1.2 [并发一致性问题](数据库系统原理.md#512-并发一致性问题) 8 | 9 | ### 5.1.3 [常见的并发控制](数据库系统原理.md#513-常见的并发控制) 10 | 11 | ### 5.1.4 [多版本并发控制](数据库系统原理.md#514-多版本并发控制) 12 | 13 | ### 5.1.5 [关系型数据库设计](数据库系统原理.md#515-关系型数据库设计) 14 | 15 | ### 5.1.6 [ER图](数据库系统原理.md#516-ER图) 16 | 17 | ## 5.2 [SQL](SQL.md) 18 | 19 | ### 5.2.1 [数据操纵](SQL.md#521-数据操纵) 20 | 21 | ### 5.2.2 [数据查询](SQL.md#522-数据查询) 22 | 23 | ### 5.2.3 [聚合函数](SQL.md#523-聚合函数) 24 | 25 | ### 5.2.4 [多表](SQL.md#524-多表) 26 | 27 | ### 5.2.5 [子查询](SQL.md#525-子查询) 28 | 29 | ### 5.2.6 [集合操作](SQL.md#526-集合操作) 30 | 31 | ### 5.2.7 [条件聚合](SQL.md#527-条件聚合) 32 | 33 | ### 5.2.8 [日期,数字和字符串函数](SQL.md#528-日期数字和字符串函数) 34 | 35 | ### 5.2.9 [视图](SQL.md#529-视图) 36 | 37 | ### 5.2.10 [存储过程](SQL.md#5210-存储过程) 38 | 39 | ### 5.2.11 [触发器](SQL.md#5211-触发器) 40 | 41 | ### 5.2.12 [事务管理](SQL.md#5212-事务管理) 42 | 43 | ## 5.3 [MySQL](MySQL.md) 44 | 45 | ### 5.3.1 [数据类型](MySQL.md#531-数据类型) 46 | 47 | ### 5.3.2 [权限管理](MySQL.md#532-权限管理) 48 | 49 | ### 5.3.3 [视图](MySQL.md#533-视图) 50 | 51 | ### 5.3.4 [索引](MySQL.md#534-索引) 52 | 53 | ### 5.3.5 [存储引擎](MySQL.md#535-存储引擎) 54 | 55 | ### 5.3.6 [读写分离和分库分表](MySQL.md#536-读写分离和分库分表) 56 | 57 | ### 5.3.7 [基本架构](MySQL.md#537-基本架构) 58 | 59 | ### 5.3.8 [日志模块](MySQL.md#538-日志模块) 60 | 61 | ### 5.3.9 [事务](MySQL.md#539-事务) 62 | 63 | ### 5.3.10 [锁](MySQL.md#5310-锁) 64 | 65 | ### 5.3.11 [`MVCC`](MySQL.md#5311-mvcc) 66 | 67 | ## 5.4 PostgreSQL 68 | 69 | ## 5.5 [MongoDB](MongoDB.md) 70 | 71 | ### 5.5.1 [NoSQL和MongoDB](MongoDB.md#551-NoSQL和MongoDB) 72 | 73 | ### 5.5.2 [常用命令](MongoDB.md#552-常用命令) 74 | 75 | ### 5.5.3 [高级操作](MongoDB.md#553-高级操作) 76 | 77 | ## 5.6 [Redis](Redis.md) 78 | 79 | ### 5.6.1 [简介](Redis.md#561-简介) 80 | 81 | ### 5.6.2 [数据类型](Redis.md#562-数据类型) 82 | 83 | ### 5.6.3 [常用命令](Redis.md#563-常用命令) 84 | 85 | ### 5.6.4 [持久化](Redis.md#564-持久化) 86 | 87 | ### 5.6.5 [事务](Redis.md#565-事务) 88 | 89 | ### 5.6.6 [发布和订阅](Redis.md#566-发布和订阅) 90 | 91 | ### 5.6.7 [事件](Redis.md#567-事件) 92 | 93 | ### 5.6.8 [内存回收机制和数据淘汰策略](Redis.md#568-内存回收机制和数据淘汰策略) 94 | 95 | ### 5.6.9 [底层数据结构](Redis.md#569-底层数据结构) 96 | 97 | ### 5.6.10 [分布式相关](Redis.md#5610-分布式相关) 98 | 99 | ### 5.6.11 [相关问题](Redis.md#5611-相关问题) 100 | 101 | ### 5.6.12 [扩展阅读](Redis.md#5612-扩展阅读) 102 | -------------------------------------------------------------------------------- /机器学习/README.md: -------------------------------------------------------------------------------- 1 | # 8. 机器学习 2 | 3 | ## 8.1 [基础概念](基础概念.md) 4 | 5 | ### 8.1.1 [概述](基础概念.md#811-概述) 6 | 7 | ### 8.1.2 [模型评估](基础概念.md#812-模型评估) 8 | 9 | ### 8.1.3 [特征工程](基础概念.md#813-特征工程) 10 | 11 | ### 8.1.4 [优化算法](基础概念.md#814-优化算法) 12 | 13 | ## 8.2 [监督学习](监督学习.md) 14 | 15 | ### 8.2.1 [`Logistic`回归](监督学习.md#821-logistic回归) 16 | 17 | ### 8.2.2 [决策树](监督学习.md#822-决策树) 18 | 19 | ### 8.2.3 [朴素贝叶斯法](监督学习.md#823-朴素贝叶斯法) 20 | 21 | ### 8.2.4 [`SVM`](监督学习.md#824-SVM) 22 | 23 | ## 8.3 [集成学习](集成学习.md) 24 | 25 | ### 8.3.1 [自助法(`Bootstrap`)](集成学习.md831-自助法bootstrap) 26 | 27 | ### 8.3.2 [装袋法(`Bagging`)](集成学习.md832-装袋法bagging) 28 | 29 | ### 8.3.3 [提升法(`Boosting`)](集成学习.md#833-提升法boosting) 30 | 31 | ### 8.3.4 [`GBDT`](集成学习.md#834-gbdt) 32 | 33 | ### 8.3.5 [`Stacking`](集成学习.md#835-stacking) 34 | 35 | ## 8.4 [非监督学习](非监督学习.md) 36 | 37 | ### 8.4.1 [`kNN`](非监督学习.md#841-knn) 38 | 39 | -------------------------------------------------------------------------------- /机器学习/非监督学习.md: -------------------------------------------------------------------------------- 1 | ## 8.4 非监督学习 2 | 3 | >date: 2019-06-28 4 | 5 | ![](../assets/images/84.jpg) 6 | 7 | ### 8.4.1 `kNN` 8 | 9 | `kNN`又叫$k$-近邻算法,是一种常用的监督学习方法,它的工作机制简单来说就是:在给定的测试样本中,基于某种距离度量找出训练集中与其最靠近的$k$个训练样本,然后基于这$k$个“邻居”的信息来进行预测。 10 | 11 | * 在分类中可使用“投票法”,即选择这$k$个样本中出现最多的类别标记作为预测的结果; 12 | * 在回归中可使用“平均法”,即将这$k$个样本的实值输出标记值的平均值作为预测结果。 13 | 14 | 还可基于距离的远近进行加权平均和加权投票。 15 | 16 | #### 度量距离 17 | 18 | 设特征空间中$X$是$n$维实数向量$\Bbb{R}^n$,$x_i,x_j\in X$,$x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(n)})$,$x_j=(x_j^{(1)},x_j^{(2)},...,x_j^{(n)})$. 19 | 20 | $x_i, x_j$ 的 $L_p$ 距离为: 21 | 22 | $$L_p(x_i, x_j)=(\sum_{l=1}^{n}|x_i^{l}-x_j^{l}|^{p})^{\frac{1}{p}}, (p\geq1)$$ 23 | 24 | 当$p=2$时,为欧式距离(`Euclidean distance`) 25 | 26 | $$L_2 (x_i,x_j)= (\sum_{l=1}^{n}|x_i^{l}-x_j^{l}|^{2})^{\frac{1}{2}}$$ 27 | 28 | 当$p=1$时,为曼哈顿距离(`Manhattan distance`) 29 | 30 | $$L_1 (x_i,x_j)= \sum_{l=1}^{n}|x_i^{l}-x_j^{l}|$$ 31 | 32 | 当$p=\infty$时,是各个坐标距离的最大值 33 | 34 | $$L_p=\infty(x_i,x_j)= \max_{l} \sum_{l=1}^{n}|x_i^{l}-x_j^{l}|$$ 35 | 36 | #### `k`值的选取 37 | 38 | `k`值的选取会对`k`近邻法的结果产生重大影响。 39 | 40 | 如果选择较小的`k`值,就相当于用较小的邻域中的训练实例进行预测,“学习”的近似误差(`approximation error`)会减小,只有与输入实例相似的训练实例才会对预测结果产生作用。但缺点是“学习”的估计误差(`estimation error`)会增大,预测结果会对近邻的实例点非常敏感。如果邻近的实例点恰好是噪声,预测就会出错,亦即`k`值的减小就意味着整体的模型变复杂,容易发生过拟合。 41 | 42 | 如果选择较大的`k`值,就相当于用较大的邻域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时与输入实例不相似的训练实例也会对预测产生作用,是预测发生错误。`k`的增大就意味着整体的模型变得简单。 43 | 44 | #### 算法实现 45 | 46 | 使用以下的数据集进行实验: 47 | 48 | | 编号 | 色泽 | 根蒂 | 敲声 | 纹理 | 脐部 | 触感 | 好瓜 | 49 | | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | 50 | | 1 | 青绿 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 | 51 | | 2 | 乌黑 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 是 | 52 | | 3 | 乌黑 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 | 53 | | 4 | 青绿 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 硬滑 | 是 | 54 | | 5 | 浅白 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 硬滑 | 是 | 55 | | 6 | 青绿 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 是 | 56 | | 7 | 乌黑 | 稍蜷 | 浊响 | 稍糊 | 稍凹 | 软粘 | 是 | 57 | | 8 | 乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 硬滑 | 是 | 58 | | 9 | 乌黑 | 稍蜷 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 | 59 | | 10 | 青绿 | 硬挺 | 清脆 | 清晰 | 平坦 | 软粘 | 否 | 60 | | 11 | 浅白 | 硬挺 | 清脆 | 模糊 | 平坦 | 硬滑 | 否 | 61 | | 12 | 浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 软粘 | 否 | 62 | | 13 | 青绿 | 稍蜷 | 浊响 | 稍糊 | 凹陷 | 硬滑 | 否 | 63 | | 14 | 浅白 | 稍蜷 | 沉闷 | 稍糊 | 凹陷 | 硬滑 | 否 | 64 | | 15 | 乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 否 | 65 | | 16 | 浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 硬滑 | 否 | 66 | | 17 | 青绿 | 蜷缩 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 | 67 | 68 | 由于各种距离需要使用数值进行计算,上述“色泽”、“根蒂”、“敲声”、“纹理”、“脐部”和“触感”6个特征变量都是类别变量(`factor`),需要将其转化为哑变量(`dummy variables`)。 69 | 70 | 例如在“色泽”中,令数值`0`代表“乌黑”,数值`1`代表“青绿”,数值`2`代表“浅白”,以此进行转换。 71 | 72 | 73 | ```python 74 | filename = '822_01.txt' 75 | def factor2dummy_variable(filename): 76 | fr = open(filename,encoding = 'utf-8')#以utf-8读取文件 77 | dataColumns = fr.readline()#去除首行 78 | arrayLines = fr.readlines()#读取所有行 79 | lines = np.array([line.replace('\n','').split(',') for line in arrayLines]).T#按行指定分隔符,并进行转置 80 | lines = lines[1:,:]#实际使用的数据部分 81 | setFactors = [set(line) for line in lines]#set操作,只保存一种分类的集合 82 | k = 0 83 | for i in setFactors: 84 | dummy_num = 0 85 | line = lines[k] 86 | for j in i: 87 | line[line == j] = dummy_num#哑变量转换 88 | dummy_num += 1 89 | k += 1 90 | lines = lines.T#转置 91 | return lines 92 | ``` 93 | 将转换好的数据集保存到文件, 94 | 95 | ```python 96 | lines = factor2dummy_variable(filename) 97 | dataSet = lines 98 | filename = '841_01.txt' 99 | def data2txt(dataSet,filename): 100 | fw = open(filename,'w',encoding='utf-8')#以utf-8编码写入 101 | for line in dataSet: 102 | for element in line: 103 | fw.write(element) 104 | fw.write(',')#tab键分割符号 105 | fw.write('\n')#换行 106 | fw.close() 107 | data2txt(dataSet, filename) 108 | ``` 109 | 110 | 转换好的数据集格式如下: 111 | 112 | ``` 113 | 1,2,0,1,0,1,0, 114 | 2,2,1,1,0,1,0, 115 | 2,2,0,1,0,1,0, 116 | 1,2,1,1,0,1,0, 117 | 0,2,0,1,0,1,0, 118 | 1,1,0,1,1,0,0, 119 | 2,1,0,0,1,0,0, 120 | 2,1,0,1,1,1,0, 121 | 2,1,1,0,1,1,1, 122 | 1,0,2,1,2,0,1, 123 | 0,0,2,2,2,1,1, 124 | 0,2,0,2,2,0,1, 125 | 1,1,0,0,0,1,1, 126 | 0,1,1,0,0,1,1, 127 | 2,1,0,1,1,0,1, 128 | 0,2,0,2,2,1,1, 129 | 1,2,1,0,1,1,1, 130 | ``` 131 | 132 | 处理完毕上述变量后,需要将转换好的数据文件转化成`NumPy`可以使用的数据集形式, 133 | 134 | ```python 135 | filename = '841_01.txt' 136 | def file2matrix(filename): 137 | fr = open(filename) 138 | arrayOLines = fr.readlines()#读取所有行 139 | numberOfLines = len(arrayOLines)#计算记录数量 140 | numberOfcloumns = len(arrayOLines[0].replace(',\n','').split(',')) - 1#计算变量数量 141 | returnMat = np.zeros((numberOfLines, numberOfcloumns)) 142 | classLabelVector = [] 143 | index = 0 144 | for line in arrayOLines: 145 | line = line.strip()#去除空格 146 | listFromLine = line.split(',')#按tab键分割 147 | returnMat[index, :] = listFromLine[:-2]#得到分类变量数组 148 | classLabelVector.append(int(listFromLine[-2]))#类别变量数组 149 | index += 1 150 | return returnMat, classLabelVector 151 | ``` 152 | 153 | ​*注:有时候由于各类变量之间数值差别太大,同时量纲也各不相同,这时候就需要进行归一化操作,将各变量的范围设置在0~1之间,以消除量纲影响,加快运算速度。* 154 | 155 | * 归一化: 156 | 157 | $$x' = \frac{x - \min{(x)}}{\min{(x)}-\max{(x)}}$$ 158 | 159 | 下述代码即进行归一化操作: 160 | 161 | ```python 162 | def autoNorm(dataSet): 163 | minValue = dataSet.min(0)#得到每列的最小值 164 | maxValue = dataSet.max(0)#每列最大值 165 | ranges = maxValue - minValue#分母 166 | normDataSet = np.zeros(np.shape(dataSet)) 167 | m = dataSet.shape[0]#行数 168 | normDataSet = dataSet - np.tile(minValue, (m,1))#分子 169 | normDataSet = normDataSet/np.tile(ranges, (m,1)) 170 | return normDataSet, ranges, minValue 171 | ``` 172 | 173 | 经过上述处理,这里通过计算欧式距离进行`kNN`分类,具体代码如下: 174 | 175 | ```python 176 | def classify0(inX, dataSet, labels, k): 177 | dataSetSize = dataSet.shape[0]#得到行数 178 | diffMat = np.tile(inX, (dataSetSize,1)) - dataSet#计算输入向量inX与训练样本的差 179 | sqDiffMat = diffMat**2#计算差值的平方 180 | sqDistances = sqDiffMat.sum(axis = 1)#距离平方和 181 | distances = sqDistances**0.5#开方得到距离 182 | sortedDistIndicies = distances.argsort()#距离进行排序,得到排序的下标 183 | classCount = {} 184 | for i in range(k):#确定前k个距离中最小元素所属分类 185 | voteIlabel = labels[sortedDistIndicies[i]] 186 | classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1#对出现的label进行计数 187 | sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)#按照计数值进行降序排序 188 | #operator.itemgetter(1)确定一个函数取出classCount中的第一个域的值,即将value取出 189 | return sortedClassCount[0][0]#返回最大的计数值的分类 190 | ``` 191 | 192 | 由此,即进行了*kNN*的分类操作,下面通过以下代码对分类效果进行测试(测试数据集仍是训练数据集合) 193 | 194 | ```python 195 | dataLines, datalabels = file2matrix('841_01.txt') 196 | i=0 197 | errorCount = 0.0 198 | for line in dataLines: 199 | print('记录%s的原始分类是:%d,划分分类是:%d' %(str(line), datalabels[i], classify0(line, dataLines ,datalabels, 1))) 200 | if (datalabels[i] != classify0(line, dataLines ,datalabels, 1)): 201 | errorCount += 1.0 202 | i += 1 203 | print('错误率为: %f' %(errorCount/float(len(dataLines)))) 204 | ''' 205 | 记录[0. 2. 0. 2. 2. 1.]的原始分类是:1,划分分类是:1 206 | 记录[1. 2. 1. 2. 2. 1.]的原始分类是:1,划分分类是:1 207 | 记录[1. 2. 0. 2. 2. 1.]的原始分类是:1,划分分类是:1 208 | 记录[0. 2. 1. 2. 2. 1.]的原始分类是:1,划分分类是:1 209 | 记录[2. 2. 0. 2. 2. 1.]的原始分类是:1,划分分类是:1 210 | 记录[0. 1. 0. 2. 1. 0.]的原始分类是:1,划分分类是:1 211 | 记录[1. 1. 0. 1. 1. 0.]的原始分类是:1,划分分类是:1 212 | 记录[1. 1. 0. 2. 1. 1.]的原始分类是:1,划分分类是:1 213 | 记录[1. 1. 1. 1. 1. 1.]的原始分类是:0,划分分类是:0 214 | 记录[0. 0. 2. 2. 0. 0.]的原始分类是:0,划分分类是:0 215 | 记录[2. 0. 2. 0. 0. 1.]的原始分类是:0,划分分类是:0 216 | 记录[2. 2. 0. 0. 0. 0.]的原始分类是:0,划分分类是:0 217 | 记录[0. 1. 0. 1. 2. 1.]的原始分类是:0,划分分类是:0 218 | 记录[2. 1. 1. 1. 2. 1.]的原始分类是:0,划分分类是:0 219 | 记录[1. 1. 0. 2. 1. 0.]的原始分类是:0,划分分类是:0 220 | 记录[2. 2. 0. 0. 0. 1.]的原始分类是:0,划分分类是:0 221 | 记录[0. 2. 1. 1. 1. 1.]的原始分类是:0,划分分类是:0 222 | 错误率为: 0.000000 223 | ''' 224 | ``` 225 | 226 | 可以看出错误率为$0.000000$,正确率达到了$100%$。可以看出准确度不错,当然此准确度也与数据量的大小有关,后续可以将数据集扩大,或者使用不同的数据集进行训练测试,来验证分类效果。 227 | 228 | #### `Scikit-Learn`库进行`kNN`过程 229 | 230 | ```python 231 | import numpy as np 232 | from sklearn import neighbors 233 | 234 | data = [] 235 | labels = [] 236 | with open('841_01.txt') as ifile: 237 | for line in ifile: 238 | tokens = line.replace(',\n','').split(',') 239 | data.append([float(tk) for tk in tokens[:-1]]) 240 | labels.append(tokens[-1]) 241 | x = np.array(data) 242 | y = np.array(labels) 243 | 244 | clf = neighbors.KNeighborsClassifier(algorithm = 'kd_tree', n_neighbors = 1) 245 | clf.fit(x,y) 246 | 247 | answer = clf.predict(x) 248 | print('准确率为:%f' % float(np.mean(answer == y)))#正确率 249 | ``` 250 | 251 | 其准确率可以达到$100%$。 252 | 253 | 值得注意的是,上述`neighbors.KNeighborsClassifier()`中,存在很多可以自行调节的参数,这里可以查看官方文档(http://scikit-learn.org/stable/documentation.html) 并进行相关操作。 -------------------------------------------------------------------------------- /算法/README.md: -------------------------------------------------------------------------------- 1 | # 2. 算法 2 | 3 | ## 2.1 [数据结构](数据结构.md) 4 | 5 | ### 2.1.1 [线性表](数据结构.md#211-线性表) 6 | 7 | ### 2.1.2 [栈和队列](数据结构.md#212-栈和队列) 8 | 9 | ### 2.1.3 [二叉树和树](数据结构.md#213-二叉树和树) 10 | 11 | ## 2.2 [经典算法](经典算法.md) 12 | 13 | ### 2.2.1 [排序算法](经典算法.md#221-排序算法) 14 | 15 | ### 2.2.2 [查找算法](经典算法.md#222-查找算法) 16 | 17 | ### 2.2.3 [经典递归算法](经典算法.md#223-递归算法) 18 | 19 | ### 2.2.4 [穷举法](经典算法.md#224-穷举法) 20 | 21 | ### 2.2.5 [贪心法](经典算法.md#225-贪心法) 22 | 23 | ### 2.2.6 [动态规划](经典算法.md#226-动态规划) 24 | 25 | ### 2.2.7 [分治法](经典算法.md#227-分治法) 26 | 27 | ### 2.2.8 [回溯法](经典算法.md#228-回溯法) 28 | 29 | ### 2.2.9 [数学](经典算法.md#229-数学) 30 | 31 | ### 2.2.10 [图论](经典算法.md#2210-图论) 32 | 33 | ### 2.2.11 [其它](经典算法.md#2211-其它) 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /网络爬虫/HTML内容解析和BeautifulSoup.md: -------------------------------------------------------------------------------- 1 | ## 3.3 HTML内容解析和BeautifulSoup 2 | 3 | >date: 2019-02-05 4 | 5 | ![](../assets/images/33.jpg) 6 | 7 | ### 3.3.1 `HTML`解析器 8 | 9 | 解析`HTML`是一项自动化的工作,由(所谓的)HTML解析器执行。它们有两个主要目的: 10 | 11 | * `HTML`遍历:为程序员提供一个接口,来轻松地访问和修改“HTML代码”。 12 | 13 | * `HTML`清理:修正有语法错误的HTML,改善结果标记的布局和缩进样式。 14 | 15 | |解析器|使用方法|优势|劣势| 16 | |:--:|:--:|:--:|:--:| 17 | |`Python`标准库|`BeautifulSoup(markup, "html.parser")`|执行速度适中;文档容错能力强|`Python 2.7.3`或`3.2.2`前的版本中文文档的容错能力差| 18 | |`lxml HTML`解析器|`BeautifulSoup(markup, "lxml")`|速度快,文档容错能力强|需要安装`C`语言库| 19 | |`lxml XML`解析器|`BeautifulSoup(markup, ["lxml-xml"]);`
`BeautifulSoup(markup, "xml")`|速度快,唯一支持`XML`的解析器|需要安装`C`语言库| 20 | |`html5lib`|`BeautifulSoup(markup, "html5lib")`|最好的容错性,以浏览器的方式解析文档,生成`HTML5`格式的文档|速度慢,不依赖外部扩展| 21 | 22 | `BeautifulSoup`支持`Python`标准库中的`HTML`解析器,还支持上述的及清洗器。 23 | 24 | ### 3.3.2 `BeautifulSoup`简明教程 25 | 26 | `BeautifulSoup` 是一个可以从`HTML`或`XML`文件中提取数据的`Python`库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.`BeautifulSoup`会帮你节省数小时甚至数天的工作时间. 27 | 28 | * `HTML`结构 29 | 30 | `HTML`页面是由基本元素及属性组成的,其基本结构由文档类型声明、`html`标签对、`head`标签对、`body`标签对组成 31 | 32 | 1) 文档类型声明``是用来说明该文档是`HTML`文档,所有`HTML`文档开始于文档声明之后,说明了文档的类型以及其遵守的标准规范集。 33 | 34 | 2) `html`标签对是由成对的``组成的,其中``位于文档最前面,用来表示`HTML`文档的开始;``位于文档最后面,用来表示`HTML`文档的结束;中间的部分是文档的头部和主题。 35 | 36 | 3) ``标签对包含有关`HTML`文档的信息,可以包含一些辅助性标签,如``、`<base>`、`<link>`、`<meta>`、`<style>`、`<script>`等。 37 | 38 | 4) `<body>`标签对是`HTML`文档的主体部分,在此标签中可以包含`<p>`、`<h1>`、`<br>`等众多标签,`<body>`标签出现在`</head>`标签之后,且必须在闭标签`</html>`之前闭合。`<body>`标签中还有很多属性,用于设置文档的背景颜色、文本颜色、链接颜色、边距等。 39 | 40 | ```html 41 | <!DOCTYPE html> 42 | <html> 43 | <head> 44 | <meta charset="utf-8"/> 45 | <title>标题 46 | 47 | 48 |

段落

49 | 50 | 51 | ``` 52 | 53 | * `BeautifulSoup`对象 54 | 55 | ```python 56 | from bs4 import BeautifulSoup 57 | 58 | soup = BeautifulSoup(html_doc, 'html.parser') # BeautifulSoup 对象 59 | 60 | tag = soup.b # Tag 对象 61 | type(tag) # 62 | 63 | tag.name # Tag 对象名称 64 | 65 | tag['class'] # Tag 的属性 66 | tag.attrs 67 | 68 | tag.string # NavigableString 对象 69 | type(tag.string) # 70 | unicode_string = unicode(tag.string) # 将 NavigableString 对象转换成Unicode字符串 71 | tag.string.replace_with("No longer bold") # 替换成其它的字符串 72 | 73 | markup = "" 74 | soup = BeautifulSoup(markup) 75 | comment = soup.b.string # Comment 对象,特殊类型的 NavigableString 对象 76 | type(comment) # 77 | ``` 78 | 79 | * 指定文档解析器 80 | 81 | ```python 82 | from bs4 import BeautifulSoup 83 | 84 | soup = BeautifulSoup(html_doc, 'html.parser') 85 | soup = BeautifulSoup(html_doc, 'lxml') 86 | soup = BeautifulSoup(html_doc, 'html5lib') 87 | ``` 88 | 89 | * 标准缩进格式输出 90 | 91 | ```python 92 | from bs4 import BeautifulSoup 93 | 94 | soup = BeautifulSoup(html_doc, 'html.parser') 95 | 96 | print(soup.prettify()) 97 | ``` 98 | 99 | * 编码 100 | 101 | ```python 102 | from bs4 import BeautifulSoup 103 | 104 | markup = "

Sacr\xc3\xa9 bleu!

" 105 | soup = BeautifulSoup(markup) 106 | soup.h1 #

Sacré bleu!

107 | soup.h1.string # u'Sacr\xe9 bleu!' 108 | soup.original_encoding # 'utf-8' 获取自动编码的结果 109 | 110 | soup = BeautifulSoup(markup, from_encoding="iso-8859-8") # 指定编码方式 111 | 112 | soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"]) # 排除自动使用编码的格式 113 | 114 | # 通过Beautiful Soup输出文档时,不管输入文档是什么编码方式,输出编码均为UTF-8编码 115 | 116 | print(soup.prettify("latin-1")) # 指定编码方式输出 117 | print(soup.p.encode("latin-1")) 118 | ``` 119 | 120 | * 浏览`HTML`结构 121 | 122 | ```python 123 | from bs4 import BeautifulSoup 124 | 125 | soup = BeautifulSoup(html_doc, 'html.parser') 126 | 127 | soup.title 128 | 129 | soup.title.name 130 | 131 | soup.title.string 132 | 133 | soup.title.parent.name 134 | 135 | soup.p 136 | 137 | soup.p['class'] 138 | 139 | soup.a 140 | 141 | soup.find_all('a') 142 | 143 | soup.find(id="link3") 144 | 145 | for link in soup.find_all('a'): 146 | print(link.get('href')) 147 | 148 | soup.get_text() 149 | soup.get_text("|") # 指定tag内容的分隔符,u'\nI linked to |example.com|\n' 150 | soup.stripped_strings # 文本列表生成器 151 | ``` 152 | 153 | 参考链接: 154 | 155 | * [BeautifulSoup 文档](https://beautifulsoup.readthedocs.io/zh_CN/latest/) 156 | -------------------------------------------------------------------------------- /网络爬虫/README.md: -------------------------------------------------------------------------------- 1 | # 3. 网络爬虫 2 | 3 | ## 3.1 [从输入URL到打开网页](从输入URL到打开网页.md) 4 | 5 | ### 3.1.1 [当你在浏览器中输入google.com并且按下回车之后发生了什么?](从输入URL到打开网页.md#311-当你在浏览器中输入googlecom并且按下回车之后发生了什么) 6 | 7 | ### 3.1.2 [复习一遍计算机网络](从输入URL到打开网页.md#312-复习一遍计算机网络) 8 | 9 | ## 3.2 [网络资源请求和Requests](网络资源请求和Requests.md) 10 | 11 | ### 3.2.1 [“让HTTP服务于人类”](网络资源请求和Requests.md#321-让HTTP服务于人类) 12 | 13 | ### 3.2.2 [Requests简明教程](网络资源请求和Requests.md#322-Requests简明教程) 14 | 15 | ## 3.3 [HTML内容解析和BeautifulSoup](HTML内容解析和BeautifulSoup.md) 16 | 17 | ### 3.3.1 [HTML解析器](HTML内容解析和BeautifulSoup.md#331-HTML解析器) 18 | 19 | ### 3.3.2 [BeautifulSoup简明教程](HTML内容解析和BeautifulSoup.md#332-BeautifulSoup简明教程) 20 | 21 | ## 3.4 [动态网页请求](动态网页请求.md) 22 | 23 | ### 3.4.1 [Ajax和动态HTML](动态网页请求.md#341-Ajax和动态HTML) 24 | 25 | ### 3.4.2 [PhantomJS和Selenium](动态网页请求.md#342-PhantomJS和Selenium) 26 | 27 | ### 3.4.3 [Selenium简明教程](动态网页请求.md#343-Selenium简明教程) 28 | 29 | ## 3.5 [Scrapy](Scrapy.md) 30 | 31 | ### 3.5.1 [Scrapy架构](Scrapy.md#351-Scrapy架构) 32 | 33 | ### 3.5.2 [Scrapy简明教程](Scrapy.md#352-Scrapy简明教程) 34 | -------------------------------------------------------------------------------- /网络爬虫/Scrapy.md: -------------------------------------------------------------------------------- 1 | ## 3.5 `Scrapy` 2 | 3 | >date: 2019-02-11 4 | 5 | ![](../assets/images/35.jpg) 6 | 7 | ### 3.5.1 `Scrapy`架构 8 | 9 | `Scrapy`是一个为了爬取网站数据,提取结构性数据而编写的爬虫框架,使用了`Twisted`异步网络库来处理网络通讯。相较于`Requests` + `BeautifulSoup`组合成爬虫流水线,`Scrapy`更像是一个开箱即用的流水线。它更加偏向于生产环境下的爬虫,包含了下载器,解析器,日志,异常处理等等模块。它实现了更加高级的定制化,更加方便管理,灵活,可配置。 10 | 11 | ![Scrapy架构图](../assets/images/351_01.png) 12 | 13 | `Scrapy Engine`: 这是引擎,负责`Spiders`、`ItemPipeline`、`Downloader`、`Scheduler`中间的通讯,信号、数据传递等等! 14 | 15 | `Scheduler`(调度器): 它负责接受引擎发送过来的`requests`请求,并按照一定的方式进行整理排列,入队、并等待`Scrapy Engine`(引擎)来请求时,交给引擎。 16 | 17 | `Downloader`(下载器):负责下载`Scrapy Engine`(引擎)发送的所有`Requests`请求,并将其获取到的`Responses`交还给`Scrapy Engine`(引擎),由引擎交给`Spiders`来处理, 18 | 19 | `Spiders`:它负责处理所有`Responses`,从中分析提取数据,获取`Item`字段需要的数据,并将需要跟进的URL提交给引擎,再次进入`Scheduler`(调度器), 20 | 21 | `Item Pipeline`:它负责处理`Spiders`中获取到的`Item`,并进行处理,比如去重,持久化存储(存数据库,写入文件,总之就是保存数据用的) 22 | 23 | `Downloader Middlewares`(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件 24 | 25 | `Spider Middlewares`(`Spider`中间件):你可以理解为是一个可以自定扩展和操作引擎和`Spiders`中间‘通信‘的功能组件(比如进入`Spiders`的`Responses`;和从`Spiders`出去的`Requests`) 26 | 27 | **数据流过程:** 28 | 29 | 1) 引擎打开一个网站,找到处理该网站的`Spider`并向该`Spider`请求第一个要爬取的`URL(s)`。 30 | 31 | 2) 引擎从`Spider`中获取到第一个要爬取的`URL`并在调度器(`Scheduler`)以`Request`调度。 32 | 33 | 3) 引擎向调度器请求下一个要爬取的`URL`。 34 | 35 | 4) 调度器返回下一个要爬取的`URL`给引擎,引擎将`URL`通过下载中间件(请求`request`方向)转发给下载器(`Downloader`)。 36 | 37 | 5) 一旦页面下载完毕,下载器生成一个该页面的`Response`,并将其通过下载中间件(返回`response`方向)发送给引擎。 38 | 39 | 6) 引擎从下载器中接收到`Response`并通过`Spider`中间件(输入方向)发送给`Spider`处理。 40 | 41 | 7) `Spider`处理`Response`并返回爬取到的`Item`及(跟进的)新的`Request`给引擎。 42 | 43 | 8) 引擎将(`Spider`返回的)爬取到的`Item`给`Item Pipeline`,将(`Spider`返回的)`Request`给调度器。 44 | 45 | 9) (从第二步)重复直到调度器中没有更多的`request`,引擎关闭该网站。 46 | 47 | ### 3.5.2 `Scrapy`简明教程 48 | 49 | * 项目结构 50 | 51 | 安装完`Scrapy`后,在命令行中输入`scrapy startproject demo`,输入`cd demo`进入项目文件夹。 52 | 53 | 项目目录结构如下: 54 | 55 | ```shell 56 | ├── demo 57 | │   ├── __init__.py 58 | │   ├── items.py 59 | │   ├── middlewares.py 60 | │   ├── pipelines.py 61 | │   ├── __pycache__ 62 | │   ├── settings.py 63 | │   └── spiders 64 | │   ├── __init__.py 65 | │   └── __pycache__ 66 | └── scrapy.cfg 67 | ``` 68 | 69 | 在上面的目录结构中,`demo`是一个模块,所有的项目代码都在这个模块内定义并添加。 70 | 71 | 1) `items.py`是定义存储对象的文件,决定爬取哪些项目; 72 | 73 | 2) `middlewares.py`是中间件,一般不进行修改,主要负责组件之间的请求和响应; 74 | 75 | 3) `pipelines.py`是管道文件,决定爬取后的数据处理和存储; 76 | 77 | 4) `settings.py`是项目的设置文件,设置项目管道数据的处理文件、爬虫频率等。 78 | 79 | 5) `spiders`文件夹主要防止爬虫主题文件,用于实现爬虫逻辑。 80 | 81 | 6) `scrapy.cfg`是这个项目的配置文件,包括与项目设置的项目名称: 82 | 83 | ```shell 84 | # Automatically created by: scrapy startproject 85 | # 86 | # For more information about the [deploy] section see: 87 | # https://scrapyd.readthedocs.io/en/latest/deploy.html 88 | 89 | [settings] 90 | default = demo.settings # 项目的设置文件名 91 | 92 | [deploy] 93 | #url = http://localhost:6800/ 94 | project = demo # 项目名称 95 | ``` 96 | 97 | * 命令行 98 | 99 | ```shell 100 | scrapy startproject project_name # 创建新的项目 101 | 102 | cd project_name # 进入项目文件夹 103 | 104 | scrapy genspider mydomain mydomain.com # 创建一个spider 105 | 106 | scrapy fetch # 使用Scrapy下载器获取URL 107 | 108 | scrapy runspider # 运行独立的蜘蛛而不创建项目 109 | 110 | scrapy settings # 指定项目设置值 111 | 112 | scrapy shell # 给定URL的交互式抓取模块 113 | 114 | scrapy startproject # 创建一个新的Scrapy项目 115 | 116 | scrapy version # 显示Scrapy版本 117 | 118 | scrapy view # 使用Scrapy下载器获取URL并在浏览器中显示内容 119 | 120 | scrapy crawl # 用于抓取使用蜘蛛的数据 121 | 122 | scrapy check # 检查爬行命令返回的项目 123 | 124 | scrapy list # 显示项目中可用蜘蛛的列表 125 | 126 | scrapy edit # 可以使用编辑器编辑蜘蛛 127 | 128 | scrapy parse # 解析蜘蛛给定的URL 129 | 130 | scrapy bench # 用于运行快速基准测试(Benchmark指出Scrapy每分钟可以抓取多少页面) 131 | 132 | scrapy -h # 查看帮助 133 | ``` 134 | 135 | * 定义存储对象 136 | 137 | 打开`./demo/items.py`文件,在其中定义抓取的数据容器。它的工作像简单的`Python`,类似定义数据库中的栏位,来结构化、细化数据的归属。 138 | 139 | ```python 140 | import scrapy 141 | 142 | class DemoItem(scrapy.Item): 143 | # define the fields for your item here like: 144 | # name = scrapy.Field() 145 | title = scrapy.Field() 146 | content = scrapy.Field() 147 | author = scrapy.Field() 148 | create_time = scrapy.Field() 149 | ``` 150 | 151 | 例如在批量爬取文章的时候,在里面定义`scrapy.Field()`来指定对应的文章标题、文章内容、作者、创建时间、阅读量等等的定义,同时也能对未定义的字段提供填充功能防止出错。 152 | 153 | * 定义爬虫 154 | 155 | 以及通过`scrapy genspider mydomain mydomain.com`命令创建了一个爬虫类,进入`spides`文件夹后,打开`./spiders/mydomain.py`文件。 156 | 157 | ```python 158 | # -*- coding: utf-8 -*- 159 | import scrapy 160 | 161 | class MydomainSpider(scrapy.Spider): 162 | name = 'mydomain' 163 | allowed_domains = ['mydomain.com'] 164 | start_urls = ['http://mydomain.com/'] 165 | 166 | def parse(self, response): 167 | pass 168 | ``` 169 | 170 | 要建立一个爬虫,必须使用`scrapy.Spider`创建一个子类,并必须确定单个强制的属性`name, allowed_domains, start_urls`和一个方法`parse()`。 171 | 172 | 1) `name`是爬虫的名称,其它爬虫不能与其相同; 173 | 174 | 2) `allowed_domains`是搜索的域名范围,亦即爬虫的约束范围,规定只能爬取该域名下的网页,不存在的页面会被忽略掉; 175 | 176 | 3) `start_urls`需要爬取的`URL`的元祖/列表,爬虫从这里开始爬取,其他的子`URL`会从这些起始`URL`中生成; 177 | 178 | 4) `parse()`定义解析的方法,解析`response`,提取结构化数据,即生成`item`;同时生成下一页`URL`请求。 179 | 180 | 由上添加`parse_item()`方法。 181 | 182 | ```python 183 | # -*- coding: utf-8 -*- 184 | import scrapy 185 | from ..items import DemoItem 186 | 187 | class MydomainSpider(scrapy.Spider): 188 | name = 'mydomain' 189 | allowed_domains = ['mydomain.com'] 190 | start_urls = ['http://mydomain.com/'] 191 | 192 | def parse(self, response): 193 | urls = response.xpath('') 194 | for url in urls: 195 | yield scrapy.Request(url, callback = self.parse_item) # 发送请求。回调给parse_item处理 196 | 197 | def parse_item(self, response): 198 | item = DemoItem() 199 | item['title'] = response.xpath('') 200 | item['content'] = response.xpath('') 201 | item['author'] = response.xpath('') 202 | item['create_time'] = response.xpath('') 203 | ``` 204 | 205 | 命令行键入`scrapy crawl mydomain -o mydomain.csv`即可以开始进行采集。 206 | 207 | * 定义存储 208 | 209 | 当`item`在`Spider`中被手机后,会被传递给`pipeline`,其按照定义的顺序处理`item`。 210 | 211 | `pipeline`大多数用于验证爬取的数据,对数据进行查重,将数据进行持久化等。 212 | 213 | ```python 214 | # -*- coding: utf-8 -*- 215 | from scrapy.exceptions import DropItem 216 | 217 | class MydomainPipeline(object): 218 | def process_item(self, item, spider): 219 | if item['author']: 220 | # processing 221 | return item 222 | else: 223 | raise DropItem("Missing author in %s" % item) 224 | ``` 225 | 226 | * 选择器 227 | 228 | 在定义`spider`时候,需要在`HTML`提取数据,`Scarpy`是基于`lxml`构建选择器的,它提供了下面四个基本方法: 229 | 230 | 1) `xpath()`传入[`xpath`](http://www.w3school.com.cn/xpath/index.asp)表达式,返回该表达式所对应的所有节点的列表; 231 | 232 | 2) `extract()`序列化该节点为`Unicode`字符串并返回列表; 233 | 234 | 3) `css()`传入`CSS`表达式,返回表达式对应所有节点的列表; 235 | 236 | 4) `re()`传入正则表达式,返回`Unicode`字符串并返回列表。 237 | 238 | * 设置文件 239 | 240 | 对于整个爬虫工程,`Scrapy`使用`settings.py`进行配置,常见的配置项如下: 241 | 242 | ```python 243 | # -*- coding: utf-8 -*- 244 | 245 | BOT_NAME = 'demo' # Scrapy项目的名字,这将用来构造默认 User-Agent,同时也用来log,当您使用 startproject 命令创建项目时其也被自动赋值。 246 | 247 | SPIDER_MODULES = ['demo.spiders'] # Scrapy搜索spider的模块列表 默认: [xxx.spiders] 248 | NEWSPIDER_MODULE = 'demo.spiders' # 使用 genspider 命令创建新spider的模块。默认: 'xxx.spiders' 249 | 250 | USER_AGENT = 'demo (+http://www.mydomain.com)' # 爬取的默认User-Agent,除非被覆盖 251 | 252 | ROBOTSTXT_OBEY = True # 如果启用, Scrapy将会采用 robots.txt 策略 (https://baike.baidu.com/item/robots%E5%8D%8F%E8%AE%AE/2483797?fr=aladdin&fromid=9518761&fromtitle=robots.txt) 253 | 254 | CONCURRENT_REQUESTS = 32 # Scrapy downloader 并发请求(concurrent requests)的最大值,默认: 16 255 | 256 | DOWNLOAD_DELAY = 3 # 为同一网站的请求配置延迟(默认值:0)。下载器在下载同一个网站下一个页面前需要等待的时间,该选项可以用来限制爬取速度,减轻服务器压力。同时也支持小数:0.25 以秒为单位 257 | 258 | # 下载延迟设置只有一个有效 259 | CONCURRENT_REQUESTS_PER_DOMAIN = 16 # 对单个网站进行并发请求的最大值。 260 | CONCURRENT_REQUESTS_PER_IP = 16 # 对单个IP进行并发请求的最大值。如果非0,则忽略 CONCURRENT_REQUESTS_PER_DOMAIN 设定,使用该设定。也就是说,并发限制将针对IP,而不是网站。该设定也影响 DOWNLOAD_DELAY: 如果 CONCURRENT_REQUESTS_PER_IP 非0,下载延迟应用在IP而不是网站上。 261 | 262 | COOKIES_ENABLED = False # 禁用Cookie(默认情况下启用) 263 | 264 | TELNETCONSOLE_ENABLED = False # 禁用Telnet控制台(默认启用) 265 | 266 | DEFAULT_REQUEST_HEADERS = { # 覆盖默认请求标头: 267 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 268 | 'Accept-Language': 'en', 269 | } 270 | 271 | SPIDER_MIDDLEWARES = { # 启用或禁用蜘蛛中间件 272 | 'demo.middlewares.DemoSpiderMiddleware': 543, 273 | } 274 | 275 | DOWNLOADER_MIDDLEWARES = { # 启用或禁用下载器中间件 276 | 'demo.middlewares.MyCustomDownloaderMiddleware': 543, 277 | } 278 | 279 | EXTENSIONS = { # 启用或禁用扩展程序 280 | 'scrapy.extensions.telnet.TelnetConsole': None, 281 | } 282 | 283 | ITEM_PIPELINES = { # 配置项目管道 284 | 'demo.pipelines.MydomainPipeline': 300, 285 | } 286 | 287 | AUTOTHROTTLE_ENABLED = True # 启用和配置AutoThrottle扩展(默认情况下禁用) 288 | 289 | AUTOTHROTTLE_START_DELAY = 5 # 初始下载延迟 290 | 291 | AUTOTHROTTLE_MAX_DELAY = 60 # 在高延迟的情况下设置的最大下载延迟 292 | 293 | AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 # Scrapy请求的平均数量应该并行发送每个远程服务器 294 | 295 | AUTOTHROTTLE_DEBUG = False # 启用显示所收到的每个响应的调节统计信息: 296 | 297 | # 启用和配置HTTP缓存(默认情况下禁用) 298 | HTTPCACHE_ENABLED = True 299 | HTTPCACHE_EXPIRATION_SECS = 0 300 | HTTPCACHE_DIR = 'httpcache' 301 | HTTPCACHE_IGNORE_HTTP_CODES = [] 302 | HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage' 303 | ``` 304 | 305 | 参考链接: 306 | 307 | * [Scrapy 文档](https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/overview.html) -------------------------------------------------------------------------------- /网络爬虫/从输入URL到打开网页.md: -------------------------------------------------------------------------------- 1 | ## 3.1 从输入URL到打开网页 2 | 3 | >date: 2019-02-02 4 | 5 | ![](../assets/images/31.jpg) 6 | 7 | ### 3.1.1 当你在浏览器中输入google.com并且按下回车之后发生了什么? 8 | 9 | [答案](https://github.com/skyline75489/what-happens-when-zh_CN) 10 | 11 | ![](../assets/images/311_01.jpg) 12 | 13 | ### 3.1.2 复习一遍计算机网络 14 | 15 | ##### 1) 识别URL 16 | 17 | 完整的`URL`是由协议:`http`,`ftp`、域名:http://www.google.com、文件路径:/htm_data/20/1510/1441477.html和 18 | 端口:`80`,四个部分组成的。 19 | 20 | ##### 2) DNS查询 21 | 22 | (1) 检查本地`hosts`文件是否有`URL`与`IP`地址的映射,如果有返回`IP`,解析完成; 23 | 24 | (2) 如果本地`hosts`文件没有,则查找本地`DNS`解析器缓存是否有这个`URL`的映射,如果有返回`IP`,解析完成; 25 | 26 | (3) 如果没有,则查找填写或分配的首选`DNS`服务器,称为本地`DNS`服务器。 27 | 28 | 服务器接收到查询时,如果要查询的域名包含在本地配置区域资源中,返回解析结果,查询结束,此解析具有权威性; 29 | 30 | 如果要查询的域名不由本地`DNS`服务器区域解析,但服务器缓存了此`URL`的映射关系,返回解析结果,查询结束,此解析不具有权威性。 31 | 32 | (5) 如果本地`DNS`服务器也失效。 33 | 34 | 如果未采用转发模式(迭代),本地`DNS`就把请求发至`13`台根`DNS`,根`DNS`服务器收到请求后,会判断这个域名(如`.com`)是谁来授权管理,并返回一个负责该顶级域名服务器的`IP`,本地`DNS`服务器收到顶级域名服务器`IP`信息后,继续向该顶级域名服务器`IP`发送请求,该服务器如果无法解析,则会找到负责这个域名的下一级`DNS`服务器(如`http://google.com`)的`IP`给本地`DNS`服务器,循环往复直至查询到映射,将解析结果返回本地`DNS`服务器,再由本地`DNS`服务器返回解析结果,查询完成; 35 | 36 | 如果采用转发模式(递归),则此`DNS`服务器就会把请求转发至上一级`DNS`服务器,如果上一级`DNS`服务器不能解析,则继续向上请求。最终将解析结果依次返回本地DNS服务器,本地`DNS`服务器再返回给客户机,查询完成。 37 | 38 | ##### 3) 客户端发送HTTP请求报文 39 | 40 | (1) 建立[`TCP`连接](../Python高级编程/网络编程.md#133-tcp协议),**三次握手**; 41 | 42 | (2) 发起`http`请求,等待服务端响应。 43 | 44 | ##### 4) 服务端发送HTTP响应报文 45 | 46 | (1) 服务端响应`HTTP`请求,返回响应的`html`文件或数据给客户端; 47 | 48 | (2) 客户端对`html`代码进行解析并请求响应的资源与数据; 49 | 50 | (3) 客户端将请求到的`html`代码和静态资源渲染呈现给用户; 51 | 52 | (4) 不再需要传输数据,进行**四次挥手**。 53 | -------------------------------------------------------------------------------- /网络爬虫/动态网页请求.md: -------------------------------------------------------------------------------- 1 | ## 3.4 动态网页请求 2 | 3 | >date: 2019-02-10 4 | 5 | ![](../assets/images/34.jpg) 6 | 7 | ### 3.4.1 `Ajax`和动态`HTML` 8 | 9 | 现代的网页技术在不断发展,网页的加载也更加讲究实时性和安全性,界面交互也更加完善与人性化,进行爬虫采集的数据当然不可能只是局限于以前的静态页面或者简单的`HTML`代码。 10 | 11 | `Ajax`全称`Asynchronous JavaScript and XML`是一种能够不需要单独的页面就能与网络服务器进行交互的技术,它能够在不重新加载整个页面的情况下,与服务器完成数据交互并更新网页的部分内容。 12 | 13 | 同时现在随着`NodeJS`的逐渐成熟,越来越多`Web`开发都逐渐变成了前后端分离的架构模式,其通过一些`HTTP`或其它协议进行交互请求,从而实现动态的`HTML`加载。 14 | 15 | 爬虫的最终目的在于获取目标数据,通过浏览器加载网页页面,相应分析前端与后端进行的交互是十分重要的。 16 | 17 | ### 3.4.2 `PhantomJS`和`Selenium` 18 | 19 | 如何让代码去模拟人浏览网页的动作?`Selenium`是为网站自动化测试而开发的,它直接运行在浏览器中,像真正的用户的操作一样。可以直接将其理解为一个浏览网页的机器人。 20 | 21 | 有了浏览者,还需要一个浏览器,同时需要让浏览的过程在后台运行,这时候就需要`PhantomJS`了,它是一个浏览器环境,内核是`WebKit`引擎,不提供图形界面。 22 | 23 | `PhantomJS`负责渲染解析`JavaScript`,`Selenium`负责驱动浏览器以及和`Python`交互,`Python`负责后期处理。 24 | 25 | ### 3.4.3 `Selenium`简明教程 26 | 27 | * 创建浏览器对象 28 | 29 | ```python 30 | from selenium import webdriver 31 | 32 | driver = webdriver.PhantomJS(executable_path='/path/to/phantomjs') 33 | driver = webdriver.Firefox() 34 | driver = webdriver.Chrome() 35 | 36 | driver.close() 37 | ``` 38 | 39 | * 打开一个页面 40 | 41 | ```python 42 | from selenium import webdriver 43 | 44 | driver = webdriver.PhantomJS(executable_path='/path/to/phantomjs') 45 | 46 | driver.get("http://www.google.com") 47 | 48 | driver.close() 49 | ``` 50 | 51 | * 查找元素 52 | 53 | ```python 54 | from selenium.webdriver.common.by import By 55 | 56 | driver.find_element(By.XPATH, '//button[text()="Some text"]') 57 | driver.find_elements(By.XPATH, '//button') 58 | ``` 59 | 60 | > ID = "id" 61 | > 62 | > XPATH = "xpath" 63 | > 64 | > LINK_TEXT = "link text" 65 | > 66 | > PARTIAL_LINK_TEXT = "partial link text" 67 | > 68 | > NAME = "name" 69 | > 70 | > TAG_NAME = "tag name" 71 | > 72 | > CLASS_NAME = "class name" 73 | > 74 | > CSS_SELECTOR = "css selector" 75 | > 76 | 77 | ```html 78 | 79 | 80 |
81 | 82 | 83 | 84 | 85 |
86 | 87 |

Are you sure you want to do this?

88 | Continue 89 | Cancel 90 | 91 |

Welcome

92 |

Site content goes here.

93 | 94 |

Site content goes here.

95 | 96 |

Site content goes here.

97 | 98 | 99 | 100 | ``` 101 | 102 | ```python 103 | element = driver.find_element_by_id("passwd-id") # 通过ID查找元素 104 | 105 | element = driver.find_element_by_name("passwd") # 通过Name查找元素 106 | 107 | element = driver.find_element_by_xpath("//input[@id='passwd-id']") # 通过XPath查找元素 108 | 109 | element = driver.find_element_by_link_text('Continue') # 通过链接文本获取超链接 110 | element = driver.find_element_by_partial_link_text('Conti') 111 | 112 | element = driver.find_element_by_tag_name('h1') # 通过标签名查找元素 113 | 114 | element = driver.find_element_by_class_name('content') # 通过Class name 定位元素 115 | 116 | element = driver.find_element_by_css_selector('p.content') # 通过CSS选择器查找元素 117 | ``` 118 | 119 | 一次查找多个元素 (这些方法会返回一个list列表): 120 | 121 | ```python 122 | find_elements_by_name 123 | find_elements_by_xpath 124 | find_elements_by_link_text 125 | find_elements_by_partial_link_text 126 | find_elements_by_tag_name 127 | find_elements_by_class_name 128 | find_elements_by_css_selector 129 | ``` 130 | 131 | * 输入内容 132 | 133 | ```python 134 | from selenium.webdriver.common.keys import Keys 135 | 136 | element = driver.find_element_by_id("passwd-id") 137 | element.send_keys("some text") 138 | element.send_keys(" and some", Keys.ARROW_DOWN) 139 | element.clear() # 清除内容 140 | ``` 141 | 142 | * 选择下拉列表 143 | 144 | ```python 145 | from selenium.webdriver.support.ui import Select 146 | 147 | select = Select(driver.find_element_by_name('name')) 148 | select.select_by_index(index) 149 | select.select_by_visible_text("text") 150 | select.select_by_value(value) 151 | 152 | all_selected_options = select.all_selected_options # 获得所有选项 153 | options = select.options 154 | 155 | select = Select(driver.find_element_by_id('id')) # 清除选项 156 | select.deselect_all() 157 | ``` 158 | 159 | * 页面等待 160 | 161 | 1) 显示等待 162 | 163 | ```python 164 | from selenium import webdriver 165 | from selenium.webdriver.common.by import By 166 | from selenium.webdriver.support.ui import WebDriverWait 167 | from selenium.webdriver.support import expected_conditions as EC 168 | 169 | driver = webdriver.Firefox() 170 | driver.get("http://somedomain/url_that_delays_loading") 171 | try: 172 | element = WebDriverWait(driver, 10).until( 173 | EC.presence_of_element_located((By.ID, 174 | "myDynamicElement"))) 175 | finally: 176 | driver.quit() 177 | ``` 178 | 179 | 2) 隐式等待 180 | 181 | ```python 182 | from selenium import webdriver 183 | 184 | driver = webdriver.Firefox() 185 | driver.implicitly_wait(10) 186 | driver.get("http://somedomain/url_that_delays_loading") 187 | myDynamicElement = driver.find_element_by_id("myDynamicElement") 188 | ``` 189 | 190 | 参考链接: 191 | 192 | * [Selenium-Python中文文档](https://selenium-python-zh.readthedocs.io/en/latest/index.html) -------------------------------------------------------------------------------- /网络爬虫/网络资源请求和Requests.md: -------------------------------------------------------------------------------- 1 | ## 3.2 网络资源请求和Requests 2 | 3 | >date: 2019-02-05 4 | 5 | ![](../assets/images/32.jpg) 6 | 7 | ### 3.2.1 “让HTTP服务于人类” 8 | 9 | 虽然`Python`标准库中的`urllib`模块已经包含了平常平常我们使用的大多数`HTTP`功能,但是它的`API`使用起来并不自然。[`Kenneth Reitz`](https://www.kennethreitz.org/)大神帮我们准备了一个优雅而简单的`HTTP`库——[`Requests`](https://github.com/requests/requests)。 10 | 11 | ![Requests库](../assets/images/321_01.png) 12 | 13 | 互联网的发展让人类获取数据更加地方便,但在繁杂的数据背景下,人类需要自己去组织获取这些繁杂的数据是一件工作量颇大的事情,网络爬虫就是为了解决这种事情而出现的。 14 | 15 | `Requests`库旨在简化`HTTP`请求的过程,针对抓取目标的描述和定义,我们利用其制定规则去爬取,然后对获得的数据和网页进行分析与过滤,得到的数据最终能用于其它用途。 16 | 17 | ### 3.2.2 Requests简明教程 18 | 19 | * `get`请求 20 | 21 | ```python 22 | import requests 23 | 24 | r = requests.get('http://httpbin.org/ip') 25 | ``` 26 | 27 | * 构造`url` 28 | 29 | >http://httpbin.org/get?key1=value1&key2=value2 30 | 31 | 构造`url`的请求参数,即`?`后的`query string`。 32 | 33 | ```python 34 | import requests 35 | 36 | d = {'key1': 'value1', 'key2': 'value2'} 37 | r = requests.get('http://httpbin.org/get', params=d) 38 | print(r.url) 39 | ``` 40 | 41 | * 响应正文文本 42 | 43 | ```python 44 | import requests 45 | 46 | r = requests.get('http://httpbin.org/ip') 47 | 48 | print(r.text) 49 | print(r.encoding) 50 | ``` 51 | 52 | * 二进制响应对象 53 | 54 | ```python 55 | import requests 56 | 57 | r = requests.get('http://httpbin.org/ip') 58 | 59 | print(r.content) 60 | ``` 61 | 62 | * `JSON`响应正文 63 | 64 | ```python 65 | import requests 66 | 67 | r = requests.get('http://httpbin.org/ip') 68 | 69 | print(r.json()) 70 | print(type(r.json())) 71 | ``` 72 | 73 | * 响应状态 74 | 75 | ```python 76 | import requests 77 | 78 | r = requests.get('http://httpbin.org/ip') 79 | 80 | print(r.status_code) 81 | print(r.raise_for_status()) # 响应返回404,使用该语句抛出异常 82 | ``` 83 | 84 | * 响应头 85 | 86 | ```python 87 | import requests 88 | 89 | r = requests.get('http://httpbin.org/ip') 90 | 91 | print(r.headers) 92 | ``` 93 | 94 | * 定制请求头 95 | 96 | ```python 97 | import requests 98 | 99 | url = 'http://httpbin.org/headers' 100 | 101 | headers = {'user-agent': 'test/0.0.1'} 102 | 103 | r = requests.get(url, headers = headers) 104 | print(r.text) 105 | ``` 106 | 107 | * `post`请求——`form`表单形式 108 | 109 | ```python 110 | import requests 111 | 112 | url = 'http://httpbin.org/post' 113 | d = {'key1': 'value1', 'key2': 'value2'} 114 | r = requests.post(url, data = d) 115 | print(r.text) 116 | ``` 117 | 118 | * `post`请求——`JSON`字符串形式 119 | 120 | ```python 121 | import requests 122 | 123 | url = 'http://httpbin.org/post' 124 | s = json.dumps({'key1': 'value1', 'key2': 'value2'}) 125 | r = requests.post(url, data = s) 126 | print(r.text) 127 | ``` 128 | 129 | * `post`请求——`multipart`形式 130 | 131 | ```python 132 | import requests 133 | 134 | url = 'http://httpbin.org/post' 135 | files = {'file': open('report.txt', 'rb')} 136 | r = requests.post(url, files = files) 137 | print(r.text) 138 | ``` 139 | 140 | * 获取`cookies` 141 | 142 | ```python 143 | import requests 144 | 145 | url = 'http://httpbin.org/post' 146 | r = requests.get(url) 147 | print(r.cookies) 148 | ``` 149 | 150 | * 带`cookies`请求 151 | 152 | ```python 153 | import requests 154 | 155 | url = 'http://httpbin.org/cookies' 156 | cookies = {'cookies_are': 'test'} 157 | r = requests.get(url, cookies = cookies) 158 | print(r.text) 159 | ``` 160 | 161 | * 设置请求超时 162 | 163 | ```python 164 | import requests 165 | 166 | url = 'http://httpbin.org/get' 167 | r = requests.get(url, timeout = 0.001) 168 | print(r.raise_for_status()) 169 | ``` 170 | 171 | * 常见异常 172 | 173 | 1) `ConnectionError` 由于网络原因,无法建立连接。 174 | 175 | 2) `HTTPError` 如果响应的状态码不为200,`Response.raise_for_status()`会抛出`HTTPError`异常。 176 | 177 | 3) `Timeout` 超时异常。 178 | 179 | 4) `TooManyRedirects` 若请求超过了设定的最大重定向次数,则会抛出一个 TooManyRedirects 异常。 180 | 181 | 所有requests抛出的异常都继承自`requests.exceptions.RequestException`类。 182 | -------------------------------------------------------------------------------- /题目整理/README.md: -------------------------------------------------------------------------------- 1 | # 题目整理 2 | 3 | ## [算法与数据结构](算法与数据结构.md) --------------------------------------------------------------------------------