├── .gitignore ├── 1.md ├── 10.md ├── 11.md ├── 12.md ├── 13.md ├── 14.md ├── 15.md ├── 16.md ├── 17.md ├── 18.md ├── 19.1.md ├── 19.2.md ├── 2.md ├── 20.md ├── 21.md ├── 3.md ├── 4.md ├── 5.md ├── 6.md ├── 7.md ├── 8.md ├── 9.md ├── README.md ├── SUMMARY.md ├── img ├── 05fb264e8717acd28d1574bee4090029.jpg ├── 19274741dc836a609c2722cd32770692.jpg ├── 2cdf1de23dbb6214dfbadd6865c464b0.jpg ├── 3375cf9c5dcba56ec89d3c109d477b42.jpg ├── 33ac24c354a4ffba2cf95d531aa2f4dd.jpg ├── 371afefc20188fb5874a852c50bce6c5.jpg ├── 37cf1c7a62127199e6e8580d9d1e6248.jpg ├── 3c3fec0241cfa4c4f5bb78c571a0f884.jpg ├── 3e9f30437a269befbe80859ffe27537e.jpg ├── 3eb344ac521726353def27e303517ba9.jpg ├── 3f0ca2e88676e335b8b20523ff94fec7.jpg ├── 3f439b203d4e179a2c15c84d3bb15cb7.jpg ├── 41b5b4e4857f15a32a484b8b4e3afbbc.jpg ├── 44cffe94ab676a80cb08e22bc19fb02d.jpg ├── 467a25fe9ed0bcdf31a140a351b7865c.jpg ├── 4c2e42ce1e09d07bd5b30da33b4adf2f.jpg ├── 502eebaffff7022fe6dd5b4a3f901d71.jpg ├── 5077893a199a7192498596a047d24c48.jpg ├── 53a181f79fb487549a6006294f7bc879.jpg ├── 54fd49268017a7b697a4eee7c911d969.jpg ├── 6516b9606dafb489e601dc4dcee9eb11.jpg ├── 65334cd1b4791a63cb320a2f2fa44ac1.jpg ├── 7592106e9633ec8a8fb6e14c1f2a2d0b.jpg ├── 797049479fae3d337256efa33157af1a.jpg ├── 7e623fe011680e01bfceb81efe4cff72.jpg ├── 89fdaf9caa2b88f10c2e281f0071ab1e.jpg ├── 99cac4640cc847b6e1e8c94a3d85d7cc.jpg ├── a98f870fa95d64ec22552e8db8a4dd7f.jpg ├── b069822c94e45cd78df010400c327e27.jpg ├── b83cb13103af990e41eaf7253c0018e9.jpg ├── bc7d72780c8296115ef744873807d5ff.jpg ├── bce11f1812038907dfc04afe063b942e.jpg ├── bd066f4a27e6863c89a4df513959be98.jpg ├── c936cfb9b6729010955e67e7aa51a4de.jpg ├── cd28dcfca524b96afc6ddf81d6f0c298.jpg ├── d3a827df8e9eb16e33ce7b3f670941fb.jpg ├── d86fdc26f2d0ab274ac8164975cc622b.jpg ├── dae1a905b9e7104ebcacfa982c3c9a5c.jpg ├── e78c54ef3d6a719f1ffa6a538f9353de.jpg ├── ec18cd723a8b269d960ff8c900a113eb.jpg ├── tex-020a9f6f179050a671f6f6f28169b20d.gif ├── tex-02129bb861061d1a052c592e2dc6b383.gif ├── tex-08ab6c8d7eefc2ed7722b28e671aa0bc.gif ├── tex-08c711a5590de57d9dd77d7b5ba4398f.gif ├── tex-09663031eaa8ade66806d053272e579c.gif ├── tex-0d61f8370cad1d412f80b84d143e1257.gif ├── tex-10ac877830803e44c3b7dc1b104101dd.gif ├── tex-18daef71b5d25ce76b8628a81e4fc76b.gif ├── tex-1a68df3b73be15a6da50bd6cfdba832a.gif ├── tex-1aa7c4b9ac179483858f457df9ee441b.gif ├── tex-1ae38954f6cba2eafda4e9c34df8d944.gif ├── tex-272ba5cfd2789d670bc65e40587345c3.gif ├── tex-2b30ddf4881c9acfc3bc0cf2880eefaa.gif ├── tex-2f728dbcde765f5a357bce9752c0d878.gif ├── tex-31f830c208ca5fcbf1bca34de8d796a6.gif ├── tex-347685e5ebc84836b7aea484b48eb555.gif ├── tex-363b122c528f54df4a0446b6bab05515.gif ├── tex-41410fd2b1e89fe55a7638312d82540c.gif ├── tex-415290769594460e2e485922904f345d.gif ├── tex-45fe873d5f83badc655eed13e1cd8ee8.gif ├── tex-46277250c0e8d4fadf188d0d22fa1343.gif ├── tex-48d71f5dc3c36e27922ff67fe9e88c6e.gif ├── tex-4aa861124eff57dd7988faa6753e8b7e.gif ├── tex-50d7cc01f0e1e57d81240e646606b14a.gif ├── tex-52539b56794b13d260a84f3461c80f49.gif ├── tex-55ddce33f44e17960c51e0b727ed0c1b.gif ├── tex-5765c72ae234bd48dadb3a8bfd20580b.gif ├── tex-5af9e28d609b16eb25693f44ea9d7a8f.gif ├── tex-5e956d2dac25a04b1f0384a339af61de.gif ├── tex-5fdb0734a2a8679264029c65df7a492b.gif ├── tex-682edd15f544ef9727367918185ee5f4.gif ├── tex-68ce6a2b5a771f689d84ac8e24e31ddf.gif ├── tex-6959801ea921957ed53ddaab936b9409.gif ├── tex-69c694c13d6cb056f400aff019f023dd.gif ├── tex-6b5a5f025640932b2554f6d400b3e45f.gif ├── tex-6b5eaa31568b521152a5aacec91548c2.gif ├── tex-6fbdf291cda891b99cf211417ad1df18.gif ├── tex-6fe2793f9b6ee038f11e89402bbf3c84.gif ├── tex-7015ea99e7b80644c1630cdfb0f6bbda.gif ├── tex-70e59a996bd69a0c21878b4093375e92.gif ├── tex-777eeb07996381e00006e77dd1aaf39f.gif ├── tex-7b7f9dbfea05c83784f8b85149852f08.gif ├── tex-7b8b965ad4bca0e41ab51de7b31363a1.gif ├── tex-7d627c4584744c44dde8a2e35bcfb90c.gif ├── tex-7e18dabda345d4f3a3642ecf7fa61ccf.gif ├── tex-7fc56270e7a70fa81a5935b72eacbe29.gif ├── tex-83878c91171338902e0fe0fb97a8c47a.gif ├── tex-865c0c0b4ab0e063e5caa3387c1a8741.gif ├── tex-8a842403dafad0ee564a1a212d19e77a.gif ├── tex-8c06f77a048c7032b6258f4ceddcac77.gif ├── tex-8ce4b16b22b58894aa86c421e8759df3.gif ├── tex-8d62e469fb30ed435a668eb5c035b1f6.gif ├── tex-8f43fce8dbdf3c4f8d0ac91f0de1d43d.gif ├── tex-8fa14cdd754f91cc6554c9e71929cce7.gif ├── tex-9081cb9b8d4cd5ee177a3287608f7424.gif ├── tex-99600e95adcc97c986df86d4b612cf52.gif ├── tex-9a7cc99da8feacd5e7efd172ae2b9b5d.gif ├── tex-9d5ed678fe57bcca610140957afab571.gif ├── tex-9dd4e461268c8034f5c8564e155c67a6.gif ├── tex-9ed438b9777ace57e974cb63995679ed.gif ├── tex-a061b9ec570e172274d24a31b7f2ec4e.gif ├── tex-a276b69c27fa2fc5adb0a238cb21baa3.gif ├── tex-a438673491daae8148eae77373b6a467.gif ├── tex-a57d522c3188c5cf8f0818e9d1a2946b.gif ├── tex-a5f3c6a11b03839d46af9fb43c97c188.gif ├── tex-a6b711ff5b6087f86069d31ba049add7.gif ├── tex-a97118fb9e8d7e006a466bfc0771f888.gif ├── tex-ad6d5470eaff252c993327c248d56b0e.gif ├── tex-b3d4a2c5b40d7af881f9d19730b6ea7c.gif ├── tex-b4ceec2c4656f5c1e7fc76c59c4f80f3.gif ├── tex-b6253f470c6bf31d67e04d80d43704be.gif ├── tex-bde5f474d3e4c7e38ddd6440a38a7f4e.gif ├── tex-c39d1645d55ca4afb20c8d6a365615bb.gif ├── tex-c9f6d8557ce40f989fa727b5c0bb1ddf.gif ├── tex-cea485c1212579d0e0fb0f665f5a85dd.gif ├── tex-d5530fdea73b725bbdb348dee89e4a20.gif ├── tex-d5cd57541fb4b75d5fdbd688f87323d5.gif ├── tex-d8dd7d0f3eb7145ca41c711457b7eb8f.gif ├── tex-d945100c5fa6a400570dcacfb1fc9869.gif ├── tex-dabc824c5f8ee13faaae5a59fec9afdc.gif ├── tex-ddc7076014b85741e2dbfe52ec40ed52.gif ├── tex-de3f198290bfe64e8e3f289f20c44434.gif ├── tex-e125e16b9b9b9a753459b31c44e565da.gif ├── tex-e1671797c52e15f763380b45e841ec32.gif ├── tex-e5a7472d780a5a032c7775cc5e3ce901.gif ├── tex-e8100be07fa5419af6c6738b934dfca0.gif ├── tex-ea7e2e0d45588bedd672db7688459b46.gif ├── tex-ecc57614c202a2c740598474fdbbb88e.gif ├── tex-f8281cafb08efe03bce3816f00fdd12d.gif ├── tex-f9a3b8e9e501458e8face47cae8826de.gif ├── tex-fc3b69ffc2761499a8f26feaaf2f3057.gif └── tex-fd6a329594a8718f6de1a6d5728eb7b7.gif ├── src └── process_tex.js └── styles └── ebook.css /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | .DS_Store 103 | 104 | # gitbook 105 | _book 106 | 107 | # node.js 108 | node_modules 109 | 110 | # windows 111 | Thumbs.db 112 | 113 | # word 114 | ~$*.docx 115 | ~$*.doc 116 | -------------------------------------------------------------------------------- /1.md: -------------------------------------------------------------------------------- 1 | # 一、向量、矩阵和数组 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 转置矩阵或向量 10 | 11 | ```py 12 | # 加载库 13 | import numpy as np 14 | 15 | # 创建向量 16 | vector = np.array([1, 2, 3, 4, 5, 6]) 17 | 18 | # 创建矩阵 19 | matrix = np.array([[1, 2, 3], 20 | [4, 5, 6], 21 | [7, 8, 9]]) 22 | 23 | # 转置向量 24 | vector.T 25 | 26 | # array([1, 2, 3, 4, 5, 6]) 27 | 28 | # 转置矩阵 29 | matrix.T 30 | 31 | ''' 32 | array([[1, 4, 7], 33 | [2, 5, 8], 34 | [3, 6, 9]]) 35 | ''' 36 | ``` 37 | 38 | ## 选择数组中的元素 39 | 40 | ```py 41 | # 加载库 42 | import numpy as np 43 | 44 | # 创建行向量 45 | vector = np.array([1, 2, 3, 4, 5, 6]) 46 | 47 | # 选择第二个元素 48 | vector[1] 49 | 50 | # 2 51 | 52 | # 创建矩阵 53 | matrix = np.array([[1, 2, 3], 54 | [4, 5, 6], 55 | [7, 8, 9]]) 56 | 57 | # 选择第二行第二列 58 | matrix[1,1] 59 | 60 | # 5 61 | 62 | # 创建矩阵 63 | tensor = np.array([ 64 | [[[1, 1], [1, 1]], [[2, 2], [2, 2]]], 65 | [[[3, 3], [3, 3]], [[4, 4], [4, 4]]] 66 | ]) 67 | 68 | # 选择三个维度的每个的第二个元素 69 | tensor[1,1,1] 70 | 71 | # array([4, 4]) 72 | ``` 73 | 74 | ## 数组变形 75 | 76 | ```py 77 | # 加载库 78 | import numpy as np 79 | 80 | # 创建 4x3 矩阵 81 | matrix = np.array([[1, 2, 3], 82 | [4, 5, 6], 83 | [7, 8, 9], 84 | [10, 11, 12]]) 85 | 86 | # 将矩阵变形为 2x6 矩阵 87 | matrix.reshape(2, 6) 88 | 89 | ''' 90 | array([[ 1, 2, 3, 4, 5, 6], 91 | [ 7, 8, 9, 10, 11, 12]]) 92 | ''' 93 | ``` 94 | 95 | ## 矩阵的逆 96 | 97 | ```py 98 | # 加载库 99 | import numpy as np 100 | 101 | # 创建矩阵 102 | matrix = np.array([[1, 4], 103 | [2, 5]]) 104 | 105 | # 计算矩阵的逆 106 | np.linalg.inv(matrix) 107 | 108 | ''' 109 | array([[-1.66666667, 1.33333333], 110 | [ 0.66666667, -0.33333333]]) 111 | ''' 112 | ``` 113 | 114 | ## 获取矩阵对角线 115 | 116 | ```py 117 | # 加载库 118 | import numpy as np 119 | 120 | # 创建矩阵 121 | matrix = np.array([[1, 2, 3], 122 | [4, 5, 6], 123 | [7, 8, 9]]) 124 | 125 | # 返回对角线元素 126 | matrix.diagonal() 127 | 128 | # array([1, 5, 9]) 129 | 130 | # 创建矩阵的迹 131 | matrix.diagonal().sum() 132 | 133 | # 15 134 | ``` 135 | 136 | ## 展开矩阵 137 | 138 | ```py 139 | # 加载库 140 | import numpy as np 141 | 142 | # 创建矩阵 143 | matrix = np.array([[1, 2, 3], 144 | [4, 5, 6], 145 | [7, 8, 9]]) 146 | 147 | # 展开矩阵 148 | matrix.flatten() 149 | 150 | # array([1, 2, 3, 4, 5, 6, 7, 8, 9]) 151 | ``` 152 | 153 | ## 寻找矩阵的秩 154 | 155 | ```py 156 | # 加载库 157 | import numpy as np 158 | 159 | # 创建矩阵 160 | matrix = np.array([[1, 2, 3], 161 | [4, 5, 6], 162 | [7, 8, 9]]) 163 | 164 | # 返回矩阵的秩 165 | np.linalg.matrix_rank(matrix) 166 | 167 | # 2 168 | ``` 169 | 170 | ## Find The Maximum And Minimum 171 | 172 | ```py 173 | # 加载库 174 | import numpy as np 175 | 176 | # 创建矩阵 177 | matrix = np.array([[1, 2, 3], 178 | [4, 5, 6], 179 | [7, 8, 9]]) 180 | 181 | # 返回最大元素 182 | np.max(matrix) 183 | 184 | # 9 185 | 186 | # 返回最小元素 187 | np.min(matrix) 188 | 189 | # 1 190 | 191 | # 寻找每列的最大元素 192 | np.max(matrix, axis=0) 193 | 194 | # array([7, 8, 9]) 195 | 196 | # 寻找每行的最大元素 197 | np.max(matrix, axis=1) 198 | 199 | # array([3, 6, 9]) 200 | ``` 201 | 202 | ## 描述数组 203 | 204 | ```py 205 | # 加载库 206 | import numpy as np 207 | 208 | # 创建矩阵 209 | matrix = np.array([[1, 2, 3, 4], 210 | [5, 6, 7, 8], 211 | [9, 10, 11, 12]]) 212 | 213 | # 查看行和列数 214 | matrix.shape 215 | 216 | # (3, 4) 217 | 218 | # 查看元素数(行乘列) 219 | matrix.size 220 | 221 | # 12 222 | 223 | # 查看维数 224 | matrix.ndim 225 | 226 | # 2 227 | ``` 228 | 229 | ## 创建向量 230 | 231 | ```py 232 | # 加载库 233 | import numpy as np 234 | 235 | # 创建行向量 236 | vector_row = np.array([1, 2, 3]) 237 | 238 | # 创建列向量 239 | vector_column = np.array([[1], 240 | [2], 241 | [3]]) 242 | ``` 243 | 244 | ## 创建稀疏矩阵 245 | 246 | ```py 247 | # Load libraries 248 | import numpy as np 249 | from scipy import sparse 250 | 251 | # 创建矩阵 252 | matrix = np.array([[0, 0], 253 | [0, 1], 254 | [3, 0]]) 255 | 256 | # 创建压缩稀疏行(CSR)矩阵 257 | matrix_sparse = sparse.csr_matrix(matrix) 258 | ``` 259 | 260 | 注意:有许多类型的稀疏矩阵。 在上面的示例中,我们使用 CSR,但我们使用的类型应该反映我们的用例。 261 | 262 | ## 创建矩阵 263 | 264 | ```py 265 | # 加载库 266 | import numpy as np 267 | 268 | # 创建矩阵 269 | matrix = np.array([[1, 4], 270 | [2, 5]]) 271 | ``` 272 | 273 | 注意 NumPy 的`mat`数据结构对于我们的目的而言不太灵活,应该避免。 274 | 275 | ## 将字典转换为矩阵 276 | 277 | ```py 278 | # 加载库 279 | from sklearn.feature_extraction import DictVectorizer 280 | 281 | # 我们的数据字典 282 | data_dict = [{'Red': 2, 'Blue': 4}, 283 | {'Red': 4, 'Blue': 3}, 284 | {'Red': 1, 'Yellow': 2}, 285 | {'Red': 2, 'Yellow': 2}] 286 | 287 | # 创建 DictVectorizer 对象 288 | dictvectorizer = DictVectorizer(sparse=False) 289 | 290 | # 将字典转换为特征矩阵 291 | features = dictvectorizer.fit_transform(data_dict) 292 | 293 | # 查看特征矩阵 294 | features 295 | 296 | ''' 297 | array([[ 4., 2., 0.], 298 | [ 3., 4., 0.], 299 | [ 0., 1., 2.], 300 | [ 0., 2., 2.]]) 301 | ''' 302 | 303 | # 查看特征矩阵的列名 304 | dictvectorizer.get_feature_names() 305 | 306 | # ['Blue', 'Red', 'Yellow'] 307 | ``` 308 | 309 | ## 计算矩阵的迹 310 | 311 | ```py 312 | # 加载库 313 | import numpy as np 314 | 315 | # 创建矩阵 316 | matrix = np.array([[1, 2, 3], 317 | [4, 5, 6], 318 | [7, 8, 9]]) 319 | 320 | # 计算矩阵的迹 321 | matrix.diagonal().sum() 322 | 323 | # 15 324 | ``` 325 | 326 | ## 计算矩阵的行列式 327 | 328 | ```py 329 | # 加载库 330 | import numpy as np 331 | 332 | # 创建矩阵 333 | matrix = np.array([[1, 2, 3], 334 | [4, 5, 6], 335 | [7, 8, 9]]) 336 | 337 | # 返回矩阵的行列式 338 | np.linalg.det(matrix) 339 | 340 | # -9.5161973539299405e-16 341 | ``` 342 | 343 | ## 计算均值、方差和标准差 344 | 345 | ```py 346 | # 加载库 347 | import numpy as np 348 | 349 | # 创建矩阵 350 | matrix = np.array([[1, 2, 3], 351 | [4, 5, 6], 352 | [7, 8, 9]]) 353 | 354 | # 返回均值 355 | np.mean(matrix) 356 | 357 | # 5.0 358 | 359 | # 返回方差 360 | np.var(matrix) 361 | 362 | # 6.666666666666667 363 | 364 | # 返回标准差 365 | np.std(matrix) 366 | 367 | # 2.5819888974716112 368 | ``` 369 | 370 | ## 计算两个向量的点积 371 | 372 | ```py 373 | # 加载库 374 | import numpy as np 375 | 376 | # 创建两个向量 377 | vector_a = np.array([1,2,3]) 378 | vector_b = np.array([4,5,6]) 379 | 380 | # 计算点积 381 | np.dot(vector_a, vector_b) 382 | 383 | # 32 384 | 385 | # 计算点积 386 | vector_a @ vector_b 387 | 388 | # 32 389 | ``` 390 | 391 | ## 对元素应用操作 392 | 393 | ```py 394 | # 加载库 395 | import numpy as np 396 | 397 | # 创建矩阵 398 | matrix = np.array([[1, 2, 3], 399 | [4, 5, 6], 400 | [7, 8, 9]]) 401 | 402 | # 创建加上 100 的函数 403 | add_100 = lambda i: i + 100 404 | 405 | # 创建向量化函数 406 | vectorized_add_100 = np.vectorize(add_100) 407 | 408 | # 对矩阵的所有元素应用函数 409 | vectorized_add_100(matrix) 410 | 411 | ''' 412 | array([[101, 102, 103], 413 | [104, 105, 106], 414 | [107, 108, 109]]) 415 | ''' 416 | ``` 417 | 418 | ## 矩阵的加和减 419 | 420 | ```py 421 | # 加载库 422 | import numpy as np 423 | 424 | # 创建矩阵 425 | matrix_a = np.array([[1, 1, 1], 426 | [1, 1, 1], 427 | [1, 1, 2]]) 428 | 429 | # 创建矩阵 430 | matrix_b = np.array([[1, 3, 1], 431 | [1, 3, 1], 432 | [1, 3, 8]]) 433 | 434 | # 将两个矩阵相加 435 | np.add(matrix_a, matrix_b) 436 | 437 | ''' 438 | array([[ 2, 4, 2], 439 | [ 2, 4, 2], 440 | [ 2, 4, 10]]) 441 | ''' 442 | 443 | # 将两个矩阵相减 444 | np.subtract(matrix_a, matrix_b) 445 | 446 | ''' 447 | array([[ 0, -2, 0], 448 | [ 0, -2, 0], 449 | [ 0, -2, -6]]) 450 | ''' 451 | ``` 452 | -------------------------------------------------------------------------------- /10.md: -------------------------------------------------------------------------------- 1 | # 十、模型选择 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 在模型选择期间寻找最佳预处理步骤 10 | 11 | 在进行模型选择时,我们必须小心正确处理预处理。 首先,`GridSearchCV`使用交叉验证来确定哪个模型表现最好。 然而,在交叉验证中,我们假装作为测试集被留出的一折是不可见的,因此不适合一些预处理步骤(例如缩放或标准化)。 出于这个原因,我们无法预处理数据然后运行`GridSearchCV`。 12 | 13 | 其次,一些预处理方法有自己的参数,通常必须由用户提供。 通过在搜索空间中包括候选成分值,可以像对待任何想要搜索其他超参数一样对待它们。 14 | 15 | ```py 16 | # 加载库 17 | import numpy as np 18 | from sklearn import datasets 19 | from sklearn.feature_selection import SelectKBest 20 | from sklearn.linear_model import LogisticRegression 21 | from sklearn.model_selection import GridSearchCV 22 | from sklearn.pipeline import Pipeline, FeatureUnion 23 | from sklearn.decomposition import PCA 24 | from sklearn.preprocessing import StandardScaler 25 | 26 | # 设置随机种子 27 | np.random.seed(0) 28 | 29 | # 加载数据 30 | iris = datasets.load_iris() 31 | X = iris.data 32 | y = iris.target 33 | ``` 34 | 35 | 我们包括两个不同的预处理步骤:主成分分析和 k 最佳特征选择。 36 | 37 | ```py 38 | # 创建组合预处理对象 39 | preprocess = FeatureUnion([('pca', PCA()), ("kbest", SelectKBest(k=1))]) 40 | 41 | # 创建流水线 42 | pipe = Pipeline([('preprocess', preprocess), ('classifier', LogisticRegression())]) 43 | 44 | # 创建候选值空间 45 | search_space = [{'preprocess__pca__n_components': [1, 2, 3], 46 | 'classifier__penalty': ['l1', 'l2'], 47 | 'classifier__C': np.logspace(0, 4, 10)}] 48 | 49 | # 创建网格搜索 50 | clf = GridSearchCV(pipe, search_space, cv=5, verbose=0, n_jobs=-1) 51 | 52 | # 拟合网格搜索 53 | best_model = clf.fit(X, y) 54 | 55 | # 查看最佳超参数 56 | print('Best Number Of Princpal Components:', best_model.best_estimator_.get_params()['preprocess__pca__n_components']) 57 | print('Best Penalty:', best_model.best_estimator_.get_params()['classifier__penalty']) 58 | print('Best C:', best_model.best_estimator_.get_params()['classifier__C']) 59 | 60 | ''' 61 | Best Number Of Princpal Components: 3 62 | Best Penalty: l1 63 | Best C: 59.9484250319 64 | ''' 65 | ``` 66 | 67 | ## 使用网格搜索的超参数调优 68 | 69 | ![](img/3f439b203d4e179a2c15c84d3bb15cb7.jpg) 70 | 71 | ```py 72 | # 加载库 73 | import numpy as np 74 | from sklearn import linear_model, datasets 75 | from sklearn.model_selection import GridSearchCV 76 | 77 | # 加载数据 78 | iris = datasets.load_iris() 79 | X = iris.data 80 | y = iris.target 81 | 82 | # 创建逻辑回归 83 | logistic = linear_model.LogisticRegression() 84 | 85 | # 创建正则化惩罚空间 86 | penalty = ['l1', 'l2'] 87 | 88 | # 创建正则化超参数空间 89 | C = np.logspace(0, 4, 10) 90 | 91 | # 创建超参数选项 92 | hyperparameters = dict(C=C, penalty=penalty) 93 | 94 | # 使用 5 折交叉验证创建网格搜索 95 | clf = GridSearchCV(logistic, hyperparameters, cv=5, verbose=0) 96 | 97 | # 拟合网格搜索 98 | best_model = clf.fit(X, y) 99 | 100 | # 查看最佳超参数 101 | print('Best Penalty:', best_model.best_estimator_.get_params()['penalty']) 102 | print('Best C:', best_model.best_estimator_.get_params()['C']) 103 | ''' 104 | Best Penalty: l1 105 | Best C: 7.74263682681 106 | ''' 107 | 108 | # 预测目标向量 109 | best_model.predict(X) 110 | ''' 111 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 114 | 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 115 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 116 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 117 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) 118 | ''' 119 | ``` 120 | 121 | ## 使用随机搜索的超参数调优 122 | 123 | 124 | ```py 125 | # 加载库 126 | from scipy.stats import uniform 127 | from sklearn import linear_model, datasets 128 | from sklearn.model_selection import RandomizedSearchCV 129 | 130 | # 加载数据 131 | iris = datasets.load_iris() 132 | X = iris.data 133 | y = iris.target 134 | 135 | # 创建逻辑回归 136 | logistic = linear_model.LogisticRegression() 137 | 138 | # 创建正则化惩罚空间 139 | penalty = ['l1', 'l2'] 140 | 141 | # 使用均匀分布创建正则化超参数分布 142 | C = uniform(loc=0, scale=4) 143 | 144 | # 创建超参数选项 145 | hyperparameters = dict(C=C, penalty=penalty) 146 | 147 | # 使用 5 折交叉验证和 100 个迭代 148 | clf = RandomizedSearchCV(logistic, hyperparameters, random_state=1, n_iter=100, cv=5, verbose=0, n_jobs=-1) 149 | 150 | # 拟合随机搜索 151 | best_model = clf.fit(X, y) 152 | 153 | # 查看最佳超参数 154 | print('Best Penalty:', best_model.best_estimator_.get_params()['penalty']) 155 | print('Best C:', best_model.best_estimator_.get_params()['C']) 156 | ''' 157 | Best Penalty: l1 158 | Best C: 1.66808801881 159 | ''' 160 | 161 | # 预测目标向量 162 | best_model.predict(X) 163 | ''' 164 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 167 | 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 168 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 169 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 170 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) 171 | ''' 172 | ``` 173 | 174 | ## 使用网格搜索的模型选择 175 | 176 | ![](img/bc7d72780c8296115ef744873807d5ff.jpg) 177 | 178 | 179 | ```py 180 | # 加载库 181 | import numpy as np 182 | from sklearn import datasets 183 | from sklearn.linear_model import LogisticRegression 184 | from sklearn.ensemble import RandomForestClassifier 185 | from sklearn.model_selection import GridSearchCV 186 | from sklearn.pipeline import Pipeline 187 | 188 | # 设置随机种子 189 | np.random.seed(0) 190 | 191 | # 加载数据 192 | iris = datasets.load_iris() 193 | X = iris.data 194 | y = iris.target 195 | ``` 196 | 197 | 请注意,我们包括需要搜索的多个可能的学习算法和多个可能的超参数值。 198 | 199 | ```py 200 | # 创建流水线 201 | pipe = Pipeline([('classifier', RandomForestClassifier())]) 202 | 203 | # 创建候选学习算法和它们的超参数的空间 204 | search_space = [{'classifier': [LogisticRegression()], 205 | 'classifier__penalty': ['l1', 'l2'], 206 | 'classifier__C': np.logspace(0, 4, 10)}, 207 | {'classifier': [RandomForestClassifier()], 208 | 'classifier__n_estimators': [10, 100, 1000], 209 | 'classifier__max_features': [1, 2, 3]}] 210 | 211 | # 创建网格搜索 212 | clf = GridSearchCV(pipe, search_space, cv=5, verbose=0) 213 | 214 | # 拟合网格搜索 215 | best_model = clf.fit(X, y) 216 | 217 | # 查看最佳模型 218 | best_model.best_estimator_.get_params()['classifier'] 219 | ''' 220 | LogisticRegression(C=7.7426368268112693, class_weight=None, dual=False, 221 | fit_intercept=True, intercept_scaling=1, max_iter=100, 222 | multi_class='ovr', n_jobs=1, penalty='l1', random_state=None, 223 | solver='liblinear', tol=0.0001, verbose=0, warm_start=False) 224 | ''' 225 | 226 | # 预测目标向量 227 | best_model.predict(X) 228 | ''' 229 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 232 | 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 233 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 234 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 235 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) 236 | ''' 237 | ``` 238 | 239 | ## 带有参数选项的流水线 240 | 241 | 242 | ```py 243 | # 导入所需的包 244 | import numpy as np 245 | from sklearn import linear_model, decomposition, datasets 246 | from sklearn.pipeline import Pipeline 247 | from sklearn.model_selection import GridSearchCV, cross_val_score 248 | from sklearn.preprocessing import StandardScaler 249 | 250 | # 加载乳腺癌数据集 251 | dataset = datasets.load_breast_cancer() 252 | 253 | # 从数据集特征中创建 X 254 | X = dataset.data 255 | 256 | # 从数据集目标中创建 y 257 | y = dataset.target 258 | 259 | # 创建缩放器对象 260 | sc = StandardScaler() 261 | 262 | # 创建 PCA 对象 263 | pca = decomposition.PCA() 264 | 265 | # 创建逻辑回归对象,带有 L2 惩罚 266 | logistic = linear_model.LogisticRegression() 267 | 268 | # 创建三步流水线。首先,标准化数据。 269 | # 其次,使用 PCA 转换数据。 270 | # 然后在数据上训练逻辑回归。 271 | pipe = Pipeline(steps=[('sc', sc), 272 | ('pca', pca), 273 | ('logistic', logistic)]) 274 | 275 | # 创建 1 到 30 的一列整数(X + 1,特征序号) 276 | n_components = list(range(1,X.shape[1]+1,1)) 277 | 278 | # 创建正则化参数的一列值 279 | C = np.logspace(-4, 4, 50) 280 | 281 | # 为正则化乘法创建一列选项 282 | penalty = ['l1', 'l2'] 283 | 284 | # 为所有参数选项创建字典 285 | # 注意,你可以使用 '__' 来访问流水线的步骤的参数 286 | parameters = dict(pca__n_components=n_components, 287 | logistic__C=C, 288 | logistic__penalty=penalty) 289 | 290 | # 创建网格搜索对象 291 | clf = GridSearchCV(pipe, parameters) 292 | 293 | # 拟合网格搜索 294 | clf.fit(X, y) 295 | 296 | # 查看超参数 297 | print('Best Penalty:', clf.best_estimator_.get_params()['logistic__penalty']) 298 | print('Best C:', clf.best_estimator_.get_params()['logistic__C']) 299 | print('Best Number Of Components:', clf.best_estimator_.get_params()['pca__n_components']) 300 | 301 | # 使用 3 折交叉验证拟合网格搜索 302 | cross_val_score(clf, X, y) 303 | ``` -------------------------------------------------------------------------------- /11.md: -------------------------------------------------------------------------------- 1 | # 十一、线性回归 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 添加交互项 10 | 11 | ![](img/19274741dc836a609c2722cd32770692.jpg) 12 | 13 | ```py 14 | # 加载库 15 | from sklearn.linear_model import LinearRegression 16 | from sklearn.datasets import load_boston 17 | from sklearn.preprocessing import PolynomialFeatures 18 | import warnings 19 | 20 | # 屏蔽警告 21 | warnings.filterwarnings(action="ignore", module="scipy", message="^internal gelsd") 22 | 23 | # 加载只有两个特征的数据 24 | boston = load_boston() 25 | X = boston.data[:,0:2] 26 | y = boston.target 27 | ``` 28 | 29 | 通过添加一个新的特征,它是交互特征的乘积,来添加交互项。 30 | 31 | ![](img/tex-020a9f6f179050a671f6f6f28169b20d.gif) 32 | 33 | 其中 ![](img/tex-f9a3b8e9e501458e8face47cae8826de.gif) 和 ![](img/tex-8f43fce8dbdf3c4f8d0ac91f0de1d43d.gif) 分别是两个特征的值,![](img/tex-f8281cafb08efe03bce3816f00fdd12d.gif) 表示两者之间的交互。使用 scikit-learn 的`PolynomialFeatures`,来为所有特征组合创建交互术项会很有用。 然后,我们可以使用模型选择策略,来识别产生最佳模型的特征和交互项的组合。 34 | 35 | ```py 36 | # 创建交互项(非多项式特征) 37 | interaction = PolynomialFeatures(degree=3, include_bias=False, interaction_only=True) 38 | X_inter = interaction.fit_transform(X) 39 | 40 | # 创建线性回归 41 | regr = LinearRegression() 42 | 43 | # 拟合线性回归 44 | model = regr.fit(X_inter, y) 45 | ``` 46 | 47 | ## 创建交互特征 48 | 49 | ```py 50 | # 加载库 51 | from sklearn.preprocessing import PolynomialFeatures 52 | import numpy as np 53 | 54 | # 创建特征矩阵 55 | X = np.array([[2, 3], 56 | [2, 3], 57 | [2, 3]]) 58 | 59 | # 创建 PolynomialFeatures 对象,它的 interaction_only 设为 True 60 | interaction = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False) 61 | 62 | # 转换特征矩阵 63 | interaction.fit_transform(X) 64 | ''' 65 | array([[ 2., 3., 6.], 66 | [ 2., 3., 6.], 67 | [ 2., 3., 6.]]) 68 | ''' 69 | ``` 70 | 71 | ## Lasso 回归的 Alpha 的效果 72 | 73 | 我们通常希望执行一个称为[正则化](https://en.wikipedia.org/wiki/Regularization)的过程,其中我们会惩罚模型中的系数数量,以便仅保留最重要的系数。 当你拥有带有 100,000 多个系数的数据集时,这一点尤为重要。 74 | 75 | [Lasso 回归](https://en.wikipedia.org/wiki/Lasso_(statistics))是正则化的常用建模技术。 它背后的数学非常有趣,但实际上,你需要知道的是,Lasso 回归带有一个参数`alpha`,而`alpha`越高,大多数特征系数越会为零。 76 | 77 | 也就是说,当`alpha`为`0`时,Lasso 回归产生与线性回归相同的系数。 当`alpha`非常大时,所有系数都为零。 78 | 79 | 在本教程中,我运行三个 Lasso 回归,具有不同的`alpha`值,并显示对系数结果的影响。 80 | 81 | ```py 82 | from sklearn.linear_model import Lasso 83 | from sklearn.preprocessing import StandardScaler 84 | from sklearn.datasets import load_boston 85 | import pandas as pd 86 | 87 | boston = load_boston() 88 | scaler = StandardScaler() 89 | X = scaler.fit_transform(boston["data"]) 90 | Y = boston["target"] 91 | names = boston["feature_names"] 92 | 93 | # 创建函数 lasso 94 | def lasso(alphas): 95 | ''' 96 | 接受 alpha 列表。输出数据帧,包含每个 alpha 的 Lasso 回归的系数。 97 | ''' 98 | # 创建空数据帧 99 | df = pd.DataFrame() 100 | 101 | # 创建特征名称列 102 | df['Feature Name'] = names 103 | 104 | # 对于每个列表中的 alpha 值, 105 | for alpha in alphas: 106 | # 创建这个 alpha 值的 laaso 回归, 107 | lasso = Lasso(alpha=alpha) 108 | 109 | # 拟合 lasso 回归 110 | lasso.fit(X, Y) 111 | 112 | # 为这个 alpha 值创建列名称 113 | column_name = 'Alpha = %f' % alpha 114 | 115 | # 创建系数列 116 | df[column_name] = lasso.coef_ 117 | 118 | # 返回数据帧 119 | return df 120 | 121 | # 调用函数 lasso 122 | lasso([.0001, .5, 10]) 123 | ``` 124 | 125 | | | Feature Name | Alpha = 0.000100 | Alpha = 0.500000 | Alpha = 10.000000 | 126 | | --- | --- | --- | --- | --- | 127 | | 0 | CRIM | -0.920130 | -0.106977 | -0.0 | 128 | | 1 | ZN | 1.080498 | 0.000000 | 0.0 | 129 | | 2 | INDUS | 0.142027 | -0.000000 | -0.0 | 130 | | 3 | CHAS | 0.682235 | 0.397399 | 0.0 | 131 | | 4 | NOX | -2.059250 | -0.000000 | -0.0 | 132 | | 5 | RM | 2.670814 | 2.973323 | 0.0 | 133 | | 6 | AGE | 0.020680 | -0.000000 | -0.0 | 134 | | 7 | DIS | -3.104070 | -0.169378 | 0.0 | 135 | | 8 | RAD | 2.656950 | -0.000000 | -0.0 | 136 | | 9 | TAX | -2.074110 | -0.000000 | -0.0 | 137 | | 10 | PTRATIO | -2.061921 | -1.599574 | -0.0 | 138 | | 11 | B | 0.856553 | 0.545715 | 0.0 | 139 | | 12 | LSTAT | -3.748470 | -3.668884 | -0.0 | 140 | 141 | 请注意,随着alpha值的增加,更多特征的系数为 0。 142 | 143 | # Lasso 回归 144 | 145 | ```py 146 | # 加载库 147 | from sklearn.linear_model import Lasso 148 | from sklearn.datasets import load_boston 149 | from sklearn.preprocessing import StandardScaler 150 | 151 | # 加载数据 152 | boston = load_boston() 153 | X = boston.data 154 | y = boston.target 155 | 156 | # 标准化特征 157 | scaler = StandardScaler() 158 | X_std = scaler.fit_transform(X) 159 | ``` 160 | 161 | 超参数 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 让我们控制我们对系数的惩罚程度,更高的 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 值创建更简单的模型。![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 的理想值应该像任何其他超参数一样调整。 在 scikit-learn中,使用`alpha`参数设置 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif)。 162 | 163 | ```py 164 | # 创建带有某个 alpha 值的 Lasso 165 | regr = Lasso(alpha=0.5) 166 | 167 | # 拟合 Lasso 回归 168 | model = regr.fit(X_std, y) 169 | ``` 170 | 171 | ## 线性回归 172 | 173 | 来源:[scikit-learn](http://scikit-learn.org/stable/auto_examples/linear_model/plot_ols.html#example-linear-model-plot-ols-py),[DrawMyData](http://robertgrantstats.co.uk/drawmydata.html). 174 | 175 | 本教程的目的是,简要介绍机器学习中使用的统计模型构建的逻辑。如果你想更加了解本教程背后的理论,请查看[统计学习导论](https://www.amazon.com/Introduction-Statistical-Learning-Applications-Statistics/dp/1461471370)。 176 | 177 | 让我们开始吧。 178 | 179 | ```py 180 | import pandas as pd 181 | from sklearn import linear_model 182 | import random 183 | import numpy as np 184 | %matplotlib inline 185 | ``` 186 | 187 | 添加这些库后,让我们加载数据集(数据集可以在他的站点的 GitHub 仓库中找到)。 188 | 189 | ```py 190 | # 加载数据 191 | df = pd.read_csv('../data/simulated_data/battledeaths_n300_cor99.csv') 192 | 193 | # 打乱数据的行(这是必要的, 194 | # 仅仅由于我使用 DrawMyData 创建数据的方式。真正的分析中通常不需要 195 | df = df.sample(frac=1) 196 | ``` 197 | 198 | 让我们看一下数据的前几行,以便了解它。 199 | 200 | ```py 201 | # 查看数据的前几行 202 | df.head() 203 | ``` 204 | 205 | | | friendly_battledeaths | enemy_battledeaths | 206 | | --- | --- | --- | 207 | | 7 | 8.2051 | 9.6154 | 208 | | 286 | 88.7179 | 86.1538 | 209 | | 164 | 14.3590 | 8.8462 | 210 | | 180 | 38.9744 | 36.5385 | 211 | | 89 | 93.0769 | 93.0769 | 212 | 213 | 现在让我们绘制数据,以便我们可以看到它的结构。 214 | 215 | ```py 216 | # 绘制两个变量,彼此对照 217 | df.plot(x='friendly_battledeaths', y='enemy_battledeaths', kind='scatter') 218 | 219 | # 220 | ``` 221 | 222 | ![png](https://chrisalbon.com/machine_learning/linear_regression/linear_regression_scikitlearn/linear_regression_scikitlearn_12_1.png) 223 | 224 | 现在是真正的工作了。 为了判断我们的模型有多好,我们需要一些东西来测试它。 我们可以使用称为交叉验证的技术来实现这一目标。 交叉验证可以变得更加复杂和强大,但在这个例子中,我们将使用这种技术的最简单版本。 225 | 226 | ### 步骤 227 | 228 | 1. 将数据集划分为两个数据集:我们将用于训练模型的“训练”数据集,和我们将用于判断该模型准确率的“测试”数据集。 229 | 2. 在“训练”数据上训练模型。 230 | 3. 将该模型应用于测试数据的`X`变量,创建模型对测试数据`Y`的猜测。 231 | 4. 比较模型对测试数据`Y`的预测,与实际测试数据`Y`的接近程度。 232 | 233 | ```py 234 | # 创建我们的预测器/自变量 235 | # 以及我们的响应/因变量 236 | X = df['friendly_battledeaths'] 237 | y = df['enemy_battledeaths'] 238 | 239 | # 从前 30 个观测中创建测试数据 240 | X_test = X[0:30].reshape(-1,1) 241 | y_test = y[0:30] 242 | 243 | # 从剩余的观测中创建我们的训练数据 244 | X_train = X[30:].reshape(-1,1) 245 | y_train = y[30:] 246 | ``` 247 | 248 | 让我们使用我们的训练数据训练模型。 249 | 250 | ```py 251 | # 创建 OLS 回归对象 252 | ols = linear_model.LinearRegression() 253 | 254 | # 使用训练数据来训练模型 255 | model = ols.fit(X_train, y_train) 256 | ``` 257 | 258 | 以下是模型的一些基本输出,特别是系数和 R 方得分。 259 | 260 | ```py 261 | # 查看训练模型的系数 262 | model.coef_ 263 | 264 | # array([ 0.97696721]) 265 | 266 | # 查看 R 方得分 267 | model.score(X_test, y_test) 268 | 269 | # 0.98573393818904709 270 | ``` 271 | 272 | 现在我们已经使用训练数据,来训练一个名为`model`的模型,我们可以将它应用于测试数据的`X`,来预测测试数据的`Y`。 273 | 274 | 以前我们使用`X_train`和`y_train`来训练线性回归模型,我们将其存储为一个名为`model`的变量。 代码`model.predict(X_test)`将训练好的模型应用于`X_test`数据,这是模型以前从未见过的数据,来生成`Y`的预测值。 275 | 276 | 只需运行代码即可轻松看到: 277 | 278 | ```py 279 | # 在 X_test 上运行模型并显示前五个结果 280 | list(model.predict(X_test)[0:5]) 281 | ''' 282 | [7.4633347104887342, 283 | 86.121700007313791, 284 | 13.475493202059415, 285 | 37.523931774900845, 286 | 90.380300060086256] 287 | ''' 288 | ``` 289 | 290 | 这个数组是模型对测试数据`Y`值的最佳猜测。 将它们与实际测试数据`Y`值进行比较: 291 | 292 | ```py 293 | # 查看前五个测试 Y 值 294 | list(y_test)[0:5] 295 | ''' 296 | [9.6153999999999993, 297 | 86.153800000000004, 298 | 8.8461999999999996, 299 | 36.538499999999999, 300 | 93.076899999999995] 301 | ''' 302 | ``` 303 | 304 | 模型的预测值与实际值之间的差异,是我们判断模型的准确率的方式,因为完全准确的模型没有残差。 305 | 306 | 但是,要判断模型,我们需要一个可用作度量的统计量(数字)。 我们希望这个度量能够捕获数据中所有观测的预测值与实际值之间的差异。 307 | 308 | 用于量化`Y`的最常见统计量是**残差平方和**: 309 | 310 | ![](img/tex-52539b56794b13d260a84f3461c80f49.gif) 311 | 312 | 不要让数学符号吓到: 313 | 314 | * ![](img/tex-7e18dabda345d4f3a3642ecf7fa61ccf.gif) 是我们训练的模型:`model.predict(X_test)` 315 | * ![](img/tex-18daef71b5d25ce76b8628a81e4fc76b.gif) 是测试数据的`y`:`y_test` 316 | * ![](img/tex-272ba5cfd2789d670bc65e40587345c3.gif) 是指数:`**2` 317 | * ![](img/tex-50d7cc01f0e1e57d81240e646606b14a.gif) 是求和:`.sum()` 318 | 319 | 在残差的平方和中,对于每个观测,我们找到模型的预测`Y`和实际`Y`值之间的差异,然后将该差异平方来使所有值为正。 然后我们将所有这些平方差加在一起得到一个数字。 最终结果是一个统计量,表示模型的预测与实际值的距离。 320 | 321 | ```py 322 | # 将我们使用训练数据创建的模型 323 | # 应用于测试数据,并计算RSS。 324 | ((y_test - model.predict(X_test)) **2).sum() 325 | 326 | # 313.6087355571951 327 | ``` 328 | 329 | 注意:你还可以使用均方差(MSE),它是 RSS 除以自由度。 但我发现用 RSS 来思考是有帮助的。 330 | 331 | ```py 332 | # 计算 MSE 333 | np.mean((model.predict(X_test) - y_test) **2) 334 | 335 | # 10.45362451857317 336 | ``` 337 | 338 | ## Sklearn 线性回归 339 | 340 | ```py 341 | # 加载库 342 | from sklearn.linear_model import LinearRegression 343 | from sklearn.datasets import load_boston 344 | import warnings 345 | 346 | # 屏蔽警告 347 | warnings.filterwarnings(action="ignore", module="scipy", message="^internal gelsd") 348 | 349 | # 加载数据 350 | boston = load_boston() 351 | X = boston.data 352 | y = boston.target 353 | 354 | # 创建线性回归 355 | regr = LinearRegression() 356 | 357 | # 拟合线性回归 358 | model = regr.fit(X, y) 359 | 360 | # 查看截距(偏差) 361 | model.intercept_ 362 | 363 | # 36.491103280361038 364 | 365 | # 查看特征系数(权重) 366 | model.coef_ 367 | 368 | ''' 369 | array([ -1.07170557e-01, 4.63952195e-02, 2.08602395e-02, 370 | 2.68856140e+00, -1.77957587e+01, 3.80475246e+00, 371 | 7.51061703e-04, -1.47575880e+00, 3.05655038e-01, 372 | -1.23293463e-02, -9.53463555e-01, 9.39251272e-03, 373 | -5.25466633e-01]) 374 | ''' 375 | ``` 376 | 377 | # 岭回归 378 | 379 | ![](img/502eebaffff7022fe6dd5b4a3f901d71.jpg) 380 | 381 | ```py 382 | # 加载库 383 | from sklearn.linear_model import Ridge 384 | from sklearn.datasets import load_boston 385 | from sklearn.preprocessing import StandardScaler 386 | 387 | # 加载数据 388 | boston = load_boston() 389 | X = boston.data 390 | y = boston.target 391 | 392 | # 标准化特征 393 | scaler = StandardScaler() 394 | X_std = scaler.fit_transform(X) 395 | ``` 396 | 397 | 超参数 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 让我们控制我们对系数的惩罚程度,更高的 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 值创建更简单的模型。![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif) 的理想值应该像任何其他超参数一样调整。 在 scikit-learn中,使用`alpha`参数设置 ![](img/tex-7b7f9dbfea05c83784f8b85149852f08.gif)。 398 | 399 | ```py 400 | # 创建带有 alpha 值的岭回归 401 | regr = Ridge(alpha=0.5) 402 | 403 | # 拟合岭回归 404 | model = regr.fit(X_std, y) 405 | ``` 406 | 407 | # 为岭回归选择最佳的 alpha 值 408 | 409 | ```py 410 | # 加载库 411 | from sklearn.linear_model import RidgeCV 412 | from sklearn.datasets import load_boston 413 | from sklearn.preprocessing import StandardScaler 414 | 415 | # 加载数据 416 | boston = load_boston() 417 | X = boston.data 418 | y = boston.target 419 | ``` 420 | 421 | 注意:因为在线性回归中,系数的值由特征的尺度部分确定,并且在正则化的模型中,所有系数加在一起,我们必须确保在训练之前将特征标准化。 422 | 423 | ```py 424 | # 标准化特征 425 | scaler = StandardScaler() 426 | X_std = scaler.fit_transform(X) 427 | 428 | # 创建带有三个可能 alpha 值的岭回归 429 | regr_cv = RidgeCV(alphas=[0.1, 1.0, 10.0]) 430 | ``` 431 | 432 | scikit-learn 包含`RidgeCV`方法,允许我们为 ![](img/tex-d945100c5fa6a400570dcacfb1fc9869.gif) 选择理想值: 433 | 434 | ```py 435 | # 拟合岭回归 436 | model_cv = regr_cv.fit(X_std, y) 437 | 438 | # 查看 alpha 439 | model_cv.alpha_ 440 | 441 | # 1.0 442 | ``` -------------------------------------------------------------------------------- /12.md: -------------------------------------------------------------------------------- 1 | # 十二、逻辑回归 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## C 超参数快速调优 10 | 11 | 有时,学习算法的特征使我们能够比蛮力或随机模型搜索方法更快地搜索最佳超参数。 12 | 13 | scikit-learn 的`LogisticRegressionCV`方法包含一个参数`C`。 如果提供了一个列表,`C`是可供选择的候选超参数值。 如果提供了一个整数,`C`的这么多个候选值,将从 0.0001 和 10000 之间的对数标度(`C`的合理值范围)中提取。 14 | 15 | ```py 16 | # 加载库 17 | from sklearn import linear_model, datasets 18 | 19 | # 加载数据 20 | iris = datasets.load_iris() 21 | X = iris.data 22 | y = iris.target 23 | 24 | # 创建逻辑回归的交叉验证 25 | clf = linear_model.LogisticRegressionCV(Cs=100) 26 | 27 | # 训练模型 28 | clf.fit(X, y) 29 | 30 | ''' 31 | LogisticRegressionCV(Cs=100, class_weight=None, cv=None, dual=False, 32 | fit_intercept=True, intercept_scaling=1.0, max_iter=100, 33 | multi_class='ovr', n_jobs=1, penalty='l2', random_state=None, 34 | refit=True, scoring=None, solver='lbfgs', tol=0.0001, verbose=0) 35 | ''' 36 | ``` 37 | 38 | # 在逻辑回归中处理不平衡类别 39 | 40 | 像 scikit-learn 中的许多其他学习算法一样,`LogisticRegression`带有处理不平衡类的内置方法。 如果我们有高度不平衡的类,并且在预处理期间没有解决它,我们可以选择使用`class_weight`参数来对类加权,确保我们拥有每个类的平衡组合。 具体来说,`balanced`参数会自动对类加权,与其频率成反比: 41 | 42 | ![](img/tex-bde5f474d3e4c7e38ddd6440a38a7f4e.gif) 43 | 44 | 其中 ![](img/tex-e8100be07fa5419af6c6738b934dfca0.gif) 是类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 的权重,![](img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif) 是观察数,![](img/tex-4aa861124eff57dd7988faa6753e8b7e.gif) 是类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 中的观察数,![](img/tex-8ce4b16b22b58894aa86c421e8759df3.gif) 是类的总数。 45 | 46 | ```py 47 | # 加载库 48 | from sklearn.linear_model import LogisticRegression 49 | from sklearn import datasets 50 | from sklearn.preprocessing import StandardScaler 51 | import numpy as np 52 | 53 | # 加载数据 54 | iris = datasets.load_iris() 55 | X = iris.data 56 | y = iris.target 57 | 58 | # 通过移除前 40 个观测,使类高度不均衡 59 | X = X[40:,:] 60 | y = y[40:] 61 | 62 | # 创建目标向量,如果表示类别是否为 0 63 | y = np.where((y == 0), 0, 1) 64 | 65 | # 标准化特征 66 | scaler = StandardScaler() 67 | X_std = scaler.fit_transform(X) 68 | 69 | # 创建决策树分类器对象 70 | clf = LogisticRegression(random_state=0, class_weight='balanced') 71 | 72 | # 训练模型 73 | model = clf.fit(X_std, y) 74 | ``` 75 | 76 | ## 逻辑回归 77 | 78 | 尽管其名称中存在“回归”,但逻辑回归实际上是广泛使用的二分类器(即,目标向量只有两个值)。 在逻辑回归中,线性模型(例如 ![](img/tex-31f830c208ca5fcbf1bca34de8d796a6.gif))包含在 logit(也称为 sigmoid)函数中,![](img/tex-ad6d5470eaff252c993327c248d56b0e.gif),满足: 79 | 80 | ![](img/tex-777eeb07996381e00006e77dd1aaf39f.gif) 81 | 82 | 其中 ![](img/tex-2b30ddf4881c9acfc3bc0cf2880eefaa.gif) 是第 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 个观测的目标值 ![](img/tex-8d62e469fb30ed435a668eb5c035b1f6.gif) 为 1 的概率,![](img/tex-02129bb861061d1a052c592e2dc6b383.gif) 是训练数据,![](img/tex-5af9e28d609b16eb25693f44ea9d7a8f.gif) 和 ![](img/tex-b4ceec2c4656f5c1e7fc76c59c4f80f3.gif) 是要学习的参数,![](img/tex-e1671797c52e15f763380b45e841ec32.gif) 是自然常数。 83 | 84 | ```py 85 | # 加载库 86 | from sklearn.linear_model import LogisticRegression 87 | from sklearn import datasets 88 | from sklearn.preprocessing import StandardScaler 89 | 90 | # 加载只有两个类别的数据 91 | iris = datasets.load_iris() 92 | X = iris.data[:100,:] 93 | y = iris.target[:100] 94 | 95 | # 标准化特征 96 | scaler = StandardScaler() 97 | X_std = scaler.fit_transform(X) 98 | 99 | # 创建逻辑回归对象 100 | clf = LogisticRegression(random_state=0) 101 | 102 | # 训练模型 103 | model = clf.fit(X_std, y) 104 | 105 | # 创建新的观测 106 | new_observation = [[.5, .5, .5, .5]] 107 | 108 | # 预测类别 109 | model.predict(new_observation) 110 | 111 | # array([1]) 112 | 113 | # 查看预测的概率 114 | model.predict_proba(new_observation) 115 | 116 | # array([[ 0.18823041, 0.81176959]]) 117 | ``` 118 | 119 | # 大量数据上的逻辑回归 120 | 121 | scikit-learn 的`LogisticRegression`提供了许多用于训练逻辑回归的技术,称为求解器。 大多数情况下,scikit-learn 会自动为我们选择最佳求解器,或警告我们,你不能用求解器做一些事情。 但是,我们应该注意一个特殊情况。 122 | 123 | 虽然精确的解释超出了本书的范围,但随机平均梯度下降使得我们在数据非常大时,比其他求解器更快训练模型。 但是,对特征尺度也非常敏感,标准化我们的特征尤为重要。 我们可以通过设置`solver ='sag'`来设置我们的学习算法来使用这个求解器。 124 | 125 | ```py 126 | # 加载库 127 | from sklearn.linear_model import LogisticRegression 128 | from sklearn import datasets 129 | from sklearn.preprocessing import StandardScaler 130 | 131 | # 加载数据 132 | iris = datasets.load_iris() 133 | X = iris.data 134 | y = iris.target 135 | 136 | # 标准化特征 137 | scaler = StandardScaler() 138 | X_std = scaler.fit_transform(X) 139 | 140 | # 创建使用 SAG 求解器的逻辑回归 141 | clf = LogisticRegression(random_state=0, solver='sag') 142 | 143 | # 训练模型 144 | model = clf.fit(X_std, y) 145 | ``` 146 | 147 | # 带有 L1 正则化的逻辑回归 148 | 149 | L1 正则化(也称为最小绝对误差)是数据科学中的强大工具。 有许多教程解释 L1 正则化,我不会在这里尝试这样做。 相反,本教程将展示正则化参数`C`对系数和模型精度的影响。 150 | 151 | ```py 152 | import numpy as np 153 | from sklearn.linear_model import LogisticRegression 154 | from sklearn import datasets 155 | from sklearn.model_selection import train_test_split 156 | from sklearn.preprocessing import StandardScaler 157 | ``` 158 | 159 | 本教程中使用的数据集是着名的[鸢尾花数据集](https://en.wikipedia.org/wiki/Iris_flower_data_set)。鸢尾花数据包含来自三种鸢尾花`y`,和四个特征变量`X`的 50 个样本。 160 | 161 | 数据集包含三个类别(三种鸢尾),但是为了简单起见,如果目标数据是二元的,则更容易。因此,我们将从数据中删除最后一种鸢尾。 162 | 163 | ```py 164 | # 加载鸢尾花数据集 165 | iris = datasets.load_iris() 166 | 167 | # 从特征中创建 X 168 | X = iris.data 169 | 170 | # 从目标中创建 y 171 | y = iris.target 172 | 173 | # 重新生成变量,保留所有标签不是 2 的数据 174 | X = X[y != 2] 175 | y = y[y != 2] 176 | 177 | # 查看特征 178 | X[0:5] 179 | 180 | ''' 181 | array([[ 5.1, 3.5, 1.4, 0.2], 182 | [ 4.9, 3\. , 1.4, 0.2], 183 | [ 4.7, 3.2, 1.3, 0.2], 184 | [ 4.6, 3.1, 1.5, 0.2], 185 | [ 5\. , 3.6, 1.4, 0.2]]) 186 | ''' 187 | 188 | # 查看目标数据 189 | y 190 | 191 | ''' 192 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 195 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 196 | 1, 1, 1, 1, 1, 1, 1, 1]) 197 | ''' 198 | 199 | # 将数据拆分为测试和训练集 200 | # 将 30% 的样本放入测试集 201 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) 202 | ``` 203 | 204 | 因为正则化惩罚由系数的绝对值之和组成,所以我们需要缩放数据,使系数都基于相同的比例。 205 | 206 | ```py 207 | # 创建缩放器对象 208 | sc = StandardScaler() 209 | 210 | # 将缩放器拟合训练数据,并转换 211 | X_train_std = sc.fit_transform(X_train) 212 | 213 | # 将缩放器应用于测试数据 214 | X_test_std = sc.transform(X_test) 215 | ``` 216 | 217 | L1 的用处在于它可以将特征系数逼近 0,从而创建一种特征选择方法。 在下面的代码中,我们运行带有 L1 惩罚的逻辑回归四次,每次都减少了`C`的值。 我们应该期望随着`C`的减少,更多的系数变为 0。 218 | 219 | ```py 220 | C = [10, 1, .1, .001] 221 | 222 | for c in C: 223 | clf = LogisticRegression(penalty='l1', C=c) 224 | clf.fit(X_train, y_train) 225 | print('C:', c) 226 | print('Coefficient of each feature:', clf.coef_) 227 | print('Training accuracy:', clf.score(X_train, y_train)) 228 | print('Test accuracy:', clf.score(X_test, y_test)) 229 | print('') 230 | 231 | ''' 232 | C: 10 233 | Coefficient of each feature: [[-0.0855264 -3.75409972 4.40427765 0\. ]] 234 | Training accuracy: 1.0 235 | Test accuracy: 1.0 236 | 237 | C: 1 238 | Coefficient of each feature: [[ 0\. -2.28800472 2.5766469 0\. ]] 239 | Training accuracy: 1.0 240 | Test accuracy: 1.0 241 | 242 | C: 0.1 243 | Coefficient of each feature: [[ 0\. -0.82310456 0.97171847 0\. ]] 244 | Training accuracy: 1.0 245 | Test accuracy: 1.0 246 | 247 | C: 0.001 248 | Coefficient of each feature: [[ 0\. 0\. 0\. 0.]] 249 | Training accuracy: 0.5 250 | Test accuracy: 0.5 251 | ''' 252 | ``` 253 | 254 | 注意,当`C`减小时,模型系数变小(例如,从`C = 10`时的`4.36276075`变为`C = 0.1`时的`0.0.97175097`),直到`C = 0.001`,所有系数都是零。 这是变得更加突出的,正则化惩罚的效果。 255 | 256 | # OVR 逻辑回归 257 | 258 | 逻辑回归本身只是二分类器,这意味着它们无法处理具有两个类别以上的目标向量。 但是,逻辑回归有一些聪明的扩展来实现它。 在 One-VS-Rest(OVR)逻辑回归中,针对每个类别训练单独的模型,预测观测是否是该类(因此使其成为二分类问题)。 它假定每个分类问题(例如是不是类 0)是独立的。 259 | 260 | ```py 261 | # 加载库 262 | from sklearn.linear_model import LogisticRegression 263 | from sklearn import datasets 264 | from sklearn.preprocessing import StandardScaler 265 | 266 | # 加载数据 267 | iris = datasets.load_iris() 268 | X = iris.data 269 | y = iris.target 270 | 271 | # 标准化特征 272 | scaler = StandardScaler() 273 | X_std = scaler.fit_transform(X) 274 | 275 | # 创建 OVR 逻辑回归对象 276 | clf = LogisticRegression(random_state=0, multi_class='ovr') 277 | 278 | # 训练模型 279 | model = clf.fit(X_std, y) 280 | 281 | # 创建新的观测 282 | new_observation = [[.5, .5, .5, .5]] 283 | 284 | # 预测类别 285 | model.predict(new_observation) 286 | 287 | # array([2]) 288 | 289 | # 查看预测概率 290 | model.predict_proba(new_observation) 291 | 292 | # array([[ 0.0829087 , 0.29697265, 0.62011865]]) 293 | ``` -------------------------------------------------------------------------------- /14.md: -------------------------------------------------------------------------------- 1 | # 十四、K 最近邻 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 确定 K 的最佳值 10 | 11 | ![](img/cd28dcfca524b96afc6ddf81d6f0c298.jpg) 12 | 13 | ```py 14 | # 加载库 15 | from sklearn.neighbors import KNeighborsClassifier 16 | from sklearn import datasets 17 | from sklearn.preprocessing import StandardScaler 18 | from sklearn.pipeline import Pipeline, FeatureUnion 19 | from sklearn.model_selection import GridSearchCV 20 | 21 | # 加载数据 22 | iris = datasets.load_iris() 23 | X = iris.data 24 | y = iris.target 25 | 26 | # 创建标准化器 27 | standardizer = StandardScaler() 28 | 29 | # 标准化特征 30 | X_std = standardizer.fit_transform(X) 31 | 32 | # 拟合 5 个邻居的 KNN 分类器 33 | knn = KNeighborsClassifier(n_neighbors=5, metric='euclidean', n_jobs=-1).fit(X_std, y) 34 | 35 | # 创建流水线 36 | pipe = Pipeline([('standardizer', standardizer), ('knn', knn)]) 37 | 38 | # 创建候选值空间 39 | search_space = [{'knn__n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}] 40 | 41 | # 创建网格搜索 42 | clf = GridSearchCV(pipe, search_space, cv=5, verbose=0).fit(X_std, y) 43 | 44 | # 最佳邻居大小(K) 45 | clf.best_estimator_.get_params()['knn__n_neighbors'] 46 | 47 | # 6 48 | ``` 49 | 50 | ## KNN 分类 51 | 52 | K 最近邻分类器(KNN)是一种简单而强大的分类学习器。 53 | 54 | KNN 有三个基本部分 55 | 56 | * ![](img/tex-8d62e469fb30ed435a668eb5c035b1f6.gif): 观测的类别(我们试图在测试数据中预测的东西)。 57 | * ![](img/tex-a97118fb9e8d7e006a466bfc0771f888.gif): 观察的预测因子/ IV /属性。 58 | * ![](img/tex-a5f3c6a11b03839d46af9fb43c97c188.gif): 研究者指定的正数。 K 表示最接近特定观测的观测数,它定义了“邻域”。 例如,`K = 2`意味着每个观测都有一个邻域,包含最接近它的另外两个观测。 59 | 60 | 想象一下,我们有一个观测,我们知道它的自变量 ![](img/tex-6b5a5f025640932b2554f6d400b3e45f.gif),但不知道它的类别 ![](img/tex-c39d1645d55ca4afb20c8d6a365615bb.gif)。 KNN 学习器找到最接近 ![](img/tex-6b5a5f025640932b2554f6d400b3e45f.gif) 的K个其他观测,并使用他们已知的类别,将类别分配给 ![](img/tex-6b5a5f025640932b2554f6d400b3e45f.gif)。 61 | 62 | ```py 63 | import pandas as pd 64 | from sklearn import neighbors 65 | import numpy as np 66 | %matplotlib inline 67 | import seaborn 68 | ``` 69 | 70 | 这里我们创建三个变量,`test_1`和`test_2`是我们的自变量,`outcome`是我们的因变量。 我们将使用这些数据来训练我们的学习器。 71 | 72 | ```py 73 | training_data = pd.DataFrame() 74 | 75 | training_data['test_1'] = [0.3051,0.4949,0.6974,0.3769,0.2231,0.341,0.4436,0.5897,0.6308,0.5] 76 | training_data['test_2'] = [0.5846,0.2654,0.2615,0.4538,0.4615,0.8308,0.4962,0.3269,0.5346,0.6731] 77 | training_data['outcome'] = ['win','win','win','win','win','loss','loss','loss','loss','loss'] 78 | 79 | training_data.head() 80 | ``` 81 | 82 | | | test_1 | test_2 | outcome | 83 | | --- | --- | --- | --- | 84 | | 0 | 0.3051 | 0.5846 | win | 85 | | 1 | 0.4949 | 0.2654 | win | 86 | | 2 | 0.6974 | 0.2615 | win | 87 | | 3 | 0.3769 | 0.4538 | win | 88 | | 4 | 0.2231 | 0.4615 | win | 89 | 90 | 这不是必需的,但因为我们只有三个变量,所以我们可以绘制训练数据集。 X 轴和 Y 轴是自变量,而点的颜色是它们的类别。 91 | 92 | ```py 93 | seaborn.lmplot('test_1', 'test_2', data=training_data, fit_reg=False,hue="outcome", scatter_kws={"marker": "D","s": 100}) 94 | 95 | # 96 | ``` 97 | 98 | ![png](https://chrisalbon.com/machine_learning/nearest_neighbors/k-nearest_neighbors_classifer/k-nearest_neighbors_classifer_9_1.png) 99 | 100 | `scikit-learn`库需要将数据格式化为`numpy`数组。 这是重新格式化的代码。 101 | 102 | ```py 103 | X = training_data.as_matrix(columns=['test_1', 'test_2']) 104 | y = np.array(training_data['outcome']) 105 | ``` 106 | 107 | 这是我们的重点。 我们使用“观测的邻域是其三个最近的邻居”的参数来训练 KNN 学习器。 `weights ='uniform'`可以当做所用的投票系统。 例如,`uniform`意味着所有邻居对观测的类别进行同等权重的“投票”,而`weight ='distance'`则告诉学习器根据到我们正在分类的观测的距离,来调整每个观测的“投票”。 108 | 109 | ```py 110 | clf = neighbors.KNeighborsClassifier(3, weights = 'uniform') 111 | trained_model = clf.fit(X, y) 112 | ``` 113 | 114 | 与训练数据相比,我们训练的模型有多好? 115 | 116 | ```py 117 | trained_model.score(X, y) 118 | 119 | # 0.80000000000000004 120 | ``` 121 | 122 | 我们的模型准确率达 80%! 123 | 124 | 注:在任何现实世界的例子中,我们都希望将训练的模型与一些保留的测试数据进行比较。 但由于这是一个玩具示例,我使用了训练数据。 125 | 126 | 现在我们已经训练了我们的模型,我们可以预测班级的任何新观测,![](img/tex-c39d1645d55ca4afb20c8d6a365615bb.gif)。 我们现在就这样做吧! 127 | 128 | ```py 129 | # 使用 'test_1' 第一个和第二个自变量的值 130 | # 创建一个新观测,为 .4 和 .6 131 | x_test = np.array([[.4,.6]]) 132 | 133 | # 将学习者应用于新的未分类的观测。 134 | trained_model.predict(x_test) 135 | 136 | # array(['loss'], dtype=object) 137 | ``` 138 | 139 | 好哇! 我们可以看到学习器预测的新观测的类是“输”。 140 | 141 | 我们甚至可以查看学习器分配给每个分类的概率: 142 | 143 | ```py 144 | trained_model.predict_proba(x_test) 145 | 146 | # array([[ 0.66666667, 0.33333333]]) 147 | ``` 148 | 149 | 根据这个结果,模型预测观测结果是“输”的概率约为 67%,“赢”的概率为 33%。 因为观测有更大的“输”的概率,所以它预测为这个分类。 150 | 151 | ## 注 152 | 153 | * K 的选择对创建的分类器有重大影响。 154 | * K 越大,决策边界越线性(高偏差和低方差)。 155 | * 有多种方法可以测量距离,两种流行的方法是简单的欧几里德距离和余弦相似度。 156 | 157 | # 基于半径的 KNN 分类器 158 | 159 | ![](img/371afefc20188fb5874a852c50bce6c5.jpg) 160 | 161 | ```py 162 | # 加载库 163 | from sklearn.neighbors import RadiusNeighborsClassifier 164 | from sklearn.preprocessing import StandardScaler 165 | from sklearn import datasets 166 | 167 | # 加载数据 168 | iris = datasets.load_iris() 169 | X = iris.data 170 | y = iris.target 171 | 172 | # 创建标准化器 173 | standardizer = StandardScaler() 174 | 175 | # 标准化特征 176 | X_std = standardizer.fit_transform(X) 177 | ``` 178 | 179 | 在 scikit-learn 中,`RadiusNeighborsClassifier`与`KNeighborsClassifier`非常相似,但有两个参数除外。 首先,在`RadiusNeighborsClassifier`中,我们需要指定固定区域的半径,用于确定观测是否是半径内的邻居。 将半径设置为某个值,最好将其视为任何其他超参数,并在模型选择期间对其进行调整。 第二个有用的参数是`outlier_label`,它表示半径内没有观测的观测的标签 - 这本身通常可以是识别异常值的有用工具。 180 | 181 | ```py 182 | # 训练半径邻居分类器 183 | rnn = RadiusNeighborsClassifier(radius=.5, n_jobs=-1).fit(X_std, y) 184 | 185 | # 创建两个观测 186 | new_observations = [[ 1, 1, 1, 1]] 187 | 188 | # 预测两个观测的类别 189 | rnn.predict(new_observations) 190 | 191 | # array([2]) 192 | ``` -------------------------------------------------------------------------------- /15.md: -------------------------------------------------------------------------------- 1 | # 十五、支持向量机 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 校准 SVC 中的预测概率 10 | 11 | SVC 使用超平面来创建决策区域,不会自然输出观察是某一类成员的概率估计。 但是,我们实际上可以通过一些技巧输出校准的类概率。 在 SVC 中,可以使用 Platt 缩放,其中首先训练 SVC,然后训练单独的交叉验证逻辑回归来将 SVC 输出映射到概率: 12 | 13 | ![](img/tex-fd6a329594a8718f6de1a6d5728eb7b7.gif) 14 | 15 | 其中 ![](img/tex-7fc56270e7a70fa81a5935b72eacbe29.gif) 和 ![](img/tex-9d5ed678fe57bcca610140957afab571.gif) 是参数向量,![](img/tex-8fa14cdd754f91cc6554c9e71929cce7.gif) 是第 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 个观测点与超平面的有符号距离。 当我们有两个以上的类时,使用 Platt 缩放的扩展。 16 | 17 | 在 scikit-learn 中,必须在训练模型时生成预测概率。 这可以通过将`SVC`的`probability`设置为`True`来完成。 在训练模型之后,我们可以使用`predict_proba`输出每个类的估计概率。 18 | 19 | ```py 20 | # 加载库 21 | from sklearn.svm import SVC 22 | from sklearn import datasets 23 | from sklearn.preprocessing import StandardScaler 24 | import numpy as np 25 | 26 | # 加载数据 27 | iris = datasets.load_iris() 28 | X = iris.data 29 | y = iris.target 30 | 31 | # 标准化特征 32 | scaler = StandardScaler() 33 | X_std = scaler.fit_transform(X) 34 | 35 | # 创建支持向量分类器对象 36 | svc = SVC(kernel='linear', probability=True, random_state=0) 37 | 38 | # 训练分类器 39 | model = svc.fit(X_std, y) 40 | 41 | # 创建新的观测 42 | new_observation = [[.4, .4, .4, .4]] 43 | 44 | # 查看预测的概率 45 | model.predict_proba(new_observation) 46 | 47 | # array([[ 0.00588822, 0.96874828, 0.0253635 ]]) 48 | ``` 49 | 50 | ## 寻找最近邻 51 | 52 | ```py 53 | # 加载库 54 | from sklearn.neighbors import NearestNeighbors 55 | from sklearn import datasets 56 | from sklearn.preprocessing import StandardScaler 57 | import numpy as np 58 | 59 | # 加载数据 60 | iris = datasets.load_iris() 61 | X = iris.data 62 | y = iris.target 63 | ``` 64 | 65 | 在计算任何距离之前标准化我们的数据非常重要。 66 | 67 | ```py 68 | # 创建标准化器 69 | standardizer = StandardScaler() 70 | 71 | # 标准化特征 72 | X_std = standardizer.fit_transform(X) 73 | 74 | # 根据欧氏距离找到三个最近邻居(包括其自身) 75 | nn_euclidean = NearestNeighbors(n_neighbors=3, metric='euclidean').fit(X) 76 | 77 | # 列表的列表,表示每个观测的 3 个最近邻 78 | nearest_neighbors_with_self = nn_euclidean.kneighbors_graph(X).toarray() 79 | 80 | # 删除距离自身最近的一个观测 81 | for i, x in enumerate(nearest_neighbors_with_self): 82 | x[i] = 0 83 | 84 | # 查看第一个观测的两个最近邻 85 | nearest_neighbors_with_self[0] 86 | 87 | ''' 88 | array([ 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 89 | 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 90 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 91 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 92 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 93 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 94 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 95 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 96 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 97 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 98 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 99 | 0., 0., 0., 0., 0., 0., 0.]) 100 | ''' 101 | ``` 102 | 103 | ## 寻找支持向量 104 | 105 | ![](img/3c3fec0241cfa4c4f5bb78c571a0f884.jpg) 106 | 107 | ```py 108 | # 加载库 109 | from sklearn.svm import SVC 110 | from sklearn import datasets 111 | from sklearn.preprocessing import StandardScaler 112 | import numpy as np 113 | 114 | # 加载只有两个分类的数据 115 | iris = datasets.load_iris() 116 | X = iris.data[:100,:] 117 | y = iris.target[:100] 118 | 119 | # 标准化特征 120 | scaler = StandardScaler() 121 | X_std = scaler.fit_transform(X) 122 | 123 | # 创建支持向量对象 124 | svc = SVC(kernel='linear', random_state=0) 125 | 126 | # 训练分类器 127 | model = svc.fit(X_std, y) 128 | 129 | # 查看支持向量 130 | model.support_vectors_ 131 | 132 | ''' 133 | array([[-0.5810659 , 0.43490123, -0.80621461, -0.50581312], 134 | [-1.52079513, -1.67626978, -1.08374115, -0.8607697 ], 135 | [-0.89430898, -1.46515268, 0.30389157, 0.38157832], 136 | [-0.5810659 , -1.25403558, 0.09574666, 0.55905661]]) 137 | ''' 138 | 139 | # 查看支持向量的下标 140 | model.support_ 141 | 142 | # array([23, 41, 57, 98], dtype=int32) 143 | 144 | # 查看每个分类的支持向量数 145 | model.n_support_ 146 | 147 | # array([2, 2], dtype=int32) 148 | ``` 149 | 150 | ## SVM 不平衡分类 151 | 152 | 在支持向量机中,![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 是一个超参数,用于确定对观测的错误分类的惩罚。 处理支持向量机中处理不平衡类的一种方法是按类加权 ![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif)。 153 | 154 | ![](img/tex-a276b69c27fa2fc5adb0a238cb21baa3.gif) 155 | 156 | 其中 ![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 是错误分类的惩罚,![](img/tex-e8100be07fa5419af6c6738b934dfca0.gif) 是与类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 频率成反比的权重,![](img/tex-1ae38954f6cba2eafda4e9c34df8d944.gif) 是类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 的 ![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 值。 一般的想法是,增加对少数类的错误分类的惩罚,来防止他们被多数类“淹没”。 157 | 158 | 在 scikit-learn 中,当使用`SVC`时,我们可以通过设置`class_weight ='balanced'`来自动设置 ![](img/tex-1ae38954f6cba2eafda4e9c34df8d944.gif) 的值.`balance`参数自动对类进行加权,使得: 159 | 160 | ![](img/tex-bde5f474d3e4c7e38ddd6440a38a7f4e.gif) 161 | 162 | 其中 ![](img/tex-e8100be07fa5419af6c6738b934dfca0.gif) 是类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 的权重,![](img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif) 是观察数,![](img/tex-4aa861124eff57dd7988faa6753e8b7e.gif) 是类 ![](img/tex-363b122c528f54df4a0446b6bab05515.gif) 中的观测数,![](img/tex-8ce4b16b22b58894aa86c421e8759df3.gif) 是类的总数。 163 | 164 | ```py 165 | # 加载库 166 | from sklearn.svm import SVC 167 | from sklearn import datasets 168 | from sklearn.preprocessing import StandardScaler 169 | import numpy as np 170 | 171 | # 加载只有两个类别的数据 172 | iris = datasets.load_iris() 173 | X = iris.data[:100,:] 174 | y = iris.target[:100] 175 | 176 | # 通过删除前 40 个观察值使类高度不平衡 177 | X = X[40:,:] 178 | y = y[40:] 179 | 180 | # 创建目标向量,表示类别是否为 0 181 | y = np.where((y == 0), 0, 1) 182 | 183 | # 标准化特征 184 | scaler = StandardScaler() 185 | X_std = scaler.fit_transform(X) 186 | 187 | # 创建支持向量分类器 188 | svc = SVC(kernel='linear', class_weight='balanced', C=1.0, random_state=0) 189 | 190 | # 训练分类器 191 | model = svc.fit(X_std, y) 192 | ``` 193 | 194 | ## 绘制支持向量分类器超平面 195 | 196 | ![](img/3f0ca2e88676e335b8b20523ff94fec7.jpg) 197 | 198 | ```py 199 | # 加载库 200 | from sklearn.svm import LinearSVC 201 | from sklearn import datasets 202 | from sklearn.preprocessing import StandardScaler 203 | import numpy as np 204 | from matplotlib import pyplot as plt 205 | 206 | # 加载只有两个分类和两个特征数据 207 | iris = datasets.load_iris() 208 | X = iris.data[:100,:2] 209 | y = iris.target[:100] 210 | 211 | # 标准化特征 212 | scaler = StandardScaler() 213 | X_std = scaler.fit_transform(X) 214 | 215 | # 创建支持向量分类器 216 | svc = LinearSVC(C=1.0) 217 | 218 | # 训练模型 219 | model = svc.fit(X_std, y) 220 | ``` 221 | 222 | 在该可视化中,类 0 的所有观测都是黑色的,类 1 的观测是浅灰色的。 超平面是决定新观测如何分类的决策边界。 具体而言,直线上方的任何观察将分为类 0,而下方的任何观测将分为类 1。 223 | 224 | ```py 225 | # 使用他们的类别绘制数据点和颜色 226 | color = ['black' if c == 0 else 'lightgrey' for c in y] 227 | plt.scatter(X_std[:,0], X_std[:,1], c=color) 228 | 229 | # 创建超平面 230 | w = svc.coef_[0] 231 | a = -w[0] / w[1] 232 | xx = np.linspace(-2.5, 2.5) 233 | yy = a * xx - (svc.intercept_[0]) / w[1] 234 | 235 | # 绘制超平面 236 | plt.plot(xx, yy) 237 | plt.axis("off"), plt.show(); 238 | ``` 239 | 240 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/plot_support_vector_classifier_hyperplane/plot_support_vector_classifier_hyperplane_11_0.png) 241 | 242 | ## 使用 RBF 核时的 SVM 参数 243 | 244 | 在本教程中,我们将使用径向基函数核(RBF)直观地探索支持向量分类器(SVC)中两个参数的影响。 本教程主要依据 Sebastian Raschka 的书 [Python Machine Learning](http://amzn.to/2iyMbpA) 中使用的代码。 245 | 246 | ```py 247 | # 导入可视化分类器的包 248 | from matplotlib.colors import ListedColormap 249 | import matplotlib.pyplot as plt 250 | import warnings 251 | 252 | # 导入执行分类的包 253 | import numpy as np 254 | from sklearn.svm import SVC 255 | ``` 256 | 257 | 你可以忽略以下代码。 它用于可视化分类器的决策区域。 但是,本教程中,不了解函数的工作原理并不重要。 258 | 259 | ```py 260 | def versiontuple(v): 261 | return tuple(map(int, (v.split(".")))) 262 | 263 | def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02): 264 | 265 | # 配置标记生成器和颜色表 266 | markers = ('s', 'x', 'o', '^', 'v') 267 | colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') 268 | cmap = ListedColormap(colors[:len(np.unique(y))]) 269 | 270 | # 绘制决策平面 271 | x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 272 | x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 273 | xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), 274 | np.arange(x2_min, x2_max, resolution)) 275 | Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) 276 | Z = Z.reshape(xx1.shape) 277 | plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap) 278 | plt.xlim(xx1.min(), xx1.max()) 279 | plt.ylim(xx2.min(), xx2.max()) 280 | 281 | for idx, cl in enumerate(np.unique(y)): 282 | plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], 283 | alpha=0.8, c=cmap(idx), 284 | marker=markers[idx], label=cl) 285 | 286 | # 高亮测试样本 287 | if test_idx: 288 | # plot all samples 289 | if not versiontuple(np.__version__) >= versiontuple('1.9.0'): 290 | X_test, y_test = X[list(test_idx), :], y[list(test_idx)] 291 | warnings.warn('Please update to NumPy 1.9.0 or newer') 292 | else: 293 | X_test, y_test = X[test_idx, :], y[test_idx] 294 | 295 | plt.scatter(X_test[:, 0], 296 | X_test[:, 1], 297 | c='', 298 | alpha=1.0, 299 | linewidths=1, 300 | marker='o', 301 | s=55, label='test set') 302 | ``` 303 | 304 | 在这里,我们生成一些非线性可分的数据,我们将用它们训练我们的分类器。 此数据类似于你的训练数据集。 我们的`y`向量中有两个类:蓝色`x`和红色方块。 305 | 306 | ```py 307 | np.random.seed(0) 308 | X_xor = np.random.randn(200, 2) 309 | y_xor = np.logical_xor(X_xor[:, 0] > 0, 310 | X_xor[:, 1] > 0) 311 | y_xor = np.where(y_xor, 1, -1) 312 | 313 | plt.scatter(X_xor[y_xor == 1, 0], 314 | X_xor[y_xor == 1, 1], 315 | c='b', marker='x', 316 | label='1') 317 | plt.scatter(X_xor[y_xor == -1, 0], 318 | X_xor[y_xor == -1, 1], 319 | c='r', 320 | marker='s', 321 | label='-1') 322 | 323 | plt.xlim([-3, 3]) 324 | plt.ylim([-3, 3]) 325 | plt.legend(loc='best') 326 | plt.tight_layout() 327 | plt.show() 328 | ``` 329 | 330 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_9_0.png) 331 | 332 | 使用 SVC 的最基本方法是使用线性核,这意味着决策边界是一条直线(或更高维度的超平面)。 线性核在实践中很少使用,但我想在此处显示它,因为它是 SVC 的最基本版本。 如下所示,它在分类方面不是很好(从红色区域中的所有蓝色`X`,可以看出来)因为数据不是线性的。 333 | 334 | ```py 335 | # 使用线性核创建SVC分类器 336 | svm = SVC(kernel='linear', C=1, random_state=0) 337 | # 训练分类器 338 | svm.fit(X_xor, y_xor) 339 | 340 | # 可视化决策边界 341 | plot_decision_regions(X_xor, y_xor, classifier=svm) 342 | plt.legend(loc='upper left') 343 | plt.tight_layout() 344 | plt.show() 345 | ``` 346 | 347 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_11_0.png) 348 | 349 | 径向基函数是 SVC 中常用的核: 350 | 351 | ![](img/tex-d5cd57541fb4b75d5fdbd688f87323d5.gif) 352 | 353 | 其中 ![](img/tex-6fe2793f9b6ee038f11e89402bbf3c84.gif) 是两个数据点 ![](img/tex-70e59a996bd69a0c21878b4093375e92.gif) 和 ![](img/tex-fc3b69ffc2761499a8f26feaaf2f3057.gif) 之间的欧几里德距离的平方。 如果你不了解,塞巴斯蒂安的书有完整的描述。 但是,对于本教程,重要的是要知道,使用 RBF 核的 SVC 分类器有两个参数:`gamma`和`C`。 354 | 355 | ### Gamma 356 | 357 | `gamma`是 RBF 核的一个参数,可以被认为是核的“扩展”,因此也就是决策区域。 当`gamma`较低时,决策边界的“曲线”非常低,因此决策区域非常宽。 当`gamma`较高时,决策边界的“曲线”很高,这会在数据点周围创建决策边界的孤岛。 我们将在下面非常清楚地看到它。 358 | 359 | ### C 360 | 361 | `C`是 SVC 学习器的参数,是对数据点的错误分类的惩罚。 当`C`很小时,分类器可以使用错误分类的数据点(高偏差,低方差)。 当`C`很大时,分类器因错误分类的数据而受到严重惩罚,因此与之相反来避免任何错误分类的数据点(低偏差,高方差)。 362 | 363 | ## Gamma 364 | 365 | 在下面的四个图表中,我们将相同的 SVC-RBF 分类器应用于相同的数据,同时保持`C`不变。 每个图表之间的唯一区别是每次我们都会增加`gamma`的值。 通过这样做,我们可以直观地看到`gamma`对决策边界的影响。 366 | 367 | ### `Gamma = 0.01` 368 | 369 | 在我们的 SVC 分类器和数据的情况下,当使用像 0.01 这样的低`gamma`时,决策边界不是非常“曲线”,它只是一个巨大的拱门。 370 | 371 | ```py 372 | # 使用 RBF 核创建 SVC 分类器 373 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=1) 374 | # 训练分类器 375 | svm.fit(X_xor, y_xor) 376 | 377 | # 可视化决策边界 378 | plot_decision_regions(X_xor, y_xor, classifier=svm) 379 | plt.legend(loc='upper left') 380 | plt.tight_layout() 381 | plt.show() 382 | ``` 383 | 384 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_15_0.png) 385 | 386 | ### `Gamma = 1.0` 387 | 388 | 当我们将`gamma`增加到 1 时,你会发现很大的不同。 现在,决策边界开始更好地覆盖数据的延展。 389 | 390 | ```py 391 | # 使用 RBF 核创建 SVC 分类器 392 | svm = SVC(kernel='rbf', random_state=0, gamma=1, C=1) 393 | # 训练分类器 394 | svm.fit(X_xor, y_xor) 395 | 396 | # 可视化决策边界 397 | plot_decision_regions(X_xor, y_xor, classifier=svm) 398 | plt.legend(loc='upper left') 399 | plt.tight_layout() 400 | plt.show() 401 | ``` 402 | 403 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_17_0.png) 404 | 405 | ### `Gamma = 10.0` 406 | 407 | `gamma = 10`时,核的延展不太明显。 决策边界开始极大地受到各个数据点(即方差)的影响。 408 | 409 | ```py 410 | # 使用 RBF 核创建 SVC 分类器 411 | svm = SVC(kernel='rbf', random_state=0, gamma=10, C=1) 412 | # 训练分类器 413 | svm.fit(X_xor, y_xor) 414 | 415 | # 可视化决策边界 416 | plot_decision_regions(X_xor, y_xor, classifier=svm) 417 | plt.legend(loc='upper left') 418 | plt.tight_layout() 419 | plt.show() 420 | ``` 421 | 422 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_19_0.png) 423 | 424 | ### `Gamma = 100.0` 425 | 426 | 对于高“伽玛”,决策边界几乎完全依赖于各个数据点,从而形成“孤岛”。 这些数据显然过拟合了。 427 | 428 | ```py 429 | # 使用 RBF 核创建 SVC 分类器 430 | svm = SVC(kernel='rbf', random_state=0, gamma=100, C=1) 431 | # 训练分类器 432 | svm.fit(X_xor, y_xor) 433 | 434 | # 可视化决策边界 435 | plot_decision_regions(X_xor, y_xor, classifier=svm) 436 | plt.legend(loc='upper left') 437 | plt.tight_layout() 438 | plt.show() 439 | ``` 440 | 441 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_21_0.png) 442 | 443 | ## C - 惩罚参数 444 | 445 | 现在我们将对`C`重复这个过程:我们将使用相同的分类器,相同的数据,并保持`gamma`常量不变。 我们唯一要改变的是`C`,错误分类的惩罚。 446 | 447 | ### `C = 1` 448 | 449 | 使用“C = 1”,分类器明显容忍错误分类的数据点。 蓝色区域有许多红点,红色区域有蓝点。 450 | 451 | ```py 452 | # 使用 RBF 核创建 SVC 分类器 453 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=1) 454 | # 训练分类器 455 | svm.fit(X_xor, y_xor) 456 | 457 | # 可视化决策边界 458 | plot_decision_regions(X_xor, y_xor, classifier=svm) 459 | plt.legend(loc='upper left') 460 | plt.tight_layout() 461 | plt.show() 462 | ``` 463 | 464 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_24_0.png) 465 | 466 | ### `C = 10` 467 | 468 | 在`C = 10`时,分类器对错误分类的数据点的容忍度较低,因此决策边界更严格。 469 | 470 | ```py 471 | # 使用 RBF 核创建 SVC 分类器 472 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=10) 473 | # 训练分类器 474 | svm.fit(X_xor, y_xor) 475 | 476 | # 可视化决策边界 477 | plot_decision_regions(X_xor, y_xor, classifier=svm) 478 | plt.legend(loc='upper left') 479 | plt.tight_layout() 480 | plt.show() 481 | ``` 482 | 483 | ![png](svc_parameters_using_rbf_kernel_26_0.png) 484 | 485 | ### C = 1000 486 | 487 | When `C = 1000`, the classifier starts to become very intolerant to misclassified data points and thus the decision boundary becomes less biased and has more variance (i.e. more dependent on the individual data points). 488 | 489 | ```py 490 | # 使用 RBF 核创建 SVC 分类器 491 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=1000) 492 | # 训练分类器 493 | svm.fit(X_xor, y_xor) 494 | 495 | # 可视化决策边界 496 | plot_decision_regions(X_xor, y_xor, classifier=svm) 497 | plt.legend(loc='upper left') 498 | plt.tight_layout() 499 | plt.show() 500 | ``` 501 | 502 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_26_0.png) 503 | 504 | ### `C = 10000` 505 | 506 | 在`C = 10000`时,分类器“非常努力”,不会对数据点进行错误分类,我们会看到过拟合的迹象。 507 | 508 | ```py 509 | # 使用 RBF 核创建 SVC 分类器 510 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=10000) 511 | # 训练分类器 512 | svm.fit(X_xor, y_xor) 513 | 514 | # 可视化决策边界 515 | plot_decision_regions(X_xor, y_xor, classifier=svm) 516 | plt.legend(loc='upper left') 517 | plt.tight_layout() 518 | plt.show() 519 | ``` 520 | 521 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_28_0.png) 522 | 523 | ### `C = 100000` 524 | 525 | 在`C = 100000`时,对于任何错误分类的数据点,分类器都会受到严重惩罚,因此边距很小。 526 | 527 | ```py 528 | # 使用 RBF 核创建 SVC 分类器 529 | svm = SVC(kernel='rbf', random_state=0, gamma=.01, C=100000) 530 | # 训练分类器 531 | svm.fit(X_xor, y_xor) 532 | 533 | # 可视化决策边界 534 | plot_decision_regions(X_xor, y_xor, classifier=svm) 535 | plt.legend(loc='upper left') 536 | plt.tight_layout() 537 | plt.show() 538 | ``` 539 | 540 | ![png](https://chrisalbon.com/machine_learning/support_vector_machines/svc_parameters_using_rbf_kernel/svc_parameters_using_rbf_kernel_30_0.png) 541 | 542 | ## 支持向量分类器 543 | 544 | ![](img/3f0ca2e88676e335b8b20523ff94fec7.jpg) 545 | 546 | SVC 在最大化超平面边距和最小化错误分类之间取得平衡。 在 SVC 中,后者由超参数 ![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 控制,对错误施加惩罚。`C`是 SVC 学习器的参数,是对数据点进行错误分类的惩罚。 当`C`很小时,分类器可以使用错误分类的数据点(高偏差但低方差)。 当`C`很大时,分类器因错误分类的数据而受到严重惩罚,因此向后弯曲避免任何错误分类的数据点(低偏差但高方差)。 547 | 548 | 在 scikit-learn 中,![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 由参数`C`确定,默认为`C = 1.0`。 我们应该将 ![](img/tex-0d61f8370cad1d412f80b84d143e1257.gif) 看做我们应该学习的算法的超参数,我们使用模型选择技术调整它。 549 | 550 | ```py 551 | # 加载库 552 | from sklearn.svm import LinearSVC 553 | from sklearn import datasets 554 | from sklearn.preprocessing import StandardScaler 555 | import numpy as np 556 | 557 | # 加载特征和目标数据 558 | iris = datasets.load_iris() 559 | X = iris.data 560 | y = iris.target 561 | 562 | # 标准化特征 563 | scaler = StandardScaler() 564 | X_std = scaler.fit_transform(X) 565 | 566 | # 创建支持向量分类器 567 | svc = LinearSVC(C=1.0) 568 | 569 | # 训练模型 570 | model = svc.fit(X_std, y) 571 | 572 | # 创建新的观测 573 | new_observation = [[-0.7, 1.1, -1.1 , -1.7]] 574 | 575 | # 预测新观测的类别 576 | svc.predict(new_observation) 577 | 578 | # array([0]) 579 | ``` -------------------------------------------------------------------------------- /16.md: -------------------------------------------------------------------------------- 1 | # 十六、朴素贝叶斯 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 伯努利朴素贝叶斯 10 | 11 | 伯努利朴素贝叶斯分类器假设我们的所有特征都是二元的,它们仅有两个值(例如,已经是独热编码的标称分类特征)。 12 | 13 | ```py 14 | # 加载库 15 | import numpy as np 16 | from sklearn.naive_bayes import BernoulliNB 17 | 18 | # 创建三个二元特征 19 | X = np.random.randint(2, size=(100, 3)) 20 | 21 | # 创建二元目标向量 22 | y = np.random.randint(2, size=(100, 1)).ravel() 23 | 24 | # 查看前十个观测 25 | X[0:10] 26 | 27 | ''' 28 | array([[1, 1, 1], 29 | [0, 1, 0], 30 | [1, 1, 1], 31 | [0, 0, 0], 32 | [1, 0, 1], 33 | [1, 1, 1], 34 | [0, 1, 1], 35 | [1, 1, 1], 36 | [1, 1, 1], 37 | [1, 1, 0]]) 38 | ''' 39 | 40 | # 创建伯努利朴素贝叶斯对象,带有每个类别的先验概率 41 | clf = BernoulliNB(class_prior=[0.25, 0.5]) 42 | 43 | # 训练模型 44 | model = clf.fit(X, y) 45 | ``` 46 | 47 | ## 校准预测概率 48 | 49 | 类别概率是机器学习模型中常见且有用的部分。 在 scikit-learn 中,大多数学习算法允许我们使用`predict_proba`来查看成员的类别预测概率。 例如,如果我们想要仅预测某个类,如果模型预测它们是该类的概率超过 90%,则这非常有用。 然而,一些模型,包括朴素贝叶斯分类器输出的概率,不基于现实世界。 也就是说,`predict_proba`可能预测,观测有 0.70 的机会成为某一类,而实际情况是它是 0.10 或 0.99。 特别是在朴素贝叶斯中,虽然不同目标类别的预测概率的排名是有效的,但是原始预测概率倾向于接近 0 和 1 的极值。 50 | 51 | 为了获得有意义的预测概率,我们需要进行所谓的校准。 在 scikit-learn 中,我们可以使用`CalibratedClassifierCV`类,使用 k-fold 交叉验证创建校准良好的预测概率。 在`CalibratedClassifierCV`中,训练集用于训练模型,测试集用于校准预测概率。返回的预测概率是 k 折的平均值。 52 | 53 | ```py 54 | # 加载库 55 | from sklearn import datasets 56 | from sklearn.naive_bayes import GaussianNB 57 | from sklearn.calibration import CalibratedClassifierCV 58 | 59 | # 加载数据 60 | iris = datasets.load_iris() 61 | X = iris.data 62 | y = iris.target 63 | 64 | # 创建高斯朴素贝叶斯对象 65 | clf = GaussianNB() 66 | 67 | # 使用 sigmoid 校准创建校准的交叉验证 68 | clf_sigmoid = CalibratedClassifierCV(clf, cv=2, method='sigmoid') 69 | 70 | # 校准概率 71 | clf_sigmoid.fit(X, y) 72 | 73 | ''' 74 | CalibratedClassifierCV(base_estimator=GaussianNB(priors=None), cv=2, 75 | method='sigmoid') 76 | ''' 77 | 78 | # 创建新的观测 79 | new_observation = [[ 2.6, 2.6, 2.6, 0.4]] 80 | 81 | # 查看校准概率 82 | clf_sigmoid.predict_proba(new_observation) 83 | 84 | # array([[ 0.31859969, 0.63663466, 0.04476565]]) 85 | ``` 86 | 87 | ## 高斯朴素贝叶斯分类器 88 | 89 | ![](img/6516b9606dafb489e601dc4dcee9eb11.jpg) 90 | 91 | 由于正态分布的假设,高斯朴素贝叶斯最适用于我们所有特征都是连续的情况。 92 | 93 | ```py 94 | # 加载库 95 | from sklearn import datasets 96 | from sklearn.naive_bayes import GaussianNB 97 | 98 | # 加载数据 99 | iris = datasets.load_iris() 100 | X = iris.data 101 | y = iris.target 102 | 103 | # 创建高斯朴素贝叶斯对象,带有每个类别的先验概率 104 | clf = GaussianNB(priors=[0.25, 0.25, 0.5]) 105 | 106 | # 训练模型 107 | model = clf.fit(X, y) 108 | 109 | # 创建新的观测 110 | new_observation = [[ 4, 4, 4, 0.4]] 111 | 112 | # 预测类别 113 | model.predict(new_observation) 114 | 115 | # array([1]) 116 | ``` 117 | 118 | 注意:来自高斯朴素贝叶斯的原始预测概率(使用`predict_proba`输出)未校准。 也就是说,他们不应该是可信的。 如果我们想要创建有用的预测概率,我们将需要使用等渗回归或相关方法来校准它们。 119 | 120 | ## 多项式逻辑回归 121 | 122 | 在多项逻辑回归(MLR)中,我们在 Recipe 15.1 中看到的逻辑函数被 softmax 函数替换: 123 | 124 | ![](img/tex-45fe873d5f83badc655eed13e1cd8ee8.gif) 125 | 126 | 其中 ![](img/tex-08c711a5590de57d9dd77d7b5ba4398f.gif) 是第 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 个观测的目标值 ![](img/tex-8d62e469fb30ed435a668eb5c035b1f6.gif) 是类 ![](img/tex-8ce4b16b22b58894aa86c421e8759df3.gif) 的概率,![](img/tex-a5f3c6a11b03839d46af9fb43c97c188.gif) 是类的总数。MLR 的一个实际优点是使用`predict_proba`方法预测的概率更可靠(即校准更好)。 127 | 128 | ```py 129 | # 加载库 130 | from sklearn.linear_model import LogisticRegression 131 | from sklearn import datasets 132 | from sklearn.preprocessing import StandardScaler 133 | 134 | # 加载数据 135 | iris = datasets.load_iris() 136 | X = iris.data 137 | y = iris.target 138 | 139 | # 标准化特征 140 | scaler = StandardScaler() 141 | X_std = scaler.fit_transform(X) 142 | 143 | # 创建 OVR 逻辑回归对象 144 | clf = LogisticRegression(random_state=0, multi_class='multinomial', solver='newton-cg') 145 | 146 | # 训练模型 147 | model = clf.fit(X_std, y) 148 | 149 | # 创建新的观测 150 | new_observation = [[.5, .5, .5, .5]] 151 | 152 | # 预测类别 153 | model.predict(new_observation) 154 | 155 | # array([1]) 156 | 157 | # 查看预测概率 158 | model.predict_proba(new_observation) 159 | 160 | # array([[ 0.01944996, 0.74469584, 0.2358542 ]]) 161 | ``` 162 | 163 | ## 多项式朴素贝叶斯分类器 164 | 165 | 多项式朴素贝叶斯的工作方式类似于高斯朴素贝叶斯,但假设这些特征是多项式分布的。 在实践中,这意味着当我们具有离散数据(例如,电影评级范围为 1 到 5)时,通常使用该分类器。 166 | 167 | ```py 168 | # 加载库 169 | import numpy as np 170 | from sklearn.naive_bayes import MultinomialNB 171 | from sklearn.feature_extraction.text import CountVectorizer 172 | 173 | # 创建文本 174 | text_data = np.array(['I love Brazil. Brazil!', 175 | 'Brazil is best', 176 | 'Germany beats both']) 177 | 178 | # 创建词袋 179 | count = CountVectorizer() 180 | bag_of_words = count.fit_transform(text_data) 181 | 182 | # 创建特征矩阵 183 | X = bag_of_words.toarray() 184 | 185 | # 创建目标向量 186 | y = np.array([0,0,1]) 187 | 188 | # 创建多项式朴素贝叶斯对象,带有每个类别的先验概率 189 | clf = MultinomialNB(class_prior=[0.25, 0.5]) 190 | 191 | # 训练模型 192 | model = clf.fit(X, y) 193 | 194 | # 创建新的观测 195 | new_observation = [[0, 0, 0, 1, 0, 1, 0]] 196 | 197 | # 预测新观测的类别 198 | model.predict(new_observation) 199 | 200 | # array([0]) 201 | ``` 202 | 203 | ## 从零编写朴素贝叶斯分类器 204 | 205 | 朴素贝叶斯是一种简单的分类器,当只有少量观测可用时,这种分类器表现良好。 在本教程中,我们将从头开始创建一个高斯朴素贝叶斯分类器,并使用它来预测以前未见过的数据点的类别。本教程基于 Wikipedia 的[朴素贝叶斯分类器页面](https://en.wikipedia.org/wiki/Naive_Bayes_classifier)上的示例,我已经用 Python 实现了它并调整了一些符号来改进解释。 206 | 207 | ```py 208 | import pandas as pd 209 | import numpy as np 210 | ``` 211 | 212 | 我们的数据集包含八个个体的数据。 我们将使用数据集构建一个分类器,该分类器接收个体的身高,体重和脚码,并输出其性别预测。 213 | 214 | ```py 215 | # 创建空数据帧 216 | data = pd.DataFrame() 217 | 218 | # 创建我们的目标变量 219 | data['Gender'] = ['male','male','male','male','female','female','female','female'] 220 | 221 | # 创建我们的特征变量 222 | data['Height'] = [6,5.92,5.58,5.92,5,5.5,5.42,5.75] 223 | data['Weight'] = [180,190,170,165,100,150,130,150] 224 | data['Foot_Size'] = [12,11,12,10,6,8,7,9] 225 | 226 | # 查看数据 227 | data 228 | ``` 229 | 230 | | | Gender | Height | Weight | Foot_Size | 231 | | --- | --- | --- | --- | --- | 232 | | 0 | male | 6.00 | 180 | 12 | 233 | | 1 | male | 5.92 | 190 | 11 | 234 | | 2 | male | 5.58 | 170 | 12 | 235 | | 3 | male | 5.92 | 165 | 10 | 236 | | 4 | female | 5.00 | 100 | 6 | 237 | | 5 | female | 5.50 | 150 | 8 | 238 | | 6 | female | 5.42 | 130 | 7 | 239 | | 7 | female | 5.75 | 150 | 9 | 240 | 241 | 上面的数据集用于构造我们的分类器。 下面我们将创建一个新的个体,我们知道它的特征值,但不知道它的性别。我们的目标是预测它的性别。 242 | 243 | ```py 244 | # 创建空数据帧 245 | person = pd.DataFrame() 246 | 247 | # 为这一行创建相同特征值 248 | person['Height'] = [6] 249 | person['Weight'] = [130] 250 | person['Foot_Size'] = [8] 251 | 252 | # 查看数据 253 | person 254 | ``` 255 | 256 | | | Height | Weight | Foot_Size | 257 | | --- | --- | --- | --- | 258 | | 0 | 6 | 130 | 8 | 259 | 260 | 贝叶斯定理是一个着名的方程,它允许我们根据数据进行预测。 这是贝叶斯定理的经典版本: 261 | 262 | ![](img/tex-55ddce33f44e17960c51e0b727ed0c1b.gif) 263 | 264 | 这可能过于抽象,所以让我们替换一些变量以使其更具体。 在贝叶斯分类器中,给定数据的情况下,我们有兴趣找出观测的类别(例如男性或女性,垃圾邮件或非垃圾邮件): 265 | 266 | ![](img/tex-682edd15f544ef9727367918185ee5f4.gif) 267 | 268 | 其中: 269 | 270 | * ![](img/tex-7015ea99e7b80644c1630cdfb0f6bbda.gif) 是特定类别(例如男性) 271 | * ![](img/tex-8a842403dafad0ee564a1a212d19e77a.gif) 是观测的数据 272 | * ![](img/tex-dabc824c5f8ee13faaae5a59fec9afdc.gif) 称为后验 273 | * ![](img/tex-347685e5ebc84836b7aea484b48eb555.gif) 叫做似然 274 | * ![](img/tex-09663031eaa8ade66806d053272e579c.gif) 叫做先验 275 | * ![](img/tex-69c694c13d6cb056f400aff019f023dd.gif) 叫做边缘概率 276 | 277 | 在贝叶斯分类器中,我们计算每个观测的每个类的后验(严格来说,我们只计算后验的分子,但现在忽略它)。 然后,基于后验值最大的类别对观测分类。 在我们的例子中,我们为观测预测两个可能的类别(例如男性和女性),因此我们将计算两个后验:一个用于男性,一个用于女性。 278 | 279 | ![](img/tex-7d627c4584744c44dde8a2e35bcfb90c.gif) 280 | 281 | ![](img/tex-b6253f470c6bf31d67e04d80d43704be.gif) 282 | 283 | 高斯朴素的贝叶斯可能是最受欢迎的贝叶斯分类器。 为了解释这个名称的含义,让我们看一下当我们应用两个类别(男性和女性)和三个特征变量(高度,重量和尺寸)时贝叶斯方程式的样子: 284 | 285 | ![](img/tex-ea7e2e0d45588bedd672db7688459b46.gif) 286 | 287 | ![](img/tex-41410fd2b1e89fe55a7638312d82540c.gif) 288 | 289 | 现在让我们解释一下上面的方程式: 290 | 291 | * ![](img/tex-9081cb9b8d4cd5ee177a3287608f7424.gif) 是先验概率。正如你所看到的,只是观测是男性的概率。 这只是数据集中的男性数量除以数据集中的总人数。 292 | * ![](img/tex-a061b9ec570e172274d24a31b7f2ec4e.gif) 是似然。注意我们已经解释了 ![](img/tex-a6b711ff5b6087f86069d31ba049add7.gif) 所以它现在是数据集中的每个特征。“高斯”和“朴素”来自似然中的两个假设: 293 | 1. 如果你查看似然中的每项,你会注意到,我们假设每个特征彼此不相关。 也就是说,脚码与体重或身高等无关。这显然不是真的,而且是一个“朴素”的假设 - 因此称为“朴素贝叶斯”。 294 | 2. 其次,我们假设特征的值(例如女性的身体,女性的体重)通常是高斯分布的。这意味着 ![](img/tex-de3f198290bfe64e8e3f289f20c44434.gif) 是通过将所需参数输入正态分布的概率密度函数来计算的: 295 | 296 | ![](img/tex-e125e16b9b9b9a753459b31c44e565da.gif) 297 | 298 | * ![](img/tex-5765c72ae234bd48dadb3a8bfd20580b.gif) 可能是贝叶斯方法中最令人困惑的部分之一。 在玩具示例(包括我们的)中,完全可以计算边际概率。 但是,在许多实际情况中,要找到边际概率的值极其困难或不可能(解释为什么超出了本教程的范围)。 对于我们的分类器来说,这并不像你想象的那么严重。 为什么? 因为我们不关心真正的后验值是什么,我们只关心哪个类具有最高的后验值。 并且因为边际概率对于所有类别都是相同的,(1)我们可以忽略分母,(2)只计算每个类的后验分子,(3)选择最大的分子。 也就是说,我们可以忽略后验分母,并仅根据后验分子的相对值进行预测。 299 | 300 | 好的! 理论结束。 现在让我们开始计算贝叶斯方程的所有不同部分。 301 | 302 | 先验可以是常数或概率分布。 在我们的例子中,这只是性别的概率。计算这很简单: 303 | 304 | ```py 305 | # 男性数量 306 | n_male = data['Gender'][data['Gender'] == 'male'].count() 307 | 308 | # 女性数量 309 | n_female = data['Gender'][data['Gender'] == 'female'].count() 310 | 311 | # 总行数 312 | total_ppl = data['Gender'].count() 313 | 314 | # 男性比例 315 | P_male = n_male/total_ppl 316 | 317 | # 女性比例 318 | P_female = n_female/total_ppl 319 | ``` 320 | 321 | 请记住,我们的似然中的每一项(例如 ![](img/tex-de3f198290bfe64e8e3f289f20c44434.gif))都可以看做正态的 PDF。 例如: 322 | 323 | ![](img/tex-e125e16b9b9b9a753459b31c44e565da.gif) 324 | 325 | 这意味着对于每个类别(例如女性)和特征(例如身高)组合,我们需要从数据计算方差和均值。Pandas 让这很容易: 326 | 327 | ```py 328 | # 按性别分组数据,并计算每个特征的均值 329 | data_means = data.groupby('Gender').mean() 330 | 331 | # 查看值 332 | data_means 333 | ``` 334 | 335 | | | Height | Weight | Foot_Size | 336 | | --- | --- | --- | --- | 337 | | Gender | | | | 338 | | female | 5.4175 | 132.50 | 7.50 | 339 | | male | 5.8550 | 176.25 | 11.25 | 340 | 341 | ```py 342 | # 按性别分组数据,并计算每个特征的方差 343 | data_variance = data.groupby('Gender').var() 344 | 345 | # 查看值 346 | data_variance 347 | ``` 348 | 349 | | | Height | Weight | Foot_Size | 350 | | --- | --- | --- | --- | 351 | | Gender | | | | 352 | | female | 0.097225 | 558.333333 | 1.666667 | 353 | | male | 0.035033 | 122.916667 | 0.916667 | 354 | 355 | 现在我们可以创建我们需要的所有变量。 下面的代码可能看起来很复杂,但我们所做的,只是从上面两个表中的每个单元格中创建一个变量。 356 | 357 | ```py 358 | # 男性的均值 359 | male_height_mean = data_means['Height'][data_variance.index == 'male'].values[0] 360 | male_weight_mean = data_means['Weight'][data_variance.index == 'male'].values[0] 361 | male_footsize_mean = data_means['Foot_Size'][data_variance.index == 'male'].values[0] 362 | 363 | # 男性的方差 364 | male_height_variance = data_variance['Height'][data_variance.index == 'male'].values[0] 365 | male_weight_variance = data_variance['Weight'][data_variance.index == 'male'].values[0] 366 | male_footsize_variance = data_variance['Foot_Size'][data_variance.index == 'male'].values[0] 367 | 368 | # Means for female 369 | female_height_mean = data_means['Height'][data_variance.index == 'female'].values[0] 370 | female_weight_mean = data_means['Weight'][data_variance.index == 'female'].values[0] 371 | female_footsize_mean = data_means['Foot_Size'][data_variance.index == 'female'].values[0] 372 | 373 | # Variance for female 374 | female_height_variance = data_variance['Height'][data_variance.index == 'female'].values[0] 375 | female_weight_variance = data_variance['Weight'][data_variance.index == 'female'].values[0] 376 | female_footsize_variance = data_variance['Foot_Size'][data_variance.index == 'female'].values[0] 377 | ``` 378 | 379 | 最后,我们需要创建一个函数来计算每个似然项的概率密度(例如 ![](img/tex-de3f198290bfe64e8e3f289f20c44434.gif))。 380 | 381 | ```py 382 | # 创建计算 p(x | y) 的函数 383 | def p_x_given_y(x, mean_y, variance_y): 384 | 385 | # 将参数输入到概率密度函数 386 | p = 1/(np.sqrt(2*np.pi*variance_y)) * np.exp((-(x-mean_y)**2)/(2*variance_y)) 387 | 388 | # 返回 p 389 | return p 390 | ``` 391 | 392 | 好的! 我们的贝叶斯分类器准备就绪。 请记住,既然我们可以忽略边际概率(分母),我们实际计算的是: 393 | 394 | ![](img/tex-68ce6a2b5a771f689d84ac8e24e31ddf.gif) 395 | 396 | 为此,我们只需要插入未分类个体(`height = 6`)的值,数据集的变量(例如女性身高的均值)和我们上面编写的函数(`p_x_given_y`): 397 | 398 | ```py 399 | # 如果未分类的观测是男性的后验分子 400 | P_male * \ 401 | p_x_given_y(person['Height'][0], male_height_mean, male_height_variance) * \ 402 | p_x_given_y(person['Weight'][0], male_weight_mean, male_weight_variance) * \ 403 | p_x_given_y(person['Foot_Size'][0], male_footsize_mean, male_footsize_variance) 404 | 405 | # 6.1970718438780782e-09 406 | ``` 407 | 408 | ```py 409 | # 如果未分类的观测是女性的后验分子 410 | P_female * \ 411 | p_x_given_y(person['Height'][0], female_height_mean, female_height_variance) * \ 412 | p_x_given_y(person['Weight'][0], female_weight_mean, female_weight_variance) * \ 413 | p_x_given_y(person['Foot_Size'][0], female_footsize_mean, female_footsize_variance) 414 | 415 | # 0.00053779091836300176 416 | ``` 417 | 418 | 因为女性的后验分子大于男性,所以我们预测这个人是女性。 419 | -------------------------------------------------------------------------------- /17.md: -------------------------------------------------------------------------------- 1 | # 十七、聚类 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 凝聚聚类 10 | 11 | ![](img/c936cfb9b6729010955e67e7aa51a4de.jpg) 12 | 13 | ```py 14 | # 加载库 15 | from sklearn import datasets 16 | from sklearn.preprocessing import StandardScaler 17 | from sklearn.cluster import AgglomerativeClustering 18 | 19 | # 加载数据 20 | iris = datasets.load_iris() 21 | X = iris.data 22 | 23 | # 标准化特征 24 | scaler = StandardScaler() 25 | X_std = scaler.fit_transform(X) 26 | ``` 27 | 28 | 在 scikit-learn 中,`AgglomerativeClustering`使用`linkage`参数来确定合并策略,来最小化(1)合并簇的方差(`ward`),(2)来自簇对的观测点的距离均值(`average`) ,或(3)来自簇对的观测之间的最大距离(`complete`)。 29 | 30 | 其他两个参数很有用。 首先,`affinity`参数确定用于`linkage`的距离度量(`minkowski`,`euclidean`等)。 其次,`n_clusters`设置聚类算法将尝试查找的聚类数。 也就是说,簇被连续合并,直到只剩下`n_clusters`。 31 | 32 | ```py 33 | # 创建聚类对象 34 | clt = AgglomerativeClustering(linkage='complete', 35 | affinity='euclidean', 36 | n_clusters=3) 37 | 38 | # 训练模型 39 | model = clt.fit(X_std) 40 | 41 | # 展示簇的成员 42 | model.labels_ 43 | 44 | ''' 45 | array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 46 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 47 | 1, 1, 1, 1, 0, 0, 0, 2, 0, 2, 0, 2, 0, 2, 2, 0, 2, 0, 0, 0, 0, 2, 2, 48 | 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 2, 0, 2, 2, 0, 49 | 2, 2, 2, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 52 | ''' 53 | ``` 54 | 55 | ## DBSCAN 聚类 56 | 57 | ![](img/99cac4640cc847b6e1e8c94a3d85d7cc.jpg) 58 | 59 | ```py 60 | # 加载库 61 | from sklearn import datasets 62 | from sklearn.preprocessing import StandardScaler 63 | from sklearn.cluster import DBSCAN 64 | 65 | # 加载数据 66 | iris = datasets.load_iris() 67 | X = iris.data 68 | 69 | # 标准化特征 70 | scaler = StandardScaler() 71 | X_std = scaler.fit_transform(X) 72 | ``` 73 | 74 | `DBSCAN`有三个要设置的主要参数: 75 | 76 | * `eps`: 观测到被认为是邻居的另一个观测的最大距离 77 | * `min_samples`: 小于上面的`eps`距离的最小观测数量 78 | * `metric`: `eps`使用的距离度量。 例如,`minkowski`,`euclidean`等(请注意,如果使用 Minkowski 距离,参数`p`可用于设置 Minkowski 度量的指数) 79 | 80 | 如果我们在训练数据中查看簇,我们可以看到已经识别出两个簇,“0”和“1”,而异常观测被标记为“-1”。 81 | 82 | ```py 83 | # 创建 DBSCAN 对象 84 | clt = DBSCAN(n_jobs=-1) 85 | 86 | # 训练模型 87 | model = clt.fit(X_std) 88 | ``` 89 | 90 | ## 评估聚类 91 | 92 | ```py 93 | import numpy as np 94 | from sklearn.metrics import silhouette_score 95 | from sklearn import datasets 96 | from sklearn.cluster import KMeans 97 | from sklearn.datasets import make_blobs 98 | 99 | # 生成特征矩阵 100 | X, _ = make_blobs(n_samples = 1000, 101 | n_features = 10, 102 | centers = 2, 103 | cluster_std = 0.5, 104 | shuffle = True, 105 | random_state = 1) 106 | 107 | # 使用 k-means 来对数据聚类 108 | model = KMeans(n_clusters=2, random_state=1).fit(X) 109 | 110 | # 获取预测的类别 111 | y_hat = model.labels_ 112 | ``` 113 | 114 | 正式地,第 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 个观测的轮廓系数是: 115 | 116 | ![](img/tex-08ab6c8d7eefc2ed7722b28e671aa0bc.gif) 117 | 118 | 其中 ![](img/tex-e5a7472d780a5a032c7775cc5e3ce901.gif) 是观测 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 的轮廓系数,![](img/tex-d8dd7d0f3eb7145ca41c711457b7eb8f.gif) 是 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 和同类的所有观测值之间的平均距离,而 ![](img/tex-c9f6d8557ce40f989fa727b5c0bb1ddf.gif) 是 ![](img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif) 和不同类的所有观测的平均距离的最小值。`silhouette_score`返回的值是所有观测值的平均轮廓系数。 轮廓系数介于 -1 和 1 之间,其中 1 表示密集,分离良好的聚类。 119 | 120 | ```py 121 | # 评估模型 122 | silhouette_score(X, y_hat) 123 | 124 | # 0.89162655640721422 125 | ``` 126 | 127 | ## 均值移动聚类 128 | 129 | ![](img/d86fdc26f2d0ab274ac8164975cc622b.jpg) 130 | 131 | ```py 132 | # 加载库 133 | from sklearn import datasets 134 | from sklearn.preprocessing import StandardScaler 135 | from sklearn.cluster import MeanShift 136 | 137 | # 加载数据 138 | iris = datasets.load_iris() 139 | X = iris.data 140 | 141 | # 标准化特征 142 | scaler = StandardScaler() 143 | X_std = scaler.fit_transform(X) 144 | ``` 145 | 146 | `MeanShift`有两个我们应该注意的重要参数。 首先,`bandwidth`设置区域(即观测核)半径,用于确定移动方向。 在我们的比喻中,带宽是一个人可以在雾中看到的距离。 我们可以手动设置此参数,但默认情况下会自动估算合理的带宽(计算成本会显着增加)。 其次,有时在均值移动中,观测核中没有其他观测结果。 也就是说,我们足球上的一个人看不到任何其它人。 默认情况下,`MeanShift`将所有这些“孤例”观测值分配给最近观测核。 但是,如果我们想要留出这些孤例,我们可以设置`cluster_all = False`,其中孤例观测标签为 -1。 147 | 148 | ```py 149 | # 创建 MeanShift 对象 150 | clt = MeanShift(n_jobs=-1) 151 | 152 | # 训练模型 153 | model = clt.fit(X_std) 154 | ``` 155 | 156 | ## 小批量 KMeans 聚类 157 | 158 | 小批量 k-means 的工作方式与上一个方案中讨论的 k-means 算法类似。 没有太多细节,不同之处在于,在小批量 k-means中,计算成本最高的步骤仅在随机的观测样本上进行,而不是所有观测。 这种方法可以显着减少算法发现收敛(即适合数据)所需的时间,而质量成本很低。 159 | 160 | ```py 161 | # 加载库 162 | from sklearn import datasets 163 | from sklearn.preprocessing import StandardScaler 164 | from sklearn.cluster import MiniBatchKMeans 165 | 166 | # 加载数据 167 | iris = datasets.load_iris() 168 | X = iris.data 169 | 170 | # 标准化特征 171 | scaler = StandardScaler() 172 | X_std = scaler.fit_transform(X) 173 | ``` 174 | 175 | `MiniBatchKMeans`与`KMeans`的工作方式类似,有一个显着性差异:`batch_size`参数。 `batch_size`控制每批中随机选择的观测数。 批量越大,训练过程的计算成本就越高。 176 | 177 | ```py 178 | # 创建 KMeans 对象 179 | clustering = MiniBatchKMeans(n_clusters=3, random_state=0, batch_size=100) 180 | 181 | # 训练模型 182 | model = clustering.fit(X_std) 183 | ``` 184 | 185 | ## KMeans 聚类 186 | 187 | ![](img/bce11f1812038907dfc04afe063b942e.jpg) 188 | 189 | ```py 190 | # 加载库 191 | from sklearn import datasets 192 | from sklearn.preprocessing import StandardScaler 193 | from sklearn.cluster import KMeans 194 | 195 | # 加载数据 196 | iris = datasets.load_iris() 197 | X = iris.data 198 | 199 | # 标准化特征 200 | scaler = StandardScaler() 201 | X_std = scaler.fit_transform(X) 202 | 203 | # 创建 KMeans 对象 204 | clt = KMeans(n_clusters=3, random_state=0, n_jobs=-1) 205 | 206 | # 训练模型 207 | model = clt.fit(X_std) 208 | 209 | # 查看预测类别 210 | model.labels_ 211 | 212 | ''' 213 | array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 214 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 215 | 1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 216 | 2, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 217 | 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 218 | 0, 0, 0, 0, 2, 0, 2, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 219 | 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2], dtype=int32) 220 | ''' 221 | 222 | # 创建新的观测 223 | new_observation = [[0.8, 0.8, 0.8, 0.8]] 224 | 225 | # 预测观测的类别 226 | model.predict(new_observation) 227 | 228 | # array([0], dtype=int32) 229 | 230 | # 查看簇中心 231 | model.cluster_centers_ 232 | 233 | ''' 234 | array([[ 1.13597027, 0.09659843, 0.996271 , 1.01717187], 235 | [-1.01457897, 0.84230679, -1.30487835, -1.25512862], 236 | [-0.05021989, -0.88029181, 0.34753171, 0.28206327]]) 237 | ''' 238 | ``` -------------------------------------------------------------------------------- /2.md: -------------------------------------------------------------------------------- 1 | # 二、数据准备 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 从字典加载特征 10 | 11 | ```py 12 | from sklearn.feature_extraction import DictVectorizer 13 | 14 | staff = [{'name': 'Steve Miller', 'age': 33.}, 15 | {'name': 'Lyndon Jones', 'age': 12.}, 16 | {'name': 'Baxter Morth', 'age': 18.}] 17 | 18 | # 为我们的字典向量化器创建对象 19 | vec = DictVectorizer() 20 | 21 | # 之后将 staff 字典转换为向量,并输出数组 22 | vec.fit_transform(staff).toarray() 23 | 24 | ''' 25 | array([[ 33., 0., 0., 1.], 26 | [ 12., 0., 1., 0.], 27 | [ 18., 1., 0., 0.]]) 28 | ''' 29 | 30 | # 获取特征名称 31 | vec.get_feature_names() 32 | 33 | # ['age', 'name=Baxter Morth', 'name=Lyndon Jones', 'name=Steve Miller'] 34 | ``` 35 | 36 | ## 加载 scikit-learn 的波士顿住房数据集 37 | 38 | ```py 39 | # 加载库 40 | from sklearn import datasets 41 | import matplotlib.pyplot as plt 42 | ``` 43 | 44 | ## 加载波士顿住房数据集 45 | 46 | [波士顿住房数据集](http://www.cs.toronto.edu/~delve/data/boston/bostonDetail.html) 是 20 世纪 70 年代的着名数据集。 它包含506个关于波士顿周边房价的观测。 它通常用于回归示例,包含 15 个特征。 47 | 48 | ```py 49 | # 加载数据集 50 | boston = datasets.load_boston() 51 | 52 | # 创建特征矩阵 53 | X = boston.data 54 | 55 | # 创建目标向量 56 | y = boston.target 57 | 58 | # 查看第一个观测的特征值 59 | X[0] 60 | 61 | ''' 62 | array([ 6.32000000e-03, 1.80000000e+01, 2.31000000e+00, 63 | 0.00000000e+00, 5.38000000e-01, 6.57500000e+00, 64 | 6.52000000e+01, 4.09000000e+00, 1.00000000e+00, 65 | 2.96000000e+02, 1.53000000e+01, 3.96900000e+02, 66 | 4.98000000e+00]) 67 | ''' 68 | ``` 69 | 70 | 如你所见,特征未标准化。 如果我们将值显示为小数,则更容易看到: 71 | 72 | ```py 73 | # 将第一个观测的每个特征值展示为浮点 74 | ['{:f}'.format(x) for x in X[0]] 75 | 76 | ''' 77 | ['0.006320', 78 | '18.000000', 79 | '2.310000', 80 | '0.000000', 81 | '0.538000', 82 | '6.575000', 83 | '65.200000', 84 | '4.090000', 85 | '1.000000', 86 | '296.000000', 87 | '15.300000', 88 | '396.900000', 89 | '4.980000'] 90 | ''' 91 | ``` 92 | 93 | 因此,标准化的特征值通常是有益的和/或需要的。 94 | 95 | ## 加载 scikit-learn 的数字数据集 96 | 97 | ```py 98 | # 加载库 99 | from sklearn import datasets 100 | import matplotlib.pyplot as plt 101 | ``` 102 | 103 | 数字是手写数字的数据集。 每个特征是 8×8 图像的一个像素的强度。 104 | 105 | ```py 106 | # 加载数字数据集 107 | digits = datasets.load_digits() 108 | 109 | # 创建特征矩阵 110 | X = digits.data 111 | 112 | # 创建目标向量 113 | y = digits.target 114 | 115 | # 查看第一个观测的特征值 116 | X[0] 117 | 118 | ''' 119 | array([ 0., 0., 5., 13., 9., 1., 0., 0., 0., 0., 13., 120 | 15., 10., 15., 5., 0., 0., 3., 15., 2., 0., 11., 121 | 8., 0., 0., 4., 12., 0., 0., 8., 8., 0., 0., 122 | 5., 8., 0., 0., 9., 8., 0., 0., 4., 11., 0., 123 | 1., 12., 7., 0., 0., 2., 14., 5., 10., 12., 0., 124 | 0., 0., 0., 6., 13., 10., 0., 0., 0.]) 125 | ''' 126 | ``` 127 | 128 | 观测的特征值展示为向量。 但是,通过使用`images`方法,我们可以将相同的特征值加载为矩阵,然后可视化实际的手写字符: 129 | 130 | ```py 131 | # 将第一个观测的特征作为矩阵查看 132 | digits.images[0] 133 | 134 | ''' 135 | array([[ 0., 0., 5., 13., 9., 1., 0., 0.], 136 | [ 0., 0., 13., 15., 10., 15., 5., 0.], 137 | [ 0., 3., 15., 2., 0., 11., 8., 0.], 138 | [ 0., 4., 12., 0., 0., 8., 8., 0.], 139 | [ 0., 5., 8., 0., 0., 9., 8., 0.], 140 | [ 0., 4., 11., 0., 1., 12., 7., 0.], 141 | [ 0., 2., 14., 5., 10., 12., 0., 0.], 142 | [ 0., 0., 6., 13., 10., 0., 0., 0.]]) 143 | ''' 144 | 145 | # 将第一个观测的特征作为图像可视化 146 | plt.gray() 147 | plt.matshow(digits.images[0]) 148 | plt.show() 149 | 150 | # 151 | ``` 152 | 153 | ![png](https://chrisalbon.com/machine_learning/basics/loading_scikit-learns_digits-dataset/loading_scikit-learns_digits-dataset_7_1.png) 154 | 155 | ## 加载 scikit-learn 的鸢尾花数据集 156 | 157 | ```py 158 | # 加载库 159 | from sklearn import datasets 160 | import matplotlib.pyplot as plt 161 | ``` 162 | 163 | The [Iris flower dataset](https://en.wikipedia.org/wiki/Iris_flower_data_set) is one of the most famous databases for classification. It contains three classes (i.e. three species of flowers) with 50 observations per class. 164 | 165 | ```py 166 | # 加载数字数据集 167 | iris = datasets.load_iris() 168 | 169 | # 创建特征矩阵 170 | X = iris.data 171 | 172 | # 创建目标向量 173 | y = iris.target 174 | 175 | # 查看第一个观测的特征值 176 | X[0] 177 | 178 | # array([ 5.1, 3.5, 1.4, 0.2]) 179 | ``` 180 | 181 | ## 为分类制作模拟数据 182 | 183 | ```py 184 | from sklearn.datasets import make_classification 185 | import pandas as pd 186 | 187 | # 创建模拟的特征矩阵和输出向量,带有 100 个样本, 188 | features, output = make_classification(n_samples = 100, 189 | # 十个特征 190 | n_features = 10, 191 | # 五个实际预测输出分类的特征, 192 | n_informative = 5, 193 | # 五个随机特征,和输出分类无关, 194 | n_redundant = 5, 195 | # 三个输出分类 196 | n_classes = 3, 197 | # 第一类有 20% 的观测,第二类有 30%, 198 | # 第三类有 50%,'None' 表示均衡分类。 199 | weights = [.2, .3, .8]) 200 | 201 | # 查看前五个管泽志和它们的 10 个特征 202 | pd.DataFrame(features).head() 203 | ``` 204 | 205 | | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 206 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 207 | | 0 | -1.338796 | 2.218025 | 3.333541 | 2.586772 | -2.050240 | -5.289060 | 4.364050 | 3.010074 | 3.073564 | 0.827317 | 208 | | 1 | 1.535519 | 1.964163 | -0.053789 | 0.610150 | -4.256450 | -6.044707 | 7.617702 | 4.654903 | 0.632368 | 3.234648 | 209 | | 2 | 0.249576 | -4.051890 | -4.578764 | -1.629710 | 2.188123 | 1.488968 | -1.977744 | -2.888737 | -4.957220 | 3.599833 | 210 | | 3 | 3.778789 | -4.797895 | -1.187821 | 0.724315 | 1.083952 | 0.165924 | -0.352818 | 0.615942 | -4.392519 | 1.683278 | 211 | | 4 | 0.856266 | 0.568888 | -0.520666 | -1.970701 | 0.597743 | 2.224923 | 0.065515 | 0.250906 | -1.512495 | -0.859869 | 212 | 213 | ```py 214 | # 查看前五个观测的分类 215 | pd.DataFrame(output).head() 216 | ``` 217 | 218 | | | 0 | 219 | | --- | --- | 220 | | 0 | 2 | 221 | | 1 | 2 | 222 | | 2 | 1 | 223 | | 3 | 2 | 224 | | 4 | 2 | 225 | 226 | ## 为矩阵生成模拟数据 227 | 228 | ```py 229 | from sklearn.datasets import make_blobs 230 | import matplotlib.pyplot as plt 231 | 232 | # 生成特征(X)和输出(Y),带有 200 个样本, 233 | X, y = make_blobs(n_samples = 200, 234 | # 两个特征, 235 | n_features = 2, 236 | # 三个簇, 237 | centers = 3, 238 | # .5 的簇内标准差, 239 | cluster_std = 0.5, 240 | # 并打乱。 241 | shuffle = True) 242 | 243 | # 创建前两个特征的散点图 244 | plt.scatter(X[:,0], 245 | X[:,1]) 246 | 247 | # 展示散点图 248 | plt.show() 249 | ``` 250 | 251 | ![png](https://chrisalbon.com/machine_learning/basics/make_simulated_data_for_clustering/make_simulated_data_for_clustering_6_0.png) 252 | 253 | ## 为回归制作模拟数据 254 | 255 | ```py 256 | import pandas as pd 257 | from sklearn.datasets import make_regression 258 | 259 | # 生成特征,输出和真实的相关度,样本为 100, 260 | features, output, coef = make_regression(n_samples = 100, 261 | # 三个特征, 262 | n_features = 3, 263 | # 只有两个特征是有用的, 264 | n_informative = 2, 265 | # 每个观测有一个目标值, 266 | n_targets = 1, 267 | # 高斯噪声的标准差为 0.0, 268 | noise = 0.0, 269 | # 展示用于生成数据的真实相关度。 270 | coef = True) 271 | 272 | # 查看前五行的特征 273 | pd.DataFrame(features, columns=['Store 1', 'Store 2', 'Store 3']).head() 274 | ``` 275 | 276 | | | Store 1 | Store 2 | Store 3 | 277 | | --- | --- | --- | --- | 278 | | 0 | -0.166697 | -0.177142 | -2.329568 | 279 | | 1 | -0.093566 | -0.544292 | 0.685165 | 280 | | 2 | 0.625958 | -0.193049 | 1.168012 | 281 | | 3 | -0.843925 | -0.567444 | -0.193631 | 282 | | 4 | -1.079227 | -0.819236 | 1.609171 | 283 | 284 | ```py 285 | # 查看前五行的输出 286 | pd.DataFrame(output, columns=['Sales']).head() 287 | ``` 288 | 289 | | | Sales | 290 | | --- | --- | 291 | | 0 | -149.387162 | 292 | | 1 | -4.164344 | 293 | | 2 | 52.166904 | 294 | | 3 | -56.996180 | 295 | | 4 | 27.246575 | 296 | 297 | ```py 298 | # 查看用于生成数据的真实相关度 299 | pd.DataFrame(coef, columns=['True Coefficient Values']) 300 | ``` 301 | 302 | | | True Coefficient Values | 303 | | --- | --- | 304 | | 0 | 0.000000 | 305 | | 1 | 80.654346 | 306 | | 2 | 57.993548 | 307 | 308 | # Scikit 中的感知机 309 | 310 | 感知机学习器是最早的机器学习技术之一,并且仍然是许多现代神经网络的基础。 在本教程中,我们使用感知器学习器来分类[经典的鸢尾花数据集](https://en.wikipedia.org/wiki/Iris_flower_data_set)。这个教程受[ Sebastian Raschka 的 Python 机器学习](http://amzn.to/2iyMbpA)的启发。 311 | 312 | ```py 313 | # 加载所需的库 314 | from sklearn import datasets 315 | from sklearn.preprocessing import StandardScaler 316 | from sklearn.linear_model import Perceptron 317 | from sklearn.model_selection import train_test_split 318 | from sklearn.metrics import accuracy_score 319 | import numpy as np 320 | 321 | # 加载鸢尾花数据集 322 | iris = datasets.load_iris() 323 | 324 | # 创建 X 和 y 数据 325 | X = iris.data 326 | y = iris.target 327 | 328 | # 查看 y 数据的前五个观测 329 | y[:5] 330 | 331 | # array([0, 0, 0, 0, 0]) 332 | 333 | # 查看 x 数据的前五个观测 334 | # 注意有四个独立变量(特征) 335 | X[:5] 336 | 337 | ''' 338 | array([[ 5.1, 3.5, 1.4, 0.2], 339 | [ 4.9, 3\. , 1.4, 0.2], 340 | [ 4.7, 3.2, 1.3, 0.2], 341 | [ 4.6, 3.1, 1.5, 0.2], 342 | [ 5\. , 3.6, 1.4, 0.2]]) 343 | ''' 344 | 345 | # 将数据分割为 70% 训练集和 30% 测试集 346 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) 347 | 348 | # 训练缩放器,将所有特征标准化为均值为 0 和标准差为 1。 349 | sc = StandardScaler() 350 | sc.fit(X_train) 351 | 352 | # StandardScaler(copy=True, with_mean=True, with_std=True) 353 | 354 | # 对 X 训练数据引用缩放器 355 | X_train_std = sc.transform(X_train) 356 | 357 | # 对 X 测试数据应用相同的缩放器 358 | X_test_std = sc.transform(X_test) 359 | 360 | # 创建感知机对象,参数为,40 个迭代,0.1 的学习率 361 | ppn = Perceptron(n_iter=40, eta0=0.1, random_state=0) 362 | 363 | # 训练感知机 364 | ppn.fit(X_train_std, y_train) 365 | 366 | ''' 367 | Perceptron(alpha=0.0001, class_weight=None, eta0=0.1, fit_intercept=True, 368 | n_iter=40, n_jobs=1, penalty=None, random_state=0, shuffle=True, 369 | verbose=0, warm_start=False) 370 | ''' 371 | 372 | # 在 X 数据上应用已训练的感知机,来对 y 测试数据做预测 373 | y_pred = ppn.predict(X_test_std) 374 | 375 | # 查看预测的 y 测试数据 376 | y_pred 377 | 378 | ''' 379 | array([0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 1, 1, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 380 | 2, 1, 0, 0, 2, 1, 0, 0, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1]) 381 | ''' 382 | 383 | # 查看真实的 y 测试数据 384 | y_test 385 | 386 | ''' 387 | array([0, 0, 0, 1, 0, 0, 2, 2, 0, 0, 1, 1, 1, 0, 2, 2, 2, 1, 0, 0, 0, 0, 2, 388 | 2, 1, 1, 0, 2, 1, 1, 1, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1]) 389 | ''' 390 | 391 | # 查看模型准确率,它是:1 -(预测错的观测 / 总观测) 392 | print('Accuracy: %.2f' % accuracy_score(y_test, y_pred)) 393 | 394 | # Accuracy: 0.87 395 | ``` 396 | 397 | # 保存机器学习模型 398 | 399 | 在 scikit 中,有两种方式来保存模型以便将来使用:pickle 字符串和作为文件的 pickled 模型。 400 | 401 | ```py 402 | from sklearn.linear_model import LogisticRegression 403 | from sklearn import datasets 404 | import pickle 405 | from sklearn.externals import joblib 406 | 407 | # 加载鸢尾花数据 408 | iris = datasets.load_iris() 409 | 410 | # 创建特征矩阵 X,和向量 y 411 | X, y = iris.data, iris.target 412 | 413 | # 训练原始的 logistic 回归模型 414 | clf = LogisticRegression(random_state=0) 415 | clf.fit(X, y) 416 | 417 | ''' 418 | LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True, 419 | intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1, 420 | penalty='l2', random_state=0, solver='liblinear', tol=0.0001, 421 | verbose=0, warm_start=False) 422 | ''' 423 | 424 | # 将已训练的模型保存为 pickle 字符串 425 | saved_model = pickle.dumps(clf) 426 | 427 | # 查看 pickled 模型 428 | saved_model 429 | 430 | # b'\x80\x03csklearn.linear_model.logistic\nLogisticRegression\nq\x00)\x81q\x01}q\x02(X\x07\x00\x00\x00penaltyq\x03X\x02\x00\x00\x00l2q\x04X\x0b\x00\x00\x00multi_classq\x05X\x03\x00\x00\x00ovrq\x06X\x08\x00\x00\x00max_iterq\x07KdX\x08\x00\x00\x00classes_q\x08cnumpy.core.multiarray\n_reconstruct\nq\tcnumpy\nndarray\nq\nK\x00\x85q\x0bC\x01bq\x0c\x87q\rRq\x0e(K\x01K\x03\x85q\x0fcnumpy\ndtype\nq\x10X\x02\x00\x00\x00i8q\x11K\x00K\x01\x87q\x12Rq\x13(K\x03X\x01\x00\x00\x00X\t\x00\x00\x00liblinearq?X\x0c\x00\x00\[[email protected]](/cdn-cgi/l/email-protection)' 431 | 432 | # 加载 pickled 模型 433 | clf_from_pickle = pickle.loads(saved_model) 434 | 435 | # 使用加载的 pickled 模型来做预测 436 | clf_from_pickle.predict(X) 437 | 438 | ''' 439 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 440 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 441 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 442 | 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 443 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 444 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 445 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) 446 | ''' 447 | 448 | # 将模型作为 pickle 保存到文件 449 | joblib.dump(clf, 'filename.pkl') 450 | 451 | ''' 452 | ['filename.pkl', 453 | 'filename.pkl_01.npy', 454 | 'filename.pkl_02.npy', 455 | 'filename.pkl_03.npy', 456 | 'filename.pkl_04.npy'] 457 | ''' 458 | 459 | # 从文件加载模型 460 | clf_from_joblib = joblib.load('filename.pkl') 461 | 462 | # 使用加载的模型做预测 463 | clf_from_joblib.predict(X) 464 | 465 | ''' 466 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 467 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 468 | 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 469 | 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 470 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 471 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 472 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]) 473 | ''' 474 | ``` 475 | -------------------------------------------------------------------------------- /21.md: -------------------------------------------------------------------------------- 1 | # 二十一、统计学 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 贝塞尔校正 10 | 11 | 贝塞尔的校正是我们在样本方差和样本标准差的计算中使用 ![](img/tex-a438673491daae8148eae77373b6a467.gif) 而不是 ![](img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif) 的原因。 12 | 13 | 样本方差: 14 | 15 | ![](img/tex-5e956d2dac25a04b1f0384a339af61de.gif) 16 | 17 | 当我们计算样本方差时,我们试图估计总体方差,这是一个未知值。 为了进行这种估计,我们从样本与总体均值的平方差的平均值,来估计未知的总体方差。 这种估计技术的负面影响是,因为我们正在采样,我们更有可能观察到差较小的观测,因为它们更常见(例如它们是分布的中心)。 按照定义我们将低估总体方差。 18 | 19 | 弗里德里希贝塞尔发现,通过将有偏差(未校正)的样本方差 ![](img/tex-9a7cc99da8feacd5e7efd172ae2b9b5d.gif) 乘以 ![](img/tex-b3d4a2c5b40d7af881f9d19730b6ea7c.gif),我们将能够减少这种偏差,从而能够准确估计总体方差和标准差。 乘法的最终结果是无偏样本方差。 20 | 21 | ## 演示中心极限定律 22 | 23 | ```py 24 | # 导入包 25 | import pandas as pd 26 | import numpy as np 27 | 28 | # 将 matplotlib 设为内联 29 | %matplotlib inline 30 | 31 | # 创建空的数据帧 32 | population = pd.DataFrame() 33 | 34 | # 创建一列,它是来自均匀分布的 10000 个随机数 35 | population['numbers'] = np.random.uniform(0,10000,size=10000) 36 | 37 | # 绘制得分数据的直方图 38 | # 这确认了数据不是正态分布的 39 | population['numbers'].hist(bins=100) 40 | 41 | # 42 | ``` 43 | 44 | ![png](https://chrisalbon.com/statistics/frequentist/demonstrate_the_central_limit_theorem/demonstrate_the_central_limit_theorem_5_1.png) 45 | 46 | ```py 47 | # 查看数值的均值 48 | population['numbers'].mean() 49 | 50 | # 4983.824612472138 51 | 52 | # 创建列表 53 | sampled_means = [] 54 | 55 | # 执行 1000 次 56 | for i in range(0,1000): 57 | # 从总体中随机抽取 100 行 58 | # 计算它们的均值,附加到 sampled_means 59 | sampled_means.append(population.sample(n=100).mean().values[0]) 60 | 61 | # 绘制 sampled_means 的直方图 62 | # 它很明显是正态分布的,中心约为 5000 63 | pd.Series(sampled_means).hist(bins=100) 64 | 65 | # 66 | ``` 67 | 68 | ![png](https://chrisalbon.com/statistics/frequentist/demonstrate_the_central_limit_theorem/demonstrate_the_central_limit_theorem_11_1.png) 69 | 70 | 这是关键的图表,记住总体分布是均匀的,然而,这个分布接近正态。 这是中心极限理论的关键点,也是我们可以假设样本均值是无偏的原因。 71 | 72 | ```py 73 | # 查看 sampled_means 的均值 74 | pd.Series(sampled_means).mean() 75 | 76 | # 4981.465310909289 77 | 78 | # 将样本均值的均值减去真实的总体均值 79 | error = population['numbers'].mean() - pd.Series(sampled_means).mean() 80 | 81 | # 打印 82 | print('The Mean Sample Mean is only %f different the True Population mean!' % error) 83 | 84 | # The Mean Sample Mean is only 2.359302 different the True Population mean! 85 | ``` 86 | 87 | ## 皮尔逊相关系数 88 | 89 | 基于 [cbare](http://stackoverflow.com/users/199166/cbare) 的[这个](http://stackoverflow.com/a/17389980/2935984) StackOverflow 答案。 90 | 91 | ```py 92 | import statistics as stats 93 | 94 | x = [1,2,3,4,5,6,7,8,9] 95 | y = [2,1,2,4.5,7,6.5,6,9,9.5] 96 | ``` 97 | 有许多等价的表达方式来计算皮尔逊相关系数(也称为皮尔逊的 r)。这是一个。 98 | 99 | ![](img/tex-ddc7076014b85741e2dbfe52ec40ed52.gif) 100 | 101 | 其中 ![](img/tex-6b5eaa31568b521152a5aacec91548c2.gif) 和 ![](img/tex-8c06f77a048c7032b6258f4ceddcac77.gif) 是 ![](img/tex-9dd4e461268c8034f5c8564e155c67a6.gif) 和 ![](img/tex-5fdb0734a2a8679264029c65df7a492b.gif) 的标准差,![](img/tex-9ed438b9777ace57e974cb63995679ed.gif) 是 ![](img/tex-9dd4e461268c8034f5c8564e155c67a6.gif) 和 ![](img/tex-415290769594460e2e485922904f345d.gif) 的[标准得分](https://en.wikipedia.org/wiki/Standard_score)。 102 | 103 | ```py 104 | # 创建函数 105 | def pearson(x,y): 106 | 107 | # 创建 n,数据中的观测数量 108 | n = len(x) 109 | 110 | # 创建列表来储存标准得分 111 | standard_score_x = [] 112 | standard_score_y = [] 113 | 114 | # 计算 x 的均值 115 | mean_x = stats.mean(x) 116 | 117 | # 计算 x 的标准差 118 | standard_deviation_x = stats.stdev(x) 119 | 120 | # 计算 y 的均值 121 | mean_y = stats.mean(y) 122 | 123 | # 计算 y 的标准差 124 | standard_deviation_y = stats.stdev(y) 125 | 126 | # 对于 x 中的每个观测 127 | for observation in x: 128 | 129 | # 计算 x 的标准得分 130 | standard_score_x.append((observation - mean_x)/standard_deviation_x) 131 | 132 | # 对于 y 中的每个观测 133 | for observation in y: 134 | 135 | # 计算 y 的标准得分 136 | standard_score_y.append((observation - mean_y)/standard_deviation_y) 137 | 138 | # 将标准得分加在一起,求和,然后除以 n-1,返回该值 139 | return (sum([i*j for i,j in zip(standard_score_x, standard_score_y)]))/(n-1) 140 | 141 | # 展示皮尔逊相关系数 142 | pearson(x,y) 143 | 144 | # 0.9412443251336238 145 | ``` 146 | 147 | ## 概率质量函数(PMF) 148 | 149 | ```py 150 | # 加载库 151 | import matplotlib.pyplot as plt 152 | 153 | # 创建一些随机整数 154 | data = [3,2,3,4,2,3,5,2,2,3,3,5,2,2,5,6,2,2,2,3,6,6,2,4,3,2,3] 155 | 156 | # 创建字典来储存计数 157 | count = {} 158 | 159 | # 对于数据中的每个值 160 | for observation in data: 161 | # 键为观测,值递增 162 | count[observation] = count.get(observation, 0) + 1 163 | 164 | # 计算观测数量 observations 165 | n = len(data) 166 | 167 | # 创建字典 168 | probability_mass_function = {} 169 | 170 | # 对于每个唯一值 171 | for unique_value, count in count.items(): 172 | # 将计数归一化,通过除以数据量,添加到 PMC 字典 173 | probability_mass_function[unique_value] = count / n 174 | 175 | # 绘制概率质量函数 176 | plt.bar(list(probability_mass_function.keys()), probability_mass_function.values(), color='g') 177 | plt.show() 178 | ``` 179 | 180 | ![png](https://chrisalbon.com/statistics/frequentist/probability_mass_functions/probability_mass_functions_10_0.png) 181 | 182 | ## Spearman 排名相关度 183 | 184 | ```py 185 | import numpy as np 186 | import pandas as pd 187 | import scipy.stats 188 | 189 | # 创建两列随机变量 190 | x = [1,2,3,4,5,6,7,8,9] 191 | y = [2,1,2,4.5,7,6.5,6,9,9.5] 192 | ``` 193 | 194 | Spearman 的排名相关度,是变量的排名版本的皮尔逊相关系数。 195 | 196 | ```py 197 | # 创建接受 x 和 y 的函数 198 | def spearmans_rank_correlation(xs, ys): 199 | 200 | # 计算 x 的排名 201 | #(也就是排序后元素的位置) 202 | xranks = pd.Series(xs).rank() 203 | 204 | # 计算 y 的排名 205 | yranks = pd.Series(ys).rank() 206 | 207 | # 在数据的排名版本上,计算皮尔逊相关系数 208 | return scipy.stats.pearsonr(xranks, yranks) 209 | 210 | # 运行函数 211 | spearmans_rank_correlation(x, y)[0] 212 | 213 | # 0.90377360145618091 214 | 215 | # 仅仅检查我们的结果,使用 Scipy 的 Spearman 216 | scipy.stats.spearmanr(x, y)[0] 217 | 218 | # 0.90377360145618102 219 | ``` 220 | 221 | ## T 检验 222 | 223 | ```py 224 | from scipy import stats 225 | import numpy as np 226 | 227 | # 创建 20 个观测的列表,从均值为 1, 228 | # 标准差为 1.5 的正态分布中随机抽取 229 | x = np.random.normal(1, 1.5, 20) 230 | 231 | # 创建 20 个观测的列表,从均值为 0, 232 | # 标准差为 1.5 的正态分布中随机抽取 233 | y = np.random.normal(0, 1.5, 20) 234 | ``` 235 | 236 | ### 单样本双边 T 检验 237 | 238 | 想象一下单样本 T 检验,并绘制一个“正态形状的”山丘,以`1`为中心,并以`1.5`为标准差而“展开”,然后在`0`处放置一个标志并查看标志在山丘上的位置。它靠近顶部吗? 或者远离山丘? 如果标志靠近山丘的底部或更远,则 t 检验的 p 值将低于`0.05`。 239 | 240 | ```py 241 | # 运行 T 检验来检验 x 的均值和 0 相比,是否有统计学显著的差异 242 | pvalue = stats.ttest_1samp(x, 0)[1] 243 | 244 | # 查看 p 值 245 | pvalue 246 | 247 | # 0.00010976647757800537 248 | ``` 249 | 250 | ### 双样本非配对等方差双边 T 检验 251 | 252 | 想象一下单样本 T 检验,并根据标准差绘制两个(正态形状的)山丘,以它们的均值为中心,并根据他们的标准差绘制它们的“平坦度”(个体延展度)。 T 检验考察了两座山丘重叠的程度。 它们基本上是彼此覆盖的吗? 山丘的底部几乎没有碰到吗? 如果山丘的尾部刚刚重叠或根本不重叠,则 t 检验的 p 值将低于 0.05。 253 | 254 | ```py 255 | stats.ttest_ind(x, y)[1] 256 | 257 | # 0.00035082056802728071 258 | 259 | stats.ttest_ind(x, y, equal_var=False)[1] 260 | 261 | # 0.00035089238660076095 262 | ``` 263 | 264 | ### 双样本配对双边 T 检验 265 | 266 | 当我们采集重复样本,并且想要考虑我们正在测试的两个分布是成对的这一事实时,使用配对 T 检验。 267 | 268 | ```py 269 | stats.ttest_rel(x, y)[1] 270 | 271 | # 0.00034222792790150386 272 | ``` 273 | 274 | ## 方差和标准差 275 | 276 | ```py 277 | # 导入包 278 | import math 279 | 280 | # 创建值的列表 281 | data = [3,2,3,4,2,3,5,2,2,33,3,5,2,2,5,6,62,2,2,3,6,6,2,23,3,2,3] 282 | ``` 283 | 284 | 方差是衡量数据分布延展度的指标。 方差越大,数据点越“分散”。 方差,通常表示为 ![](img/tex-10ac877830803e44c3b7dc1b104101dd.gif),计算方式如下: 285 | 286 | ![](img/tex-cea485c1212579d0e0fb0f665f5a85dd.gif) 287 | 288 | ![](img/tex-48d71f5dc3c36e27922ff67fe9e88c6e.gif) 289 | 290 | 其中 ![](img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif) 是观测数,![](img/tex-6fbdf291cda891b99cf211417ad1df18.gif) 是观察值的平均值,![](img/tex-d5530fdea73b725bbdb348dee89e4a20.gif) 是单个观察值减去数据均值。 请注意,如果我们根据来自该总体的样本估计总体的方差,我们应该使用第二个等式,将 ![](img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif) 替换为 ![](img/tex-a438673491daae8148eae77373b6a467.gif)。 291 | 292 | ```py 293 | # 计算 n 294 | n = len(data) 295 | 296 | # 计算均值 297 | mean = sum(data)/len(data) 298 | 299 | # 从均值创建所有观测的差 300 | all_deviations_from_mean_squared = [] 301 | 302 | # 对于数据中的每个观测 303 | for observation in data: 304 | 305 | # 计算到均值的差 306 | deviation_from_mean = (observation - mean) 307 | 308 | # 计算平方 309 | deviation_from_mean_squared = deviation_from_mean**2 310 | 311 | # 将结果添加到列表 312 | all_deviations_from_mean_squared.append(deviation_from_mean_squared) 313 | 314 | # 对于列表中所有平方差求和 315 | sum_of_deviations_from_mean_squared = sum(all_deviations_from_mean_squared) 316 | 317 | # 除以 n 318 | population_variance = sum_of_deviations_from_mean_squared/n 319 | 320 | # 展示方差 321 | population_variance 322 | 323 | # 160.78463648834017 324 | ``` 325 | 326 | 标准差就是方差的平方根。 327 | 328 | ```py 329 | # 计算总体方差的平方根 330 | population_standard_deviation = math.sqrt(population_variance) 331 | 332 | # 打印总体标准差 333 | population_standard_deviation 334 | 335 | # 12.68008818929664 336 | ``` -------------------------------------------------------------------------------- /3.md: -------------------------------------------------------------------------------- 1 | # 三、数据预处理 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 为 Scikit-Learn 转换 Pandas 类别数据 10 | 11 | ```py 12 | # 导入所需的库 13 | from sklearn import preprocessing 14 | import pandas as pd 15 | 16 | raw_data = {'patient': [1, 1, 1, 2, 2], 17 | 'obs': [1, 2, 3, 1, 2], 18 | 'treatment': [0, 1, 0, 1, 0], 19 | 'score': ['strong', 'weak', 'normal', 'weak', 'strong']} 20 | df = pd.DataFrame(raw_data, columns = ['patient', 'obs', 'treatment', 'score']) 21 | 22 | # 创建标签(类别)编码对象 23 | le = preprocessing.LabelEncoder() 24 | 25 | # 使编码器拟合 pandas 列 26 | le.fit(df['score']) 27 | 28 | # LabelEncoder() 29 | 30 | # 查看标签(如果你希望) 31 | list(le.classes_) 32 | 33 | # ['normal', 'strong', 'weak'] 34 | 35 | # 将拟合的编码器应用于 pandas 列 36 | le.transform(df['score']) 37 | 38 | # array([1, 2, 0, 2, 1]) 39 | 40 | # 将一些整数转换为它们的类别名称 41 | list(le.inverse_transform([2, 2, 1])) 42 | 43 | # ['weak', 'weak', 'strong'] 44 | ``` 45 | 46 | ## 删除带缺失值的观测 47 | 48 | ```py 49 | # 加载库 50 | import numpy as np 51 | import pandas as pd 52 | 53 | # 创建特征矩阵 54 | X = np.array([[1.1, 11.1], 55 | [2.2, 22.2], 56 | [3.3, 33.3], 57 | [4.4, 44.4], 58 | [np.nan, 55]]) 59 | 60 | # 移除带缺失值的观测 61 | X[~np.isnan(X).any(axis=1)] 62 | 63 | ''' 64 | array([[ 1.1, 11.1], 65 | [ 2.2, 22.2], 66 | [ 3.3, 33.3], 67 | [ 4.4, 44.4]]) 68 | ''' 69 | ``` 70 | 71 | ## 删除缺失值 72 | 73 | ```py 74 | # 加载库 75 | import numpy as np 76 | import pandas as pd 77 | 78 | # 创建特征矩阵 79 | X = np.array([[1, 2], 80 | [6, 3], 81 | [8, 4], 82 | [9, 5], 83 | [np.nan, 4]]) 84 | 85 | # 移除带缺失值的观测 86 | X[~np.isnan(X).any(axis=1)] 87 | 88 | array([[ 1., 2.], 89 | [ 6., 3.], 90 | [ 8., 4.], 91 | [ 9., 5.]]) 92 | 93 | # 将数据加载为数据帧 94 | df = pd.DataFrame(X, columns=['feature_1', 'feature_2']) 95 | 96 | # 移除带缺失值的观测 97 | df.dropna() 98 | ``` 99 | 100 | | | feature_1 | feature_2 | 101 | | --- | --- | --- | 102 | | 0 | 1.0 | 2.0 | 103 | | 1 | 6.0 | 3.0 | 104 | | 2 | 8.0 | 4.0 | 105 | | 3 | 9.0 | 5.0 | 106 | 107 | ## 检测离群点 108 | 109 | ```py 110 | # 加载库 111 | import numpy as np 112 | from sklearn.covariance import EllipticEnvelope 113 | from sklearn.datasets import make_blobs 114 | 115 | # 创建模拟数据 116 | X, _ = make_blobs(n_samples = 10, 117 | n_features = 2, 118 | centers = 1, 119 | random_state = 1) 120 | 121 | # 将第一个观测值替换为异常值 122 | X[0,0] = 10000 123 | X[0,1] = 10000 124 | ``` 125 | 126 | `EllipticEnvelope`假设数据是正态分布的,并且基于该假设,在数据周围“绘制”椭圆,将椭圆内的任何观测分类为正常(标记为`1`),并将椭圆外的任何观测分类为异常值(标记为`-1`)。 这种方法的一个主要限制是,需要指定一个`contamination`参数,该参数是异常观测值的比例,这是我们不知道的值。 127 | 128 | ```py 129 | # 创建检测器 130 | outlier_detector = EllipticEnvelope(contamination=.1) 131 | 132 | # 拟合检测器 133 | outlier_detector.fit(X) 134 | 135 | # 预测离群点 136 | outlier_detector.predict(X) 137 | 138 | # array([-1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 139 | ``` 140 | 141 | ## 离散化特征 142 | 143 | ```py 144 | # 加载库 145 | from sklearn.preprocessing import Binarizer 146 | import numpy as np 147 | 148 | # 创建特征 149 | age = np.array([[6], 150 | [12], 151 | [20], 152 | [36], 153 | [65]]) 154 | 155 | # 创建二值化器 156 | binarizer = Binarizer(18) 157 | 158 | # 转换特征 159 | binarizer.fit_transform(age) 160 | 161 | ''' 162 | array([[0], 163 | [0], 164 | [1], 165 | [1], 166 | [1]]) 167 | ''' 168 | 169 | # 对特征分箱 170 | np.digitize(age, bins=[20,30,64]) 171 | 172 | ''' 173 | array([[0], 174 | [0], 175 | [1], 176 | [2], 177 | [3]]) 178 | ''' 179 | ``` 180 | 181 | ## 编码序数类别特征 182 | 183 | ```py 184 | # 加载库 185 | import pandas as pd 186 | 187 | # 创建特征 188 | df = pd.DataFrame({'Score': ['Low', 189 | 'Low', 190 | 'Medium', 191 | 'Medium', 192 | 'High']}) 193 | 194 | # 查看数据帧 195 | df 196 | ``` 197 | 198 | | | Score | 199 | | --- | --- | 200 | | 0 | Low | 201 | | 1 | Low | 202 | | 2 | Medium | 203 | | 3 | Medium | 204 | | 4 | High | 205 | 206 | ### 创建比例映射 207 | 208 | ```py 209 | # 创建映射器 210 | scale_mapper = {'Low':1, 211 | 'Medium':2, 212 | 'High':3} 213 | 214 | # 将特征值映射为比例 215 | df['Scale'] = df['Score'].replace(scale_mapper) 216 | 217 | # 查看数据帧 218 | df 219 | ``` 220 | 221 | | | Score | Scale | 222 | | --- | --- | --- | 223 | | 0 | Low | 1 | 224 | | 1 | Low | 1 | 225 | | 2 | Medium | 2 | 226 | | 3 | Medium | 2 | 227 | | 4 | High | 3 | 228 | 229 | ## 使用下采样处理不平衡类 230 | 231 | ![](img/a98f870fa95d64ec22552e8db8a4dd7f.jpg) 232 | 233 | 在下采样中,我们从多数类(即具有更多观测值的类)中不放回随机抽样,来创建与少数类相等的新观测子集。 234 | 235 | ```py 236 | # 加载库 237 | import numpy as np 238 | from sklearn.datasets import load_iris 239 | 240 | # 加载鸢尾花数据 241 | iris = load_iris() 242 | 243 | # 创建特征矩阵 244 | X = iris.data 245 | 246 | # 创建目标向量 247 | y = iris.target 248 | 249 | # 移除前 40 个观测 250 | X = X[40:,:] 251 | y = y[40:] 252 | 253 | # 创建二元目标向量,表示是否是类 0 254 | y = np.where((y == 0), 0, 1) 255 | 256 | # 查看不平衡的目标向量 257 | y 258 | 259 | ''' 260 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 261 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 262 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 263 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 264 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 265 | ''' 266 | 267 | # 每个类别的观测的下标 268 | i_class0 = np.where(y == 0)[0] 269 | i_class1 = np.where(y == 1)[0] 270 | 271 | # 每个类别的观测数量 272 | n_class0 = len(i_class0) 273 | n_class1 = len(i_class1) 274 | 275 | # 对于类 0 的每个观测,随机从类 1 不放回采样 276 | i_class1_downsampled = np.random.choice(i_class1, size=n_class0, replace=False) 277 | 278 | # 将类 0 的目标向量,和下采样的类 1 的目标向量连接到一起 279 | np.hstack((y[i_class0], y[i_class1_downsampled])) 280 | 281 | # array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 282 | ``` 283 | 284 | ## 使用上采样处理不平衡类别 285 | 286 | ![](img/05fb264e8717acd28d1574bee4090029.jpg) 287 | 288 | 在上采样中,对于多数类中的每个观测,我们从少数类中带放回随机选择观测。 最终结果是来自少数类和多数类的观测数量相同。 289 | 290 | ```py 291 | # 加载库 292 | import numpy as np 293 | from sklearn.datasets import load_iris 294 | 295 | # 加载鸢尾花数据 296 | iris = load_iris() 297 | 298 | # 创建特征矩阵 299 | X = iris.data 300 | 301 | # 创建目标向量 302 | y = iris.target 303 | 304 | # 移除前 40 个观测 305 | X = X[40:,:] 306 | y = y[40:] 307 | 308 | # 创建二元目标向量,表示是否是类 0 309 | y = np.where((y == 0), 0, 1) 310 | 311 | # 查看不平衡的目标向量 312 | y 313 | 314 | ''' 315 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 316 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 317 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 318 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 319 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 320 | ''' 321 | 322 | # 每个类别的观测的下标 323 | i_class0 = np.where(y == 0)[0] 324 | i_class1 = np.where(y == 1)[0] 325 | 326 | # 每个类别的观测数量 327 | n_class0 = len(i_class0) 328 | n_class1 = len(i_class1) 329 | 330 | # 对于类 1 中的每个观测,我们从类 0 中带放回随机选择观测。 331 | i_class0_upsampled = np.random.choice(i_class0, size=n_class1, replace=True) 332 | 333 | # 将类 0 的上采样的目标向量,和类 1 的目标向量连接到一起 334 | np.concatenate((y[i_class0_upsampled], y[i_class1])) 335 | 336 | ''' 337 | array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 338 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 339 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 340 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 341 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 342 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 343 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 344 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 345 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 346 | ''' 347 | ``` 348 | 349 | ## 处理离群点 350 | 351 | ![](img/3375cf9c5dcba56ec89d3c109d477b42.jpg) 352 | 353 | ```py 354 | # 加载库 355 | import pandas as pd 356 | 357 | # 创建 DataFrame 358 | houses = pd.DataFrame() 359 | houses['Price'] = [534433, 392333, 293222, 4322032] 360 | houses['Bathrooms'] = [2, 3.5, 2, 116] 361 | houses['Square_Feet'] = [1500, 2500, 1500, 48000] 362 | 363 | houses 364 | ``` 365 | 366 | | | Price | Bathrooms | Square_Feet | 367 | | --- | --- | --- | --- | 368 | | 0 | 534433 | 2.0 | 1500 | 369 | | 1 | 392333 | 3.5 | 2500 | 370 | | 2 | 293222 | 2.0 | 1500 | 371 | | 3 | 4322032 | 116.0 | 48000 | 372 | 373 | ### 选择 1:丢弃 374 | 375 | ```py 376 | # 丢弃大于某个值的观测 377 | houses[houses['Bathrooms'] < 20] 378 | ``` 379 | 380 | | | Price | Bathrooms | Square_Feet | 381 | | --- | --- | --- | --- | 382 | | 0 | 534433 | 2.0 | 1500 | 383 | | 1 | 392333 | 3.5 | 2500 | 384 | | 2 | 293222 | 2.0 | 1500 | 385 | 386 | ### 选择 2:标记 387 | 388 | ```py 389 | # 加载库 390 | import numpy as np 391 | 392 | # 基于布尔条件创建特征 393 | houses['Outlier'] = np.where(houses['Bathrooms'] < 20, 0, 1) 394 | 395 | # 展示数据 396 | houses 397 | ``` 398 | 399 | | | Price | Bathrooms | Square_Feet | Outlier | 400 | | --- | --- | --- | --- | --- | 401 | | 0 | 534433 | 2.0 | 1500 | 0 | 402 | | 1 | 392333 | 3.5 | 2500 | 0 | 403 | | 2 | 293222 | 2.0 | 1500 | 0 | 404 | | 3 | 4322032 | 116.0 | 48000 | 1 | 405 | 406 | ### 选择 3:重缩放 407 | 408 | ```py 409 | # 对数特征 410 | houses['Log_Of_Square_Feet'] = [np.log(x) for x in houses['Square_Feet']] 411 | 412 | # 展示数据 413 | houses 414 | ``` 415 | 416 | | | Price | Bathrooms | Square_Feet | Outlier | Log_Of_Square_Feet | 417 | | --- | --- | --- | --- | --- | --- | 418 | | 0 | 534433 | 2.0 | 1500 | 0 | 7.313220 | 419 | | 1 | 392333 | 3.5 | 2500 | 0 | 7.824046 | 420 | | 2 | 293222 | 2.0 | 1500 | 0 | 7.313220 | 421 | | 3 | 4322032 | 116.0 | 48000 | 1 | 10.778956 | 422 | 423 | # 使用均值填充缺失值 424 | 425 | 均值插补用该特征/变量的平均值替换缺失值。 平均插补是最“朴素”的插补方法之一,因为不像 k 最近邻居插补这样的更复杂的方法,它不会使用观测的信息来估计它的值。 426 | 427 | ```py 428 | import pandas as pd 429 | import numpy as np 430 | from sklearn.preprocessing import Imputer 431 | 432 | # 创建空数据集 433 | df = pd.DataFrame() 434 | 435 | # 创建两个变量,叫做 x0 和 x1 436 | # 使 x1 的第一个值为缺失值 437 | df['x0'] = [0.3051,0.4949,0.6974,0.3769,0.2231,0.341,0.4436,0.5897,0.6308,0.5] 438 | df['x1'] = [np.nan,0.2654,0.2615,0.5846,0.4615,0.8308,0.4962,0.3269,0.5346,0.6731] 439 | 440 | # 观察数据集 441 | df 442 | ``` 443 | 444 | | | x0 | x1 | 445 | | --- | --- | --- | 446 | | 0 | 0.3051 | NaN | 447 | | 1 | 0.4949 | 0.2654 | 448 | | 2 | 0.6974 | 0.2615 | 449 | | 3 | 0.3769 | 0.5846 | 450 | | 4 | 0.2231 | 0.4615 | 451 | | 5 | 0.3410 | 0.8308 | 452 | | 6 | 0.4436 | 0.4962 | 453 | | 7 | 0.5897 | 0.3269 | 454 | | 8 | 0.6308 | 0.5346 | 455 | | 9 | 0.5000 | 0.6731 | 456 | 457 | ### 拟合填充器 458 | 459 | ```py 460 | # 创建一个填充器对象,它寻找 NaN 值,之后将它们按列替换为特征的均值 461 | mean_imputer = Imputer(missing_values='NaN', strategy='mean', axis=0) 462 | 463 | # 在 df 数据及上训练填充器 464 | mean_imputer = mean_imputer.fit(df) 465 | 466 | # 将填充器应用于 df 数据集 467 | imputed_df = mean_imputer.transform(df.values) 468 | 469 | # 查看数据 470 | imputed_df 471 | 472 | ''' 473 | array([[ 0.3051 , 0.49273333], 474 | [ 0.4949 , 0.2654 ], 475 | [ 0.6974 , 0.2615 ], 476 | [ 0.3769 , 0.5846 ], 477 | [ 0.2231 , 0.4615 ], 478 | [ 0.341 , 0.8308 ], 479 | [ 0.4436 , 0.4962 ], 480 | [ 0.5897 , 0.3269 ], 481 | [ 0.6308 , 0.5346 ], 482 | [ 0.5 , 0.6731 ]]) 483 | ''' 484 | ``` 485 | 486 | 请注意,`0.49273333`是估算值,取代了`np.NaN`值。 487 | 488 | ## 填充缺失的类标签 489 | 490 | ```py 491 | # 加载库 492 | import numpy as np 493 | from sklearn.preprocessing import Imputer 494 | 495 | # 创建带有类别特征的特征矩阵 496 | X = np.array([[0, 2.10, 1.45], 497 | [1, 1.18, 1.33], 498 | [0, 1.22, 1.27], 499 | [0, -0.21, -1.19], 500 | [np.nan, 0.87, 1.31], 501 | [np.nan, -0.67, -0.22]]) 502 | 503 | # 创建填充器对象 504 | imputer = Imputer(strategy='most_frequent', axis=0) 505 | 506 | # 使用最频繁的类别填充缺失值 507 | imputer.fit_transform(X) 508 | 509 | ''' 510 | array([[ 0. , 2.1 , 1.45], 511 | [ 1. , 1.18, 1.33], 512 | [ 0. , 1.22, 1.27], 513 | [ 0. , -0.21, -1.19], 514 | [ 0. , 0.87, 1.31], 515 | [ 0. , -0.67, -0.22]]) 516 | ''' 517 | ``` 518 | 519 | ## 使用 KNN 填充缺失类别 520 | 521 | ```py 522 | # 加载库 523 | import numpy as np 524 | from sklearn.neighbors import KNeighborsClassifier 525 | 526 | # 创建带有类别特征的特征矩阵 527 | X = np.array([[0, 2.10, 1.45], 528 | [1, 1.18, 1.33], 529 | [0, 1.22, 1.27], 530 | [1, -0.21, -1.19]]) 531 | 532 | # 创建类别特征有缺失的特征矩阵 533 | X_with_nan = np.array([[np.nan, 0.87, 1.31], 534 | [np.nan, -0.67, -0.22]]) 535 | 536 | # 训练 KNN 学习器 537 | clf = KNeighborsClassifier(3, weights='distance') 538 | trained_model = clf.fit(X[:,1:], X[:,0]) 539 | 540 | # 预测缺失值的类别 541 | imputed_values = trained_model.predict(X_with_nan[:,1:]) 542 | 543 | # 将预测分类的列和它们的其它特征连接 544 | X_with_imputed = np.hstack((imputed_values.reshape(-1,1), X_with_nan[:,1:])) 545 | 546 | # 连接两个特征矩阵 547 | np.vstack((X_with_imputed, X)) 548 | 549 | ''' 550 | array([[ 0. , 0.87, 1.31], 551 | [ 1. , -0.67, -0.22], 552 | [ 0. , 2.1 , 1.45], 553 | [ 1. , 1.18, 1.33], 554 | [ 0. , 1.22, 1.27], 555 | [ 1. , -0.21, -1.19]]) 556 | ''' 557 | ``` 558 | 559 | ## 观测正则化 560 | 561 | ![](img/3e9f30437a269befbe80859ffe27537e.jpg) 562 | 563 | ```py 564 | # 加载库 565 | from sklearn.preprocessing import Normalizer 566 | import numpy as np 567 | 568 | # 创建特征矩阵 569 | X = np.array([[0.5, 0.5], 570 | [1.1, 3.4], 571 | [1.5, 20.2], 572 | [1.63, 34.4], 573 | [10.9, 3.3]]) 574 | ``` 575 | 576 | `Normalizer`重缩放各个观侧,使其具有单位范数(长度之和为 1)。 577 | 578 | ```py 579 | # 创建正则化器 580 | normalizer = Normalizer(norm='l2') 581 | 582 | # 转换特征矩阵 583 | normalizer.transform(X) 584 | 585 | ''' 586 | array([[ 0.70710678, 0.70710678], 587 | [ 0.30782029, 0.95144452], 588 | [ 0.07405353, 0.99725427], 589 | [ 0.04733062, 0.99887928], 590 | [ 0.95709822, 0.28976368]]) 591 | ''' 592 | ``` 593 | 594 | ## 多个标签的独热编码特征 595 | 596 | ```py 597 | # 加载库 598 | from sklearn.preprocessing import MultiLabelBinarizer 599 | import numpy as np 600 | 601 | # 创建 NumPy 数组 602 | y = [('Texas', 'Florida'), 603 | ('California', 'Alabama'), 604 | ('Texas', 'Florida'), 605 | ('Delware', 'Florida'), 606 | ('Texas', 'Alabama')] 607 | 608 | # 创建 MultiLabelBinarizer 对象 609 | one_hot = MultiLabelBinarizer() 610 | 611 | # 独热编码数据 612 | one_hot.fit_transform(y) 613 | 614 | ''' 615 | array([[0, 0, 0, 1, 1], 616 | [1, 1, 0, 0, 0], 617 | [0, 0, 0, 1, 1], 618 | [0, 0, 1, 1, 0], 619 | [1, 0, 0, 0, 1]]) 620 | ''' 621 | 622 | # 查看类别 623 | one_hot.classes_ 624 | 625 | # array(['Alabama', 'California', 'Delware', 'Florida', 'Texas'], dtype=object) 626 | ``` 627 | 628 | ## 独热编码标称类别特征 629 | 630 | ![](img/7e623fe011680e01bfceb81efe4cff72.jpg) 631 | 632 | ```py 633 | # 加载库 634 | import numpy as np 635 | import pandas as pd 636 | from sklearn.preprocessing import LabelBinarizer 637 | 638 | # 创建 NumPy 数组 639 | x = np.array([['Texas'], 640 | ['California'], 641 | ['Texas'], 642 | ['Delaware'], 643 | ['Texas']]) 644 | 645 | # 创建 LabelBinzarizer 对象 646 | one_hot = LabelBinarizer() 647 | 648 | # 独热编码数据 649 | one_hot.fit_transform(x) 650 | 651 | ''' 652 | array([[0, 0, 1], 653 | [1, 0, 0], 654 | [0, 0, 1], 655 | [0, 1, 0], 656 | [0, 0, 1]]) 657 | ''' 658 | 659 | # 查看类别 660 | one_hot.classes_ 661 | 662 | ''' 663 | array(['California', 'Delaware', 'Texas'], 664 | dtype=' 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 图像二值化 10 | 11 | ```py 12 | # 加载库 13 | import cv2 14 | import numpy as np 15 | from matplotlib import pyplot as plt 16 | 17 | # 将图像加载为灰度 18 | image_grey = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 19 | 20 | # 应用自适应阈值 21 | max_output_value = 255 22 | neighorhood_size = 99 23 | subtract_from_mean = 10 24 | image_binarized = cv2.adaptiveThreshold(image_grey, 25 | max_output_value, 26 | cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 27 | cv2.THRESH_BINARY, 28 | neighorhood_size, 29 | subtract_from_mean) 30 | 31 | # 展示图像 32 | plt.imshow(image_binarized, cmap='gray'), plt.axis("off") 33 | plt.show() 34 | ``` 35 | 36 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/binarize_image/binarize_image_8_0.png) 37 | 38 | ## 图像模糊 39 | 40 | ```py 41 | # 加载库 42 | import cv2 43 | import numpy as np 44 | from matplotlib import pyplot as plt 45 | 46 | # 将图像加载为灰度 47 | image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 48 | 49 | # 使图像模糊 50 | image_blurry = cv2.blur(image, (5,5)) 51 | 52 | # 展示图像 53 | plt.imshow(image_blurry, cmap='gray'), plt.xticks([]), plt.yticks([]) 54 | plt.show() 55 | ``` 56 | 57 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/blurring_img/blurring_images_8_0.png) 58 | 59 | ## 图像剪裁 60 | 61 | ```py 62 | # 加载库 63 | import cv2 64 | import numpy as np 65 | from matplotlib import pyplot as plt 66 | 67 | # 将图像加载为灰度 68 | image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 69 | 70 | # 选择所有行,和前一半的列 71 | image_cropped = image[:,:126] 72 | 73 | # 查看图像 74 | plt.imshow(image_cropped, cmap='gray'), plt.axis("off") 75 | plt.show() 76 | ``` 77 | 78 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/cropping_img/cropping_images_8_0.png) 79 | 80 | ## 边缘检测 81 | 82 | ```py 83 | # 加载库 84 | import cv2 85 | import numpy as np 86 | from matplotlib import pyplot as plt 87 | 88 | # 将图像加载为灰度 89 | image_gray = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 90 | 91 | # 计算强度中值 92 | median_intensity = np.median(image_gray) 93 | 94 | # 将阈值设为强度中值上下一个标准差 95 | lower_threshold = int(max(0, (1.0 - 0.33) * median_intensity)) 96 | upper_threshold = int(min(255, (1.0 + 0.33) * median_intensity)) 97 | 98 | # 应用 canny 边缘检测 99 | image_canny = cv2.Canny(image_gray, lower_threshold, upper_threshold) 100 | 101 | # 展示图像 102 | plt.imshow(image_canny, cmap='gray'), plt.axis("off") 103 | plt.show() 104 | ``` 105 | 106 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/detect_edges/detect_edges_8_0.png) 107 | 108 | ## 增强彩色图像的对比度 109 | 110 | ```py 111 | # 加载库 112 | import cv2 113 | import numpy as np 114 | from matplotlib import pyplot as plt 115 | 116 | # 加载图像 117 | image_bgr = cv2.imread('img/plane.jpg') 118 | 119 | # 转换为 YUV 120 | image_yuv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2YUV) 121 | 122 | # 应用直方图均衡 123 | image_yuv[:, :, 0] = cv2.equalizeHist(image_yuv[:, :, 0]) 124 | 125 | # 转换为 RGB 126 | image_rgb = cv2.cvtColor(image_yuv, cv2.COLOR_YUV2RGB) 127 | 128 | # 展示图像 129 | plt.imshow(image_rgb), plt.axis("off") 130 | plt.show() 131 | ``` 132 | 133 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/enhance_contrast_of_color_image/enhance_contrast_of_color_image_12_0.png) 134 | 135 | ## 增强灰度图像的对比度 136 | 137 | ```py 138 | # 加载库 139 | import cv2 140 | import numpy as np 141 | from matplotlib import pyplot as plt 142 | 143 | # 将图像加载为灰度 144 | image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 145 | 146 | # 增强图像 147 | image_enhanced = cv2.equalizeHist(image) 148 | 149 | # 展示图像 150 | plt.imshow(image_enhanced, cmap='gray'), plt.axis("off") 151 | plt.show() 152 | ``` 153 | 154 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/enhance_contrast_of_greyscale_image/enhance_contrast_of_greyscale_image_8_0.png) 155 | 156 | # Harris 角点检测 157 | 158 | Harris 角点检测器是检测两个边缘角点的常用方法。 它寻找窗口(也称为邻域或补丁),其中窗口的小移动(想象摇动窗口)使窗口内的像素内容产生大的变化。 159 | 160 | ```py 161 | # 加载库 162 | import cv2 163 | import numpy as np 164 | from matplotlib import pyplot as plt 165 | 166 | # 将图像加载为灰度 167 | image_bgr = cv2.imread('img/plane_256x256.jpg') 168 | image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY) 169 | image_gray = np.float32(image_gray) 170 | 171 | # 设置角点检测器的参数 172 | block_size = 2 173 | aperture = 29 174 | free_parameter = 0.04 175 | 176 | # 检测角点 177 | detector_responses = cv2.cornerHarris(image_gray, block_size, aperture, free_parameter) 178 | 179 | # 大型角点标记器 180 | detector_responses = cv2.dilate(detector_responses, None) 181 | 182 | # 只保留大于阈值的检测器结果,标记为白色 183 | threshold = 0.02 184 | image_bgr[detector_responses > threshold * detector_responses.max()] = [255,255,255] 185 | 186 | # 转换为灰度 187 | image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY) 188 | 189 | # 展示图像 190 | plt.imshow(image_gray, cmap='gray'), plt.axis("off") 191 | plt.show() 192 | ``` 193 | 194 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/harris_corner_detector/harris_corner_detector_13_0.png) 195 | 196 | # 安装 OpenCV 197 | 198 | 虽然有许多好的库,OpenCV 是最受欢迎和文档最全的图像处理库。 使用 OpenCV 的最大障碍之一就是安装它。 但是,幸运的是,我们可以使用 Anaconda 的软件包管理器工具 conda,在我们的终端中用一行代码安装 OpenCV: 199 | 200 | ``` 201 | conda install --channel https://conda.anaconda.org/menpo opencv3 202 | ``` 203 | 204 | 之后,我们可以通过打开笔记本,导入 OpenCV 并检查版本号(3.1.0)来检查安装: 205 | 206 | ```py 207 | # 加载库 208 | import cv2 209 | 210 | # 查看版本号 211 | cv2.__version__ 212 | 213 | # '3.2.0' 214 | ``` 215 | 216 | ## 颜色隔离 217 | 218 | ```py 219 | # 加载库 220 | import cv2 221 | import numpy as np 222 | from matplotlib import pyplot as plt 223 | 224 | # 加载图像 225 | image_bgr = cv2.imread('img/plane_256x256.jpg') 226 | 227 | # 将 BGR 转换为 HSV 228 | image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV) 229 | 230 | # 定义 HSV 中蓝色值的范围 231 | lower_blue = np.array([50,100,50]) 232 | upper_blue = np.array([130,255,255]) 233 | 234 | # 创建遮罩 235 | mask = cv2.inRange(image_hsv, lower_blue, upper_blue) 236 | 237 | # 屏蔽图像 238 | image_bgr_masked = cv2.bitwise_and(image_bgr, image_bgr, mask=mask) 239 | 240 | # 将 BGR 转换为 RGB 241 | image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB) 242 | 243 | # 展示图像 244 | plt.imshow(image_rgb), plt.axis("off") 245 | plt.show() 246 | ``` 247 | 248 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/isolate_colors/isolate_colors_14_0.png) 249 | 250 | ## 加载图像 251 | 252 | ```py 253 | # 加载库 254 | import cv2 255 | import numpy as np 256 | from matplotlib import pyplot as plt 257 | 258 | # 将图像加载为灰度 259 | image = cv2.imread('img/plane.jpg', cv2.IMREAD_GRAYSCALE) 260 | 261 | # 展示图像 262 | plt.imshow(image, cmap='gray'), plt.axis("off") 263 | plt.show() 264 | ``` 265 | 266 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/load_img/load_images_4_0.png) 267 | 268 | ```py 269 | # 加载彩色图像 270 | image_bgr = cv2.imread('img/plane.jpg', cv2.IMREAD_COLOR) 271 | 272 | # 转换为 RGB 273 | image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) 274 | 275 | # 展示图像 276 | plt.imshow(image_rgb), plt.axis("off") 277 | plt.show() 278 | ``` 279 | 280 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/load_img/load_images_6_0.png) 281 | 282 | ```py 283 | # 展示图像数据 284 | image 285 | 286 | ''' 287 | array([[140, 136, 146, ..., 132, 139, 134], 288 | [144, 136, 149, ..., 142, 124, 126], 289 | [152, 139, 144, ..., 121, 127, 134], 290 | ..., 291 | [156, 146, 144, ..., 157, 154, 151], 292 | [146, 150, 147, ..., 156, 158, 157], 293 | [143, 138, 147, ..., 156, 157, 157]], dtype=uint8) 294 | ''' 295 | 296 | # 展示维度 297 | image.shape 298 | 299 | # (2270, 3600) 300 | ``` 301 | 302 | # 背景移除 303 | 304 | [![](img/4c2e42ce1e09d07bd5b30da33b4adf2f.jpg)](https://machinelearningflashcards.com) 305 | 306 | ```py 307 | # 加载库 308 | import cv2 309 | import numpy as np 310 | from matplotlib import pyplot as plt 311 | 312 | # 加载图像 313 | image_bgr = cv2.imread('img/plane_256x256.jpg') 314 | 315 | # 转换为 RGB 316 | image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) 317 | 318 | # 矩形值:起点 x,起点 y,宽度,高度 319 | rectangle = (0, 56, 256, 150) 320 | 321 | # 创建初始遮罩 322 | mask = np.zeros(image_rgb.shape[:2], np.uint8) 323 | 324 | # 创建用于 grabCut 的临时数组 325 | bgdModel = np.zeros((1, 65), np.float64) 326 | fgdModel = np.zeros((1, 65), np.float64) 327 | 328 | # 执行 grabCut 329 | cv2.grabCut(image_rgb, # 我们的图像 330 | mask, # 遮罩 331 | rectangle, # 我们的矩形 332 | bgdModel, # 用于背景的临时数组 333 | fgdModel, # 用于前景的临时数组 334 | 5, # 迭代数量 335 | cv2.GC_INIT_WITH_RECT) # 使用我们的矩形来初始化 336 | 337 | # 创建遮罩,其中背景设置为 0,否则为 1 338 | mask_2 = np.where((mask==2) | (mask==0), 0, 1).astype('uint8') 339 | 340 | # 使用新的遮罩移除多个图像的背景 341 | image_rgb_nobg = image_rgb * mask_2[:, :, np.newaxis] 342 | 343 | # 展示图像 344 | plt.imshow(image_rgb_nobg), plt.axis("off") 345 | plt.show() 346 | ``` 347 | 348 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/remove_backgrounds/remove_backgrounds_13_0.png) 349 | 350 | ## 保存图像 351 | 352 | ```py 353 | # 加载库 354 | import cv2 355 | import numpy as np 356 | from matplotlib import pyplot as plt 357 | 358 | # 将图像加载为灰度 359 | image = cv2.imread('img/plane.jpg', cv2.IMREAD_GRAYSCALE) 360 | 361 | # 展示图像 362 | plt.imshow(image, cmap='gray'), plt.axis("off") 363 | plt.show() 364 | ``` 365 | 366 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/save_img/save_images_4_0.png) 367 | 368 | ```py 369 | # 保存图像 370 | cv2.imwrite('img/plane_new.jpg', image) 371 | 372 | # True 373 | ``` 374 | 375 | ## 图像锐化 376 | 377 | ```py 378 | # 加载库 379 | import cv2 380 | import numpy as np 381 | from matplotlib import pyplot as plt 382 | 383 | # 将图像加载为灰度 384 | image = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_GRAYSCALE) 385 | 386 | # 创建核 387 | kernel = np.array([[0, -1, 0], 388 | [-1, 5,-1], 389 | [0, -1, 0]]) 390 | 391 | # 锐化图像 392 | image_sharp = cv2.filter2D(image, -1, kernel) 393 | 394 | # 展示图像 395 | plt.imshow(image_sharp, cmap='gray'), plt.axis("off") 396 | plt.show() 397 | ``` 398 | 399 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/sharpen_img/sharpen_images_8_0.png) 400 | 401 | ## Shi-Tomasi 角点检测 402 | 403 | ```py 404 | # 加载库 405 | import cv2 406 | import numpy as np 407 | from matplotlib import pyplot as plt 408 | 409 | # 加载图像 410 | image_bgr = cv2.imread('img/plane_256x256.jpg') 411 | image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY) 412 | 413 | # 要检测的角点数量 414 | corners_to_detect = 10 415 | minimum_quality_score = 0.05 416 | minimum_distance = 25 417 | 418 | # 检测角点 419 | corners = cv2.goodFeaturesToTrack(image_gray, 420 | corners_to_detect, 421 | minimum_quality_score, 422 | minimum_distance) 423 | corners = np.float32(corners) 424 | 425 | # 在每个角点上绘制白色圆圈 426 | for corner in corners: 427 | x, y = corner[0] 428 | cv2.circle(image_bgr, (x,y), 10, (255,255,255), -1) 429 | 430 | # 转换为灰度 431 | image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY) 432 | 433 | # 展示图像 434 | plt.imshow(image_gray, cmap='gray'), plt.axis("off") 435 | plt.show() 436 | ``` 437 | 438 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/ski-tomasi_corner_detector/ski-tomasi_corner_detector_12_0.png) 439 | 440 | ## 使用颜色均值作为特征 441 | 442 | ```py 443 | # 加载库 444 | import cv2 445 | import numpy as np 446 | from matplotlib import pyplot as plt 447 | 448 | # 将图像加载为 BGR 449 | image_bgr = cv2.imread('img/plane_256x256.jpg', cv2.IMREAD_COLOR) 450 | 451 | # 计算每个通道的均值 452 | channels = cv2.mean(image_bgr) 453 | 454 | # 交换蓝色和红色值(使其变成 RGB 而不是 BGR) 455 | observation = np.array([(channels[2], channels[1], channels[0])]) 456 | 457 | # 展示通道的均值 458 | observation 459 | 460 | # array([[ 90.53204346, 133.11735535, 169.03074646]]) 461 | 462 | # 展示图像 463 | plt.imshow(observation), plt.axis("off") 464 | plt.show() 465 | ``` 466 | 467 | ![png](https://chrisalbon.com/machine_learning/preprocessing_img/using_mean_color_as_a_feature/using_mean_color_as_a_feature_10_0.png) 468 | -------------------------------------------------------------------------------- /5.md: -------------------------------------------------------------------------------- 1 | # 五、文本预处理 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 词袋 10 | 11 | ![](img/dae1a905b9e7104ebcacfa982c3c9a5c.jpg) 12 | 13 | ```py 14 | # 加载库 15 | import numpy as np 16 | from sklearn.feature_extraction.text import CountVectorizer 17 | import pandas as pd 18 | 19 | # 创建文本 20 | text_data = np.array(['I love Brazil. Brazil!', 21 | 'Sweden is best', 22 | 'Germany beats both']) 23 | 24 | # 创建词袋特征矩阵 25 | count = CountVectorizer() 26 | bag_of_words = count.fit_transform(text_data) 27 | 28 | # 展示特征矩阵 29 | bag_of_words.toarray() 30 | 31 | ''' 32 | array([[0, 0, 0, 2, 0, 0, 1, 0], 33 | [0, 1, 0, 0, 0, 1, 0, 1], 34 | [1, 0, 1, 0, 1, 0, 0, 0]], dtype=int64) 35 | ''' 36 | 37 | # 获取特征名称 38 | feature_names = count.get_feature_names() 39 | 40 | # 查看特征名称 41 | feature_names 42 | 43 | # ['beats', 'best', 'both', 'brazil', 'germany', 'is', 'love', 'sweden'] 44 | 45 | # 创建数据帧 46 | pd.DataFrame(bag_of_words.toarray(), columns=feature_names) 47 | ``` 48 | 49 | | | beats | best | both | brazil | germany | is | love | sweden | 50 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | 51 | | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 1 | 0 | 52 | | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 53 | | 2 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 54 | 55 | ## 解析 HTML 56 | 57 | ```py 58 | # 加载库 59 | from bs4 import BeautifulSoup 60 | 61 | # 创建一些 HTML 代码 62 | html = "
Masego Azra
" 63 | 64 | # 解析 html 65 | soup = BeautifulSoup(html, "lxml") 66 | 67 | # 寻找带有 "full_name" 类的
,展示文本 68 | soup.find("div", { "class" : "full_name" }).text 69 | 70 | # 'Masego Azra' 71 | ``` 72 | 73 | ## 移除标点 74 | 75 | ```py 76 | # 加载库 77 | import string 78 | import numpy as np 79 | 80 | # 创建文本 81 | text_data = ['Hi!!!! I. Love. This. Song....', 82 | '10000% Agree!!!! #LoveIT', 83 | 'Right?!?!'] 84 | 85 | # 创建函数,使用 string.punctuation 移除所有标点 86 | def remove_punctuation(sentence: str) -> str: 87 | return sentence.translate(str.maketrans('', '', string.punctuation)) 88 | 89 | # 应用函数 90 | [remove_punctuation(sentence) for sentence in text_data] 91 | 92 | # ['Hi I Love This Song', '10000 Agree LoveIT', 'Right'] 93 | ``` 94 | 95 | ## 移除停止词 96 | 97 | ```py 98 | # 加载库 99 | from nltk.corpus import stopwords 100 | 101 | # 你第一次需要下载停止词的集合 102 | import nltk 103 | nltk.download('stopwords') 104 | 105 | ''' 106 | [nltk_data] Downloading package stopwords to 107 | [nltk_data] /Users/chrisalbon/nltk_data... 108 | [nltk_data] Package stopwords is already up-to-date! 109 | 110 | True 111 | ''' 112 | 113 | # 创建单词标记 114 | tokenized_words = ['i', 'am', 'going', 'to', 'go', 'to', 'the', 'store', 'and', 'park'] 115 | 116 | # 加载停止词 117 | stop_words = stopwords.words('english') 118 | 119 | # 展示停止词 120 | stop_words[:5] 121 | 122 | # ['i', 'me', 'my', 'myself', 'we'] 123 | 124 | # 移除停止词 125 | [word for word in tokenized_words if word not in stop_words] 126 | 127 | # ['going', 'go', 'store', 'park'] 128 | ``` 129 | 130 | ## 替换字符 131 | 132 | ```py 133 | # 导入库 134 | import re 135 | 136 | # 创建文本 137 | text_data = ['Interrobang. By Aishwarya Henriette', 138 | 'Parking And Going. By Karl Gautier', 139 | 'Today Is The night. By Jarek Prakash'] 140 | 141 | # 移除句号 142 | remove_periods = [string.replace('.', '') for string in text_data] 143 | 144 | # 展示文本 145 | remove_periods 146 | 147 | ''' 148 | ['Interrobang By Aishwarya Henriette', 149 | 'Parking And Going By Karl Gautier', 150 | 'Today Is The night By Jarek Prakash'] 151 | ''' 152 | 153 | # 创建函数 154 | def replace_letters_with_X(string: str) -> str: 155 | return re.sub(r'[a-zA-Z]', 'X', string) 156 | 157 | # 应用函数 158 | [replace_letters_with_X(string) for string in remove_periods] 159 | 160 | ''' 161 | ['XXXXXXXXXXX XX XXXXXXXXX XXXXXXXXX', 162 | 'XXXXXXX XXX XXXXX XX XXXX XXXXXXX', 163 | 'XXXXX XX XXX XXXXX XX XXXXX XXXXXXX'] 164 | ''' 165 | ``` 166 | 167 | ## 词干提取 168 | 169 | ![](img/54fd49268017a7b697a4eee7c911d969.jpg) 170 | 171 | ```py 172 | # 加载库 173 | from nltk.stem.porter import PorterStemmer 174 | 175 | # 创建单词标记 176 | tokenized_words = ['i', 'am', 'humbled', 'by', 'this', 'traditional', 'meeting'] 177 | ``` 178 | 179 | 词干提取通过识别和删除词缀(例如动名词)同时保持词的根本意义,将词语简化为词干。 NLTK 的`PorterStemmer`实现了广泛使用的 Porter 词干算法。 180 | 181 | ```py 182 | # 创建提取器 183 | porter = PorterStemmer() 184 | 185 | # 应用提取器 186 | [porter.stem(word) for word in tokenized_words] 187 | 188 | # ['i', 'am', 'humbl', 'by', 'thi', 'tradit', 'meet'] 189 | ``` 190 | 191 | ## 移除空白 192 | 193 | ```py 194 | # 创建文本 195 | text_data = [' Interrobang. By Aishwarya Henriette ', 196 | 'Parking And Going. By Karl Gautier', 197 | ' Today Is The night. By Jarek Prakash '] 198 | 199 | # 移除空白 200 | strip_whitespace = [string.strip() for string in text_data] 201 | 202 | # 展示文本 203 | strip_whitespace 204 | 205 | ''' 206 | ['Interrobang. By Aishwarya Henriette', 207 | 'Parking And Going. By Karl Gautier', 208 | 'Today Is The night. By Jarek Prakash'] 209 | ''' 210 | ``` 211 | 212 | ## 词性标签 213 | 214 | ```py 215 | # 加载库 216 | from nltk import pos_tag 217 | from nltk import word_tokenize 218 | 219 | # 创建文本 220 | text_data = "Chris loved outdoor running" 221 | 222 | # 使用预训练的词性标注器 223 | text_tagged = pos_tag(word_tokenize(text_data)) 224 | 225 | # 展示词性 226 | text_tagged 227 | 228 | # [('Chris', 'NNP'), ('loved', 'VBD'), ('outdoor', 'RP'), ('running', 'VBG')] 229 | ``` 230 | 231 | 输出是一个元组列表,包含单词和词性的标记。 NLTK 使用 Penn Treebank 词性标签。 232 | 233 | | 标签 | 词性 | 234 | | --- | --- | 235 | | NNP | 专有名词,单数 | 236 | | NN | 名词,单数或集体 | 237 | | RB | 副词 | 238 | | VBD | 动词,过去式 | 239 | | VBG | 动词,动名词或现在分词 | 240 | | JJ | 形容词 | 241 | | PRP | 人称代词 | 242 | 243 | ## TF-IDF 244 | 245 | ![](img/2cdf1de23dbb6214dfbadd6865c464b0.jpg) 246 | 247 | ```py 248 | # 加载库 249 | import numpy as np 250 | from sklearn.feature_extraction.text import TfidfVectorizer 251 | import pandas as pd 252 | 253 | # 创建文本 254 | text_data = np.array(['I love Brazil. Brazil!', 255 | 'Sweden is best', 256 | 'Germany beats both']) 257 | 258 | # 创建 tf-idf 特征矩阵 259 | tfidf = TfidfVectorizer() 260 | feature_matrix = tfidf.fit_transform(text_data) 261 | 262 | # 展示 tf-idf 特征矩阵 263 | feature_matrix.toarray() 264 | 265 | ''' 266 | array([[ 0. , 0. , 0. , 0.89442719, 0. , 267 | 0. , 0.4472136 , 0. ], 268 | [ 0. , 0.57735027, 0. , 0. , 0. , 269 | 0.57735027, 0. , 0.57735027], 270 | [ 0.57735027, 0. , 0.57735027, 0. , 0.57735027, 271 | 0. , 0. , 0. ]]) 272 | ''' 273 | 274 | # 展示 tf-idf 特征矩阵 275 | tfidf.get_feature_names() 276 | 277 | # ['beats', 'best', 'both', 'brazil', 'germany', 'is', 'love', 'sweden'] 278 | 279 | # 创建数据帧 280 | pd.DataFrame(feature_matrix.toarray(), columns=tfidf.get_feature_names()) 281 | ``` 282 | 283 | | | beats | best | both | brazil | germany | is | love | sweden | 284 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | 285 | | 0 | 0.00000 | 0.00000 | 0.00000 | 0.894427 | 0.00000 | 0.00000 | 0.447214 | 0.00000 | 286 | | 1 | 0.00000 | 0.57735 | 0.00000 | 0.000000 | 0.00000 | 0.57735 | 0.000000 | 0.57735 | 287 | | 2 | 0.57735 | 0.00000 | 0.57735 | 0.000000 | 0.57735 | 0.00000 | 0.000000 | 0.00000 | 288 | 289 | ## 文本分词 290 | 291 | ```py 292 | # 加载库 293 | from nltk.tokenize import word_tokenize, sent_tokenize 294 | 295 | # 创建文本 296 | string = "The science of today is the technology of tomorrow. Tomorrow is today." 297 | 298 | # 对文本分词 299 | word_tokenize(string) 300 | 301 | ''' 302 | ['The', 303 | 'science', 304 | 'of', 305 | 'today', 306 | 'is', 307 | 'the', 308 | 'technology', 309 | 'of', 310 | 'tomorrow', 311 | '.', 312 | 'Tomorrow', 313 | 'is', 314 | 'today', 315 | '.'] 316 | ''' 317 | 318 | # 对句子分词 319 | sent_tokenize(string) 320 | 321 | # ['The science of today is the technology of tomorrow.', 'Tomorrow is today.'] 322 | ``` 323 | -------------------------------------------------------------------------------- /6.md: -------------------------------------------------------------------------------- 1 | # 六、日期时间预处理 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 把日期和时间拆成多个特征 10 | 11 | ```py 12 | # 加载库 13 | import pandas as pd 14 | 15 | # 创建数据帧 16 | df = pd.DataFrame() 17 | 18 | # 创建五个日期 19 | df['date'] = pd.date_range('1/1/2001', periods=150, freq='W') 20 | 21 | # 为年月日,时分秒创建特征 22 | df['year'] = df['date'].dt.year 23 | df['month'] = df['date'].dt.month 24 | df['day'] = df['date'].dt.day 25 | df['hour'] = df['date'].dt.hour 26 | df['minute'] = df['date'].dt.minute 27 | 28 | # 展示三行 29 | df.head(3) 30 | ``` 31 | 32 | | | date | year | month | day | hour | minute | 33 | | --- | --- | --- | --- | --- | --- | --- | 34 | | 0 | 2001-01-07 | 2001 | 1 | 7 | 0 | 0 | 35 | | 1 | 2001-01-14 | 2001 | 1 | 14 | 0 | 0 | 36 | | 2 | 2001-01-21 | 2001 | 1 | 21 | 0 | 0 | 37 | 38 | ## 计算日期时间之间的差 39 | 40 | ```py 41 | # 加载库 42 | import pandas as pd 43 | 44 | # 创建数据帧 45 | df = pd.DataFrame() 46 | 47 | # 创建两个 datetime 特征 48 | df['Arrived'] = [pd.Timestamp('01-01-2017'), pd.Timestamp('01-04-2017')] 49 | df['Left'] = [pd.Timestamp('01-01-2017'), pd.Timestamp('01-06-2017')] 50 | 51 | # 计算特征之间的间隔 52 | df['Left'] - df['Arrived'] 53 | 54 | ''' 55 | 0 0 days 56 | 1 2 days 57 | dtype: timedelta64[ns] 58 | ''' 59 | 60 | # 计算特征之间的间隔 61 | pd.Series(delta.days for delta in (df['Left'] - df['Arrived'])) 62 | 63 | ''' 64 | 0 0 65 | 1 2 66 | dtype: int64 67 | ''' 68 | ``` 69 | 70 | ## 将字符串转换为日期 71 | 72 | ```py 73 | # 加载库 74 | import numpy as np 75 | import pandas as pd 76 | 77 | # 创建字符串 78 | date_strings = np.array(['03-04-2005 11:35 PM', 79 | '23-05-2010 12:01 AM', 80 | '04-09-2009 09:09 PM']) 81 | ``` 82 | 83 | 如果`errors="coerce"`那么任何问题都不会产生错误(默认行为),而是将导致错误的值设置为`NaT`(即缺失值)。 84 | 85 | | 代码 | 描述 | 示例 | 86 | | --- | --- | --- | 87 | | ` %Y ` | 整年 | `2001` | 88 | | ` %m ` | 零填充的月份 | `04` | 89 | | ` %d ` | 零填充的日期 | `09` | 90 | | ` %I ` | 零填充的小时(12 小时) | `02` | 91 | | ` %p ` | AM 或 PM | `AM` | 92 | | ` %M ` | 零填充的分钟 | `05` | 93 | | ` %S ` | 零填充的秒钟 | `09` | 94 | 95 | ```py 96 | # 转换为 datetime 97 | [pd.to_datetime(date, format="%d-%m-%Y %I:%M %p", errors="coerce") for date in date_strings] 98 | 99 | ''' 100 | [Timestamp('2005-04-03 23:35:00'), 101 | Timestamp('2010-05-23 00:01:00'), 102 | Timestamp('2009-09-04 21:09:00')] 103 | ''' 104 | ``` 105 | 106 | ## 转换 pandas 列的时区 107 | 108 | ```py 109 | # 加载库 110 | import pandas as pd 111 | from pytz import all_timezones 112 | 113 | # 展示十个时区 114 | all_timezones[0:10] 115 | 116 | ''' 117 | ['Africa/Abidjan', 118 | 'Africa/Accra', 119 | 'Africa/Addis_Ababa', 120 | 'Africa/Algiers', 121 | 'Africa/Asmara', 122 | 'Africa/Asmera', 123 | 'Africa/Bamako', 124 | 'Africa/Bangui', 125 | 'Africa/Banjul', 126 | 'Africa/Bissau'] 127 | ''' 128 | 129 | # 创建十个日期 130 | dates = pd.Series(pd.date_range('2/2/2002', periods=10, freq='M')) 131 | 132 | # 设置时区 133 | dates_with_abidjan_time_zone = dates.dt.tz_localize('Africa/Abidjan') 134 | 135 | # 查看 pandas 序列 136 | dates_with_abidjan_time_zone 137 | 138 | ''' 139 | 0 2002-02-28 00:00:00+00:00 140 | 1 2002-03-31 00:00:00+00:00 141 | 2 2002-04-30 00:00:00+00:00 142 | 3 2002-05-31 00:00:00+00:00 143 | 4 2002-06-30 00:00:00+00:00 144 | 5 2002-07-31 00:00:00+00:00 145 | 6 2002-08-31 00:00:00+00:00 146 | 7 2002-09-30 00:00:00+00:00 147 | 8 2002-10-31 00:00:00+00:00 148 | 9 2002-11-30 00:00:00+00:00 149 | dtype: datetime64[ns, Africa/Abidjan] 150 | ''' 151 | 152 | # 转换时区 153 | dates_with_london_time_zone = dates_with_abidjan_time_zone.dt.tz_convert('Europe/London') 154 | 155 | # 查看 pandas 序列 156 | dates_with_london_time_zone 157 | 158 | ''' 159 | 0 2002-02-28 00:00:00+00:00 160 | 1 2002-03-31 00:00:00+00:00 161 | 2 2002-04-30 01:00:00+01:00 162 | 3 2002-05-31 01:00:00+01:00 163 | 4 2002-06-30 01:00:00+01:00 164 | 5 2002-07-31 01:00:00+01:00 165 | 6 2002-08-31 01:00:00+01:00 166 | 7 2002-09-30 01:00:00+01:00 167 | 8 2002-10-31 00:00:00+00:00 168 | 9 2002-11-30 00:00:00+00:00 169 | dtype: datetime64[ns, Europe/London] 170 | ''' 171 | ``` 172 | 173 | ## 编码星期 174 | 175 | ```py 176 | # 加载库 177 | import pandas as pd 178 | 179 | # 创建数据集 180 | dates = pd.Series(pd.date_range('2/2/2002', periods=3, freq='M')) 181 | 182 | # 查看数据 183 | dates 184 | 185 | ''' 186 | 0 2002-02-28 187 | 1 2002-03-31 188 | 2 2002-04-30 189 | dtype: datetime64[ns] 190 | ''' 191 | 192 | # 查看星期 193 | dates.dt.weekday_name 194 | 195 | ''' 196 | 0 Thursday 197 | 1 Sunday 198 | 2 Tuesday 199 | dtype: object 200 | ''' 201 | ``` 202 | 203 | ## 处理时间序列中的缺失值 204 | 205 | ```py 206 | # 加载库 207 | import pandas as pd 208 | import numpy as np 209 | 210 | # 创建日期 211 | time_index = pd.date_range('01/01/2010', periods=5, freq='M') 212 | 213 | # 创建数据帧,设置索引 214 | df = pd.DataFrame(index=time_index) 215 | 216 | # 创建带有一些缺失值的特征 217 | df['Sales'] = [1.0,2.0,np.nan,np.nan,5.0] 218 | 219 | # 对缺失值执行插值 220 | df.interpolate() 221 | ``` 222 | 223 | | | Sales | 224 | | --- | --- | 225 | | 2010-01-31 | 1.0 | 226 | | 2010-02-28 | 2.0 | 227 | | 2010-03-31 | 3.0 | 228 | | 2010-04-30 | 4.0 | 229 | | 2010-05-31 | 5.0 | 230 | 231 | ```py 232 | # 前向填充 233 | df.ffill() 234 | ``` 235 | 236 | | | Sales | 237 | | --- | --- | 238 | | 2010-01-31 | 1.0 | 239 | | 2010-02-28 | 2.0 | 240 | | 2010-03-31 | 2.0 | 241 | | 2010-04-30 | 2.0 | 242 | | 2010-05-31 | 5.0 | 243 | 244 | ```py 245 | # 后向填充 246 | df.bfill() 247 | ``` 248 | 249 | | | Sales | 250 | | --- | --- | 251 | | 2010-01-31 | 1.0 | 252 | | 2010-02-28 | 2.0 | 253 | | 2010-03-31 | 5.0 | 254 | | 2010-04-30 | 5.0 | 255 | | 2010-05-31 | 5.0 | 256 | 257 | ```py 258 | # 对缺失值执行插值 259 | df.interpolate(limit=1, limit_direction='forward') 260 | ``` 261 | 262 | | | Sales | 263 | | --- | --- | 264 | | 2010-01-31 | 1.0 | 265 | | 2010-02-28 | 2.0 | 266 | | 2010-03-31 | 3.0 | 267 | | 2010-04-30 | NaN | 268 | | 2010-05-31 | 5.0 | 269 | 270 | ## 处理时区 271 | 272 | ```py 273 | # 加载库 274 | import pandas as pd 275 | from pytz import all_timezones 276 | 277 | # 展示十个时区 278 | all_timezones[0:10] 279 | 280 | ''' 281 | ['Africa/Abidjan', 282 | 'Africa/Accra', 283 | 'Africa/Addis_Ababa', 284 | 'Africa/Algiers', 285 | 'Africa/Asmara', 286 | 'Africa/Asmera', 287 | 'Africa/Bamako', 288 | 'Africa/Bangui', 289 | 'Africa/Banjul', 290 | 'Africa/Bissau'] 291 | ''' 292 | 293 | # 创建 datetime 294 | pd.Timestamp('2017-05-01 06:00:00', tz='Europe/London') 295 | 296 | # Timestamp('2017-05-01 06:00:00+0100', tz='Europe/London') 297 | 298 | # 创建 datetime 299 | date = pd.Timestamp('2017-05-01 06:00:00') 300 | 301 | # 设置时区 302 | date_in_london = date.tz_localize('Europe/London') 303 | 304 | # 修改时区 305 | date_in_london.tz_convert('Africa/Abidjan') 306 | 307 | # Timestamp('2017-05-01 05:00:00+0000', tz='Africa/Abidjan') 308 | ``` 309 | 310 | ## 平移时间特征 311 | 312 | ```py 313 | # 加载库 314 | import pandas as pd 315 | 316 | # 创建数据帧 317 | df = pd.DataFrame() 318 | 319 | # 创建数据 320 | df['dates'] = pd.date_range('1/1/2001', periods=5, freq='D') 321 | df['stock_price'] = [1.1,2.2,3.3,4.4,5.5] 322 | 323 | # 将值平移一行 324 | df['previous_days_stock_price'] = df['stock_price'].shift(1) 325 | 326 | # 展示数据帧 327 | df 328 | ``` 329 | 330 | | | dates | stock_price | previous_days_stock_price | 331 | | --- | --- | --- | --- | 332 | | 0 | 2001-01-01 | 1.1 | NaN | 333 | | 1 | 2001-01-02 | 2.2 | 1.1 | 334 | | 2 | 2001-01-03 | 3.3 | 2.2 | 335 | | 3 | 2001-01-04 | 4.4 | 3.3 | 336 | | 4 | 2001-01-05 | 5.5 | 4.4 | 337 | 338 | ## 滑动时间窗口 339 | 340 | ```py 341 | # 加载库 342 | import pandas as pd 343 | 344 | # 创建 datetime 345 | time_index = pd.date_range('01/01/2010', periods=5, freq='M') 346 | 347 | # 创建数据帧,设置索引 348 | df = pd.DataFrame(index=time_index) 349 | 350 | # 创建特征 351 | df['Stock_Price'] = [1,2,3,4,5] 352 | 353 | # 计算滑动均值 354 | df.rolling(window=2).mean() 355 | ``` 356 | 357 | | | Stock_Price | 358 | | --- | --- | 359 | | 2010-01-31 | NaN | 360 | | 2010-02-28 | 1.5 | 361 | | 2010-03-31 | 2.5 | 362 | | 2010-04-30 | 3.5 | 363 | | 2010-05-31 | 4.5 | 364 | 365 | ```py 366 | # 识别滑动时间窗口中的最大值 367 | df.rolling(window=2).max() 368 | ``` 369 | 370 | | | Stock_Price | 371 | | --- | --- | 372 | | 2010-01-31 | NaN | 373 | | 2010-02-28 | 2.0 | 374 | | 2010-03-31 | 3.0 | 375 | | 2010-04-30 | 4.0 | 376 | | 2010-05-31 | 5.0 | 377 | 378 | ## 选择日期时间范围 379 | 380 | ```py 381 | # 加载库 382 | import pandas as pd 383 | 384 | # 创建数据帧 385 | df = pd.DataFrame() 386 | 387 | # 创建 datetime 388 | df['date'] = pd.date_range('1/1/2001', periods=100000, freq='H') 389 | ``` 390 | 391 | 如果数据帧未按时间索引,请使用此方法。 392 | 393 | ```py 394 | # 选择两个日期时间之间的观测 395 | df[(df['date'] > '2002-1-1 01:00:00') & (df['date'] <= '2002-1-1 04:00:00')] 396 | ``` 397 | 398 | | | date | 399 | | --- | --- | 400 | | 8762 | 2002-01-01 02:00:00 | 401 | | 8763 | 2002-01-01 03:00:00 | 402 | | 8764 | 2002-01-01 04:00:00 | 403 | 404 | 如果数据帧按时间索引,请使用此方法。 405 | 406 | ```py 407 | # 设置索引 408 | df = df.set_index(df['date']) 409 | 410 | # 选择两个日期时间之间的观测 411 | df.loc['2002-1-1 01:00:00':'2002-1-1 04:00:00'] 412 | ``` 413 | 414 | | | date | 415 | | --- | --- | 416 | | date | | 417 | | 2002-01-01 01:00:00 | 2002-01-01 01:00:00 | 418 | | 2002-01-01 02:00:00 | 2002-01-01 02:00:00 | 419 | | 2002-01-01 03:00:00 | 2002-01-01 03:00:00 | 420 | | 2002-01-01 04:00:00 | 2002-01-01 04:00:00 | 421 | -------------------------------------------------------------------------------- /7.md: -------------------------------------------------------------------------------- 1 | # 七、特征工程 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 稀疏特征矩阵上的降维 10 | 11 | ```py 12 | # 加载库 13 | from sklearn.preprocessing import StandardScaler 14 | from sklearn.decomposition import TruncatedSVD 15 | from scipy.sparse import csr_matrix 16 | from sklearn import datasets 17 | import numpy as np 18 | 19 | # 加载数据 20 | digits = datasets.load_digits() 21 | 22 | # 标准化特征矩阵 23 | X = StandardScaler().fit_transform(digits.data) 24 | 25 | # 生成稀疏矩阵 26 | X_sparse = csr_matrix(X) 27 | 28 | # 创建 TSVD 29 | tsvd = TruncatedSVD(n_components=10) 30 | 31 | # 在稀疏矩阵上使用 TSVD 32 | X_sparse_tsvd = tsvd.fit(X_sparse).transform(X_sparse) 33 | 34 | # 展示结果 35 | print('Original number of features:', X_sparse.shape[1]) 36 | print('Reduced number of features:', X_sparse_tsvd.shape[1]) 37 | 38 | ''' 39 | Original number of features: 64 40 | Reduced number of features: 10 41 | ''' 42 | 43 | # 前三个主成分的解释方差比之和 44 | tsvd.explained_variance_ratio_[0:3].sum() 45 | 46 | # 0.30039385372588506 47 | ``` 48 | 49 | ## 核 PCA 降维 50 | 51 | ![](img/65334cd1b4791a63cb320a2f2fa44ac1.jpg) 52 | 53 | ```py 54 | # 加载库 55 | from sklearn.decomposition import PCA, KernelPCA 56 | from sklearn.datasets import make_circles 57 | 58 | # 创建线性不可分的数据 59 | X, _ = make_circles(n_samples=1000, random_state=1, noise=0.1, factor=0.1) 60 | 61 | # 应用带有径向基函数(RBF)核的核 PCA 62 | kpca = KernelPCA(kernel="rbf", gamma=15, n_components=1) 63 | X_kpca = kpca.fit_transform(X) 64 | 65 | print('Original number of features:', X.shape[1]) 66 | print('Reduced number of features:', X_kpca.shape[1]) 67 | 68 | ''' 69 | Original number of features: 2 70 | Reduced number of features: 1 71 | ''' 72 | ``` 73 | 74 | ## 使用 PCA 的降维 75 | 76 | ![](img/e78c54ef3d6a719f1ffa6a538f9353de.jpg) 77 | 78 | ```py 79 | # 加载库 80 | from sklearn.preprocessing import StandardScaler 81 | from sklearn.decomposition import PCA 82 | from sklearn import datasets 83 | 84 | # 加载数据 85 | digits = datasets.load_digits() 86 | 87 | # 标准化特征矩阵 88 | X = StandardScaler().fit_transform(digits.data) 89 | 90 | # 创建保留 99% 方差的 PCA 91 | pca = PCA(n_components=0.99, whiten=True) 92 | 93 | # 使用 PCA 94 | X_pca = pca.fit_transform(X) 95 | 96 | # 展示结果 97 | print('Original number of features:', X.shape[1]) 98 | print('Reduced number of features:', X_pca.shape[1]) 99 | 100 | ''' 101 | Original number of features: 64 102 | Reduced number of features: 54 103 | ''' 104 | ``` 105 | 106 | ## PCA 特征提取 107 | 108 | [主成分分析](https://en.wikipedia.org/wiki/Principal_component_analysis)(PCA)是数据科学中常见的特征提取方法。 从技术上讲,PCA 找到具有最高特征值的协方差矩阵的特征向量,然后使用这些特征向量将数据投影到相等或更小维度的新子空间。 实际上,PCA 将 n 个特征矩阵转换为(可能)小于 n 个特征的新数据集。 也就是说,它通过构造新的较少变量来减少特征的数量,这些变量捕获原始特征中找到的信息的重要部分。 但是,本教程的目的不是要解释 PCA 的概念,这在其他地方做得非常好,而是用于演示 PCA 的实际应用。 109 | 110 | ```py 111 | # 导入库 112 | import numpy as np 113 | from sklearn import decomposition, datasets 114 | from sklearn.preprocessing import StandardScaler 115 | 116 | # 加载乳腺癌数据集 117 | dataset = datasets.load_breast_cancer() 118 | 119 | # 加载特征 120 | X = dataset.data 121 | ``` 122 | 123 | 请注意,原始数据包含 569 个观测和 30 个特征。 124 | 125 | ```py 126 | # 查看数据集的形状 127 | X.shape 128 | 129 | # (569, 30) 130 | ``` 131 | 132 | 这里是数据的样子 133 | 134 | ```py 135 | # 查看数据 136 | X 137 | 138 | ''' 139 | array([[ 1.79900000e+01, 1.03800000e+01, 1.22800000e+02, ..., 140 | 2.65400000e-01, 4.60100000e-01, 1.18900000e-01], 141 | [ 2.05700000e+01, 1.77700000e+01, 1.32900000e+02, ..., 142 | 1.86000000e-01, 2.75000000e-01, 8.90200000e-02], 143 | [ 1.96900000e+01, 2.12500000e+01, 1.30000000e+02, ..., 144 | 2.43000000e-01, 3.61300000e-01, 8.75800000e-02], 145 | ..., 146 | [ 1.66000000e+01, 2.80800000e+01, 1.08300000e+02, ..., 147 | 1.41800000e-01, 2.21800000e-01, 7.82000000e-02], 148 | [ 2.06000000e+01, 2.93300000e+01, 1.40100000e+02, ..., 149 | 2.65000000e-01, 4.08700000e-01, 1.24000000e-01], 150 | [ 7.76000000e+00, 2.45400000e+01, 4.79200000e+01, ..., 151 | 0.00000000e+00, 2.87100000e-01, 7.03900000e-02]]) 152 | ''' 153 | 154 | # 创建缩放器对象 155 | sc = StandardScaler() 156 | 157 | # 使缩放器拟合特征并转换 158 | X_std = sc.fit_transform(X) 159 | ``` 160 | 161 | 请注意,PCA 包含一个参数,即成分数。 这是输出特征的数量,需要进行调整。 162 | 163 | ```py 164 | # 创建 PCA 对象,使用两个成分作为参数 165 | pca = decomposition.PCA(n_components=2) 166 | 167 | # 拟合 PCA 并转换数据 168 | X_std_pca = pca.fit_transform(X_std) 169 | ``` 170 | 171 | 在 PCA 之后,新数据已降到了两个特征,其行数与原始特征相同。 172 | 173 | ```py 174 | # 查看新特征数据的形状 175 | X_std_pca.shape 176 | 177 | # (569, 2) 178 | 179 | # 查看新特征数据 180 | X_std_pca 181 | 182 | ''' 183 | array([[ 9.19283683, 1.94858307], 184 | [ 2.3878018 , -3.76817174], 185 | [ 5.73389628, -1.0751738 ], 186 | ..., 187 | [ 1.25617928, -1.90229671], 188 | [ 10.37479406, 1.67201011], 189 | [ -5.4752433 , -0.67063679]]) 190 | ''' 191 | ``` 192 | 193 | ## 使用 KMeans 聚类对观测分组 194 | 195 | ```py 196 | # 加载库 197 | from sklearn.datasets import make_blobs 198 | from sklearn.cluster import KMeans 199 | import pandas as pd 200 | 201 | # 制作模拟特征矩阵 202 | X, _ = make_blobs(n_samples = 50, 203 | n_features = 2, 204 | centers = 3, 205 | random_state = 1) 206 | 207 | # 创建 DataFrame 208 | df = pd.DataFrame(X, columns=['feature_1','feature_2']) 209 | 210 | # 创建 KMeans 聚类器 211 | clusterer = KMeans(3, random_state=1) 212 | 213 | # 拟合聚类器 214 | clusterer.fit(X) 215 | 216 | ''' 217 | KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300, 218 | n_clusters=3, n_init=10, n_jobs=1, precompute_distances='auto', 219 | random_state=1, tol=0.0001, verbose=0) 220 | ''' 221 | 222 | # 预测值 223 | df['group'] = clusterer.predict(X) 224 | 225 | # 前几个观测 226 | df.head(5) 227 | ``` 228 | 229 | | | feature_1 | feature_2 | group | 230 | | --- | --- | --- | --- | 231 | | 0 | -9.877554 | -3.336145 | 0 | 232 | | 1 | -7.287210 | -8.353986 | 2 | 233 | | 2 | -6.943061 | -7.023744 | 2 | 234 | | 3 | -7.440167 | -8.791959 | 2 | 235 | | 4 | -6.641388 | -8.075888 | 2 | 236 | 237 | # 为 LDA 选择最佳数量的成分 238 | 239 | 在 scikit-learn 中,LDA 是使用`LinearDiscriminantAnalysis`实现的,包含一个参数`n_components`,表示我们想要返回的特征数。 为了找出用于`n_components`的参数值(例如,要保留多少参数),我们可以利用一个事实,`explain_variance_ratio_`告诉我们每个输出特征的解释方差并且是有序数组。 240 | 241 | 具体来说,我们可以运行`Linear_iscriminantAnalysis`,将`n_components`设置为`None`来返回由每个特征成分的解释方差比,然后计算需要多少成分才能超过解释方差的阈值(通常为 0.95 或 0.99)。 242 | 243 | ```py 244 | # 加载库 245 | from sklearn import datasets 246 | from sklearn.discriminant_analysis import LinearDiscriminantAnalysis 247 | 248 | # 加载鸢尾花数据集 249 | iris = datasets.load_iris() 250 | X = iris.data 251 | y = iris.target 252 | 253 | # 创建并运行 LDA 254 | lda = LinearDiscriminantAnalysis(n_components=None) 255 | X_lda = lda.fit(X, y) 256 | 257 | # 创建解释方差比的数组 258 | lda_var_ratios = lda.explained_variance_ratio_ 259 | 260 | # 创建函数 261 | def select_n_components(var_ratio, goal_var: float) -> int: 262 | # 设置目前为止的初始解释方差 263 | total_variance = 0.0 264 | 265 | # 设置初始特征数 266 | n_components = 0 267 | 268 | # 对于每个特征的解释方差 269 | for explained_variance in var_ratio: 270 | 271 | # 将解释方差添加到总体 272 | total_variance += explained_variance 273 | 274 | # 成分数加一 275 | n_components += 1 276 | 277 | # 如果我们达到了我们的解释方差目标 278 | if total_variance >= goal_var: 279 | # 结束循环 280 | break 281 | 282 | # 返回成分数量 283 | return n_components 284 | 285 | # 执行函数 286 | select_n_components(lda_var_ratios, 0.95) 287 | 288 | # 1 289 | ``` 290 | 291 | ## 为 TSVD 选择最佳数量的成分 292 | 293 | ```py 294 | # 加载库 295 | from sklearn.preprocessing import StandardScaler 296 | from sklearn.decomposition import TruncatedSVD 297 | from scipy.sparse import csr_matrix 298 | from sklearn import datasets 299 | import numpy as np 300 | 301 | # 加载数据 302 | digits = datasets.load_digits() 303 | 304 | # Standardize the feature matrix 305 | X = StandardScaler().fit_transform(digits.data) 306 | 307 | # 制作系数矩阵 308 | X_sparse = csr_matrix(X) 309 | 310 | # 创建并使用特征数减一运行 TSVD 311 | tsvd = TruncatedSVD(n_components=X_sparse.shape[1]-1) 312 | X_tsvd = tsvd.fit(X) 313 | 314 | # 解释方差的列表 315 | tsvd_var_ratios = tsvd.explained_variance_ratio_ 316 | 317 | # 创建函数 318 | def select_n_components(var_ratio, goal_var: float) -> int: 319 | # 设置目前为止的初始解释方差 320 | total_variance = 0.0 321 | 322 | # 设置初始特征数 323 | n_components = 0 324 | 325 | # 对于每个特征的解释方差 326 | for explained_variance in var_ratio: 327 | 328 | # 将解释方差添加到总体 329 | total_variance += explained_variance 330 | 331 | # 成分数加一 332 | n_components += 1 333 | 334 | # 如果我们达到了我们的解释方差目标 335 | if total_variance >= goal_var: 336 | # 结束循环 337 | break 338 | 339 | # 返回成分数量 340 | return n_components 341 | 342 | # 执行函数 343 | select_n_components(tsvd_var_ratios, 0.95) 344 | 345 | # 40 346 | ``` 347 | 348 | ## 将 LDA 用于降维 349 | 350 | ```py 351 | # 加载库 352 | from sklearn import datasets 353 | from sklearn.discriminant_analysis import LinearDiscriminantAnalysis 354 | 355 | # 加载鸢尾花数据集 356 | iris = datasets.load_iris() 357 | X = iris.data 358 | y = iris.target 359 | 360 | # 创建 LDA,它将数据降维到 1 个特征 361 | lda = LinearDiscriminantAnalysis(n_components=1) 362 | 363 | # 运行 LDA 并使用它转换特征 364 | X_lda = lda.fit(X, y).transform(X) 365 | 366 | # 打印特征数 367 | print('Original number of features:', X.shape[1]) 368 | print('Reduced number of features:', X_lda.shape[1]) 369 | 370 | ''' 371 | Original number of features: 4 372 | Reduced number of features: 1 373 | ''' 374 | 375 | ## 查看解释方差比 376 | lda.explained_variance_ratio_ 377 | 378 | # array([ 0.99147248]) 379 | ``` 380 | -------------------------------------------------------------------------------- /8.md: -------------------------------------------------------------------------------- 1 | # 八、特征选择 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | 9 | ## 用于特征选取的 ANOVA F 值 10 | 11 | 如果特征是类别的,计算每个特征与目标向量之间的卡方(![](img/tex-2f728dbcde765f5a357bce9752c0d878.gif))统计量。 但是,如果特征是定量的,则计算每个特征与目标向量之间的 ANOVA F 值。 12 | 13 | F 值得分检查当我们按照目标向量对数字特征进行分组时,每个组的均值是否显着不同。 14 | 15 | ```py 16 | # 加载库 17 | from sklearn.datasets import load_iris 18 | from sklearn.feature_selection import SelectKBest 19 | from sklearn.feature_selection import f_classif 20 | 21 | # 加载鸢尾花数据 22 | iris = load_iris() 23 | 24 | # 创建特征和标签 25 | X = iris.data 26 | y = iris.target 27 | 28 | # 创建 SelectKBest 对象来选择两个带有最佳 ANOVA F 值的特征 29 | fvalue_selector = SelectKBest(f_classif, k=2) 30 | 31 | # 对 SelectKBest 对象应用特征和标签 32 | X_kbest = fvalue_selector.fit_transform(X, y) 33 | 34 | # 展示结果 35 | print('Original number of features:', X.shape[1]) 36 | print('Reduced number of features:', X_kbest.shape[1]) 37 | 38 | ''' 39 | Original number of features: 4 40 | Reduced number of features: 2 41 | ''' 42 | ``` 43 | 44 | ## 用于特征选择的卡方 45 | 46 | ![](img/b83cb13103af990e41eaf7253c0018e9.jpg) 47 | 48 | ```py 49 | # 加载库 50 | from sklearn.datasets import load_iris 51 | from sklearn.feature_selection import SelectKBest 52 | from sklearn.feature_selection import chi2 53 | 54 | # 加载鸢尾花数据 55 | iris = load_iris() 56 | 57 | # 创建特征和目标 58 | X = iris.data 59 | y = iris.target 60 | 61 | # 通过将数据转换为整数,转换为类别数据 62 | X = X.astype(int) 63 | 64 | # 选择两个卡方统计量最高的特征 65 | chi2_selector = SelectKBest(chi2, k=2) 66 | X_kbest = chi2_selector.fit_transform(X, y) 67 | 68 | # 展示结果 69 | print('Original number of features:', X.shape[1]) 70 | print('Reduced number of features:', X_kbest.shape[1]) 71 | 72 | ''' 73 | Original number of features: 4 74 | Reduced number of features: 2 75 | ''' 76 | ``` 77 | 78 | ## 丢弃高度相关的特征 79 | 80 | ```py 81 | # 加载库 82 | import pandas as pd 83 | import numpy as np 84 | 85 | # 创建特征矩阵,具有两个高度相关特征 86 | X = np.array([[1, 1, 1], 87 | [2, 2, 0], 88 | [3, 3, 1], 89 | [4, 4, 0], 90 | [5, 5, 1], 91 | [6, 6, 0], 92 | [7, 7, 1], 93 | [8, 7, 0], 94 | [9, 7, 1]]) 95 | 96 | # 将特征矩阵转换为 DataFrame 97 | df = pd.DataFrame(X) 98 | 99 | # 查看数据帧 100 | df 101 | ``` 102 | 103 | | | 0 | 1 | 2 | 104 | | --- | --- | --- | --- | 105 | | 0 | 1 | 1 | 1 | 106 | | 1 | 2 | 2 | 0 | 107 | | 2 | 3 | 3 | 1 | 108 | | 3 | 4 | 4 | 0 | 109 | | 4 | 5 | 5 | 1 | 110 | | 5 | 6 | 6 | 0 | 111 | | 6 | 7 | 7 | 1 | 112 | | 7 | 8 | 7 | 0 | 113 | | 8 | 9 | 7 | 1 | 114 | 115 | ```py 116 | # 创建相关度矩阵 117 | corr_matrix = df.corr().abs() 118 | 119 | # 选择相关度矩阵的上三角 120 | upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool)) 121 | 122 | # 寻找相关度大于 0.95 的特征列的索引 123 | to_drop = [column for column in upper.columns if any(upper[column] > 0.95)] 124 | 125 | # 丢弃特征 126 | df.drop(df.columns[to_drop], axis=1) 127 | ``` 128 | 129 | | | 0 | 2 | 130 | | --- | --- | --- | 131 | | 0 | 1 | 1 | 132 | | 1 | 2 | 0 | 133 | | 2 | 3 | 1 | 134 | | 3 | 4 | 0 | 135 | | 4 | 5 | 1 | 136 | | 5 | 6 | 0 | 137 | | 6 | 7 | 1 | 138 | | 7 | 8 | 0 | 139 | | 8 | 9 | 1 | 140 | 141 | ## 递归特征消除 142 | 143 | ```py 144 | # 加载库 145 | from sklearn.datasets import make_regression 146 | from sklearn.feature_selection import RFECV 147 | from sklearn import datasets, linear_model 148 | import warnings 149 | 150 | # 消除烦人但无害的警告 151 | warnings.filterwarnings(action="ignore", module="scipy", message="^internal gelsd") 152 | 153 | # 生成特征矩阵,目标向量和真实相关度 154 | X, y = make_regression(n_samples = 10000, 155 | n_features = 100, 156 | n_informative = 2, 157 | random_state = 1) 158 | 159 | # 创建线性回归 160 | ols = linear_model.LinearRegression() 161 | 162 | # 创建递归特征消除器,按照 MSE 对特征评分 163 | rfecv = RFECV(estimator=ols, step=1, scoring='neg_mean_squared_error') 164 | 165 | # 拟合递归特征消除器 166 | rfecv.fit(X, y) 167 | 168 | # 递归特征消除 169 | rfecv.transform(X) 170 | 171 | ''' 172 | array([[ 0.00850799, 0.7031277 , -1.2416911 , -0.25651883, -0.10738769], 173 | [-1.07500204, 2.56148527, 0.5540926 , -0.72602474, -0.91773159], 174 | [ 1.37940721, -1.77039484, -0.59609275, 0.51485979, -1.17442094], 175 | ..., 176 | [-0.80331656, -1.60648007, 0.37195763, 0.78006511, -0.20756972], 177 | [ 0.39508844, -1.34564911, -0.9639982 , 1.7983361 , -0.61308782], 178 | [-0.55383035, 0.82880112, 0.24597833, -1.71411248, 0.3816852 ]]) 179 | ''' 180 | 181 | # 最佳特征数量 182 | rfecv.n_features_ 183 | 184 | # 5 185 | ``` 186 | 187 | ## 方差阈值二元特征 188 | 189 | ```py 190 | from sklearn.feature_selection import VarianceThreshold 191 | 192 | # 创建特征矩阵: 193 | # 特征 0:80% 的类 0 194 | # 特征 1:80% 的类 1 195 | # 特征 2:60% 的类 0,40% 的类 1 196 | X = [[0, 1, 0], 197 | [0, 1, 1], 198 | [0, 1, 0], 199 | [0, 1, 1], 200 | [1, 0, 0]] 201 | ``` 202 | 203 | 在二元特征(即伯努利随机变量)中,方差计算如下: 204 | 205 | ![](img/tex-46277250c0e8d4fadf188d0d22fa1343.gif)](../img/tex-6959801ea921957ed53ddaab936b9409.gif) 206 | 207 | 其中 ![](img/tex-83878c91171338902e0fe0fb97a8c47a.gif) 是类 1 观测的比例。 因此,通过设置 ![](img/tex-83878c91171338902e0fe0fb97a8c47a.gif),我们可以删除绝大多数观察是类 1 的特征。 208 | 209 | ```py 210 | # Run threshold by variance 211 | thresholder = VarianceThreshold(threshold=(.75 * (1 - .75))) 212 | thresholder.fit_transform(X) 213 | 214 | ''' 215 | array([[0], 216 | [1], 217 | [0], 218 | [1], 219 | [0]]) 220 | ''' 221 | ``` 222 | 223 | ## 用于特征选择的方差阈值 224 | 225 | ![](img/d3a827df8e9eb16e33ce7b3f670941fb.jpg) 226 | 227 | ```py 228 | from sklearn import datasets 229 | from sklearn.feature_selection import VarianceThreshold 230 | 231 | # 加载鸢尾花数据 232 | iris = datasets.load_iris() 233 | 234 | # 创建特征和目标 235 | X = iris.data 236 | y = iris.target 237 | 238 | # 使用方差阈值 0.5 创建 VarianceThreshold 对象 239 | thresholder = VarianceThreshold(threshold=.5) 240 | 241 | # 应用方差阈值 242 | X_high_variance = thresholder.fit_transform(X) 243 | 244 | # 查看方差大于阈值的前五行 245 | X_high_variance[0:5] 246 | 247 | ''' 248 | array([[ 5.1, 1.4, 0.2], 249 | [ 4.9, 1.4, 0.2], 250 | [ 4.7, 1.3, 0.2], 251 | [ 4.6, 1.5, 0.2], 252 | [ 5\. , 1.4, 0.2]]) 253 | ''' 254 | ``` 255 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 数据科学和人工智能技术笔记 2 | 3 | > 作者:[Chris Albon](https://chrisalbon.com/) 4 | > 5 | > 译者:[飞龙](https://github.com/wizardforcel) 6 | > 7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) 8 | > 9 | > 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。 10 | 11 | + [ApacheCN 机器学习交流群 629470233](http://shang.qq.com/wpa/qunwpa?idkey=30e5f1123a79867570f665aa3a483ca404b1c3f77737bc01ec520ed5f078ddef) 12 | + [ApacheCN 学习资源](http://www.apachecn.org/) 13 | 14 | 15 | 16 | + [在线阅读](https://www.gitbook.com/book/wizardforcel/ds-ai-tech-notes/details) 17 | + [PDF格式](https://www.gitbook.com/download/pdf/book/wizardforcel/ds-ai-tech-notes) 18 | + [EPUB格式](https://www.gitbook.com/download/epub/book/wizardforcel/ds-ai-tech-notes) 19 | + [MOBI格式](https://www.gitbook.com/download/mobi/book/wizardforcel/ds-ai-tech-notes) 20 | + [代码仓库](https://github.com/apachecn/ds-ai-tech-notes) 21 | 22 | ## 赞助我 23 | 24 | ![](http://ww1.sinaimg.cn/large/841aea59ly1fx0qnvulnjj2074074747.jpg) 25 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | + [数据科学和人工智能技术笔记](README.md) 2 | + [一、向量、矩阵和数组](1.md) 3 | + [二、数据准备](2.md) 4 | + [三、数据预处理](3.md) 5 | + [四、图像预处理](4.md) 6 | + [五、文本预处理](5.md) 7 | + [六、日期时间预处理](6.md) 8 | + [七、特征工程](7.md) 9 | + [八、特征选择](8.md) 10 | + [九、模型验证](9.md) 11 | + [十、模型选择](10.md) 12 | + [十一、线性回归](11.md) 13 | + [十二、逻辑回归](12.md) 14 | + [十三、树和森林](13.md) 15 | + [十四、K 最近邻](14.md) 16 | + [十五、支持向量机](15.md) 17 | + [十六、朴素贝叶斯](16.md) 18 | + [十七、聚类](17.md) 19 | + [十八、Keras](18.md) 20 | + [十九、数据整理(上)](19.1.md) 21 | + [十九、数据整理(下)](19.2.md) 22 | + [二十、数据可视化](20.md) 23 | + [二十一、统计学](21.md) -------------------------------------------------------------------------------- /img/05fb264e8717acd28d1574bee4090029.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/05fb264e8717acd28d1574bee4090029.jpg -------------------------------------------------------------------------------- /img/19274741dc836a609c2722cd32770692.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/19274741dc836a609c2722cd32770692.jpg -------------------------------------------------------------------------------- /img/2cdf1de23dbb6214dfbadd6865c464b0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/2cdf1de23dbb6214dfbadd6865c464b0.jpg -------------------------------------------------------------------------------- /img/3375cf9c5dcba56ec89d3c109d477b42.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3375cf9c5dcba56ec89d3c109d477b42.jpg -------------------------------------------------------------------------------- /img/33ac24c354a4ffba2cf95d531aa2f4dd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/33ac24c354a4ffba2cf95d531aa2f4dd.jpg -------------------------------------------------------------------------------- /img/371afefc20188fb5874a852c50bce6c5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/371afefc20188fb5874a852c50bce6c5.jpg -------------------------------------------------------------------------------- /img/37cf1c7a62127199e6e8580d9d1e6248.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/37cf1c7a62127199e6e8580d9d1e6248.jpg -------------------------------------------------------------------------------- /img/3c3fec0241cfa4c4f5bb78c571a0f884.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3c3fec0241cfa4c4f5bb78c571a0f884.jpg -------------------------------------------------------------------------------- /img/3e9f30437a269befbe80859ffe27537e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3e9f30437a269befbe80859ffe27537e.jpg -------------------------------------------------------------------------------- /img/3eb344ac521726353def27e303517ba9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3eb344ac521726353def27e303517ba9.jpg -------------------------------------------------------------------------------- /img/3f0ca2e88676e335b8b20523ff94fec7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3f0ca2e88676e335b8b20523ff94fec7.jpg -------------------------------------------------------------------------------- /img/3f439b203d4e179a2c15c84d3bb15cb7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/3f439b203d4e179a2c15c84d3bb15cb7.jpg -------------------------------------------------------------------------------- /img/41b5b4e4857f15a32a484b8b4e3afbbc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/41b5b4e4857f15a32a484b8b4e3afbbc.jpg -------------------------------------------------------------------------------- /img/44cffe94ab676a80cb08e22bc19fb02d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/44cffe94ab676a80cb08e22bc19fb02d.jpg -------------------------------------------------------------------------------- /img/467a25fe9ed0bcdf31a140a351b7865c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/467a25fe9ed0bcdf31a140a351b7865c.jpg -------------------------------------------------------------------------------- /img/4c2e42ce1e09d07bd5b30da33b4adf2f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/4c2e42ce1e09d07bd5b30da33b4adf2f.jpg -------------------------------------------------------------------------------- /img/502eebaffff7022fe6dd5b4a3f901d71.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/502eebaffff7022fe6dd5b4a3f901d71.jpg -------------------------------------------------------------------------------- /img/5077893a199a7192498596a047d24c48.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/5077893a199a7192498596a047d24c48.jpg -------------------------------------------------------------------------------- /img/53a181f79fb487549a6006294f7bc879.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/53a181f79fb487549a6006294f7bc879.jpg -------------------------------------------------------------------------------- /img/54fd49268017a7b697a4eee7c911d969.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/54fd49268017a7b697a4eee7c911d969.jpg -------------------------------------------------------------------------------- /img/6516b9606dafb489e601dc4dcee9eb11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/6516b9606dafb489e601dc4dcee9eb11.jpg -------------------------------------------------------------------------------- /img/65334cd1b4791a63cb320a2f2fa44ac1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/65334cd1b4791a63cb320a2f2fa44ac1.jpg -------------------------------------------------------------------------------- /img/7592106e9633ec8a8fb6e14c1f2a2d0b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/7592106e9633ec8a8fb6e14c1f2a2d0b.jpg -------------------------------------------------------------------------------- /img/797049479fae3d337256efa33157af1a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/797049479fae3d337256efa33157af1a.jpg -------------------------------------------------------------------------------- /img/7e623fe011680e01bfceb81efe4cff72.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/7e623fe011680e01bfceb81efe4cff72.jpg -------------------------------------------------------------------------------- /img/89fdaf9caa2b88f10c2e281f0071ab1e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/89fdaf9caa2b88f10c2e281f0071ab1e.jpg -------------------------------------------------------------------------------- /img/99cac4640cc847b6e1e8c94a3d85d7cc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/99cac4640cc847b6e1e8c94a3d85d7cc.jpg -------------------------------------------------------------------------------- /img/a98f870fa95d64ec22552e8db8a4dd7f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/a98f870fa95d64ec22552e8db8a4dd7f.jpg -------------------------------------------------------------------------------- /img/b069822c94e45cd78df010400c327e27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/b069822c94e45cd78df010400c327e27.jpg -------------------------------------------------------------------------------- /img/b83cb13103af990e41eaf7253c0018e9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/b83cb13103af990e41eaf7253c0018e9.jpg -------------------------------------------------------------------------------- /img/bc7d72780c8296115ef744873807d5ff.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/bc7d72780c8296115ef744873807d5ff.jpg -------------------------------------------------------------------------------- /img/bce11f1812038907dfc04afe063b942e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/bce11f1812038907dfc04afe063b942e.jpg -------------------------------------------------------------------------------- /img/bd066f4a27e6863c89a4df513959be98.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/bd066f4a27e6863c89a4df513959be98.jpg -------------------------------------------------------------------------------- /img/c936cfb9b6729010955e67e7aa51a4de.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/c936cfb9b6729010955e67e7aa51a4de.jpg -------------------------------------------------------------------------------- /img/cd28dcfca524b96afc6ddf81d6f0c298.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/cd28dcfca524b96afc6ddf81d6f0c298.jpg -------------------------------------------------------------------------------- /img/d3a827df8e9eb16e33ce7b3f670941fb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/d3a827df8e9eb16e33ce7b3f670941fb.jpg -------------------------------------------------------------------------------- /img/d86fdc26f2d0ab274ac8164975cc622b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/d86fdc26f2d0ab274ac8164975cc622b.jpg -------------------------------------------------------------------------------- /img/dae1a905b9e7104ebcacfa982c3c9a5c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/dae1a905b9e7104ebcacfa982c3c9a5c.jpg -------------------------------------------------------------------------------- /img/e78c54ef3d6a719f1ffa6a538f9353de.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/e78c54ef3d6a719f1ffa6a538f9353de.jpg -------------------------------------------------------------------------------- /img/ec18cd723a8b269d960ff8c900a113eb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/ec18cd723a8b269d960ff8c900a113eb.jpg -------------------------------------------------------------------------------- /img/tex-020a9f6f179050a671f6f6f28169b20d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-020a9f6f179050a671f6f6f28169b20d.gif -------------------------------------------------------------------------------- /img/tex-02129bb861061d1a052c592e2dc6b383.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-02129bb861061d1a052c592e2dc6b383.gif -------------------------------------------------------------------------------- /img/tex-08ab6c8d7eefc2ed7722b28e671aa0bc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-08ab6c8d7eefc2ed7722b28e671aa0bc.gif -------------------------------------------------------------------------------- /img/tex-08c711a5590de57d9dd77d7b5ba4398f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-08c711a5590de57d9dd77d7b5ba4398f.gif -------------------------------------------------------------------------------- /img/tex-09663031eaa8ade66806d053272e579c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-09663031eaa8ade66806d053272e579c.gif -------------------------------------------------------------------------------- /img/tex-0d61f8370cad1d412f80b84d143e1257.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-0d61f8370cad1d412f80b84d143e1257.gif -------------------------------------------------------------------------------- /img/tex-10ac877830803e44c3b7dc1b104101dd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-10ac877830803e44c3b7dc1b104101dd.gif -------------------------------------------------------------------------------- /img/tex-18daef71b5d25ce76b8628a81e4fc76b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-18daef71b5d25ce76b8628a81e4fc76b.gif -------------------------------------------------------------------------------- /img/tex-1a68df3b73be15a6da50bd6cfdba832a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-1a68df3b73be15a6da50bd6cfdba832a.gif -------------------------------------------------------------------------------- /img/tex-1aa7c4b9ac179483858f457df9ee441b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-1aa7c4b9ac179483858f457df9ee441b.gif -------------------------------------------------------------------------------- /img/tex-1ae38954f6cba2eafda4e9c34df8d944.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-1ae38954f6cba2eafda4e9c34df8d944.gif -------------------------------------------------------------------------------- /img/tex-272ba5cfd2789d670bc65e40587345c3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-272ba5cfd2789d670bc65e40587345c3.gif -------------------------------------------------------------------------------- /img/tex-2b30ddf4881c9acfc3bc0cf2880eefaa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-2b30ddf4881c9acfc3bc0cf2880eefaa.gif -------------------------------------------------------------------------------- /img/tex-2f728dbcde765f5a357bce9752c0d878.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-2f728dbcde765f5a357bce9752c0d878.gif -------------------------------------------------------------------------------- /img/tex-31f830c208ca5fcbf1bca34de8d796a6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-31f830c208ca5fcbf1bca34de8d796a6.gif -------------------------------------------------------------------------------- /img/tex-347685e5ebc84836b7aea484b48eb555.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-347685e5ebc84836b7aea484b48eb555.gif -------------------------------------------------------------------------------- /img/tex-363b122c528f54df4a0446b6bab05515.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-363b122c528f54df4a0446b6bab05515.gif -------------------------------------------------------------------------------- /img/tex-41410fd2b1e89fe55a7638312d82540c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-41410fd2b1e89fe55a7638312d82540c.gif -------------------------------------------------------------------------------- /img/tex-415290769594460e2e485922904f345d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-415290769594460e2e485922904f345d.gif -------------------------------------------------------------------------------- /img/tex-45fe873d5f83badc655eed13e1cd8ee8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-45fe873d5f83badc655eed13e1cd8ee8.gif -------------------------------------------------------------------------------- /img/tex-46277250c0e8d4fadf188d0d22fa1343.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-46277250c0e8d4fadf188d0d22fa1343.gif -------------------------------------------------------------------------------- /img/tex-48d71f5dc3c36e27922ff67fe9e88c6e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-48d71f5dc3c36e27922ff67fe9e88c6e.gif -------------------------------------------------------------------------------- /img/tex-4aa861124eff57dd7988faa6753e8b7e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-4aa861124eff57dd7988faa6753e8b7e.gif -------------------------------------------------------------------------------- /img/tex-50d7cc01f0e1e57d81240e646606b14a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-50d7cc01f0e1e57d81240e646606b14a.gif -------------------------------------------------------------------------------- /img/tex-52539b56794b13d260a84f3461c80f49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-52539b56794b13d260a84f3461c80f49.gif -------------------------------------------------------------------------------- /img/tex-55ddce33f44e17960c51e0b727ed0c1b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-55ddce33f44e17960c51e0b727ed0c1b.gif -------------------------------------------------------------------------------- /img/tex-5765c72ae234bd48dadb3a8bfd20580b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-5765c72ae234bd48dadb3a8bfd20580b.gif -------------------------------------------------------------------------------- /img/tex-5af9e28d609b16eb25693f44ea9d7a8f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-5af9e28d609b16eb25693f44ea9d7a8f.gif -------------------------------------------------------------------------------- /img/tex-5e956d2dac25a04b1f0384a339af61de.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-5e956d2dac25a04b1f0384a339af61de.gif -------------------------------------------------------------------------------- /img/tex-5fdb0734a2a8679264029c65df7a492b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-5fdb0734a2a8679264029c65df7a492b.gif -------------------------------------------------------------------------------- /img/tex-682edd15f544ef9727367918185ee5f4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-682edd15f544ef9727367918185ee5f4.gif -------------------------------------------------------------------------------- /img/tex-68ce6a2b5a771f689d84ac8e24e31ddf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-68ce6a2b5a771f689d84ac8e24e31ddf.gif -------------------------------------------------------------------------------- /img/tex-6959801ea921957ed53ddaab936b9409.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-6959801ea921957ed53ddaab936b9409.gif -------------------------------------------------------------------------------- /img/tex-69c694c13d6cb056f400aff019f023dd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-69c694c13d6cb056f400aff019f023dd.gif -------------------------------------------------------------------------------- /img/tex-6b5a5f025640932b2554f6d400b3e45f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-6b5a5f025640932b2554f6d400b3e45f.gif -------------------------------------------------------------------------------- /img/tex-6b5eaa31568b521152a5aacec91548c2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-6b5eaa31568b521152a5aacec91548c2.gif -------------------------------------------------------------------------------- /img/tex-6fbdf291cda891b99cf211417ad1df18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-6fbdf291cda891b99cf211417ad1df18.gif -------------------------------------------------------------------------------- /img/tex-6fe2793f9b6ee038f11e89402bbf3c84.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-6fe2793f9b6ee038f11e89402bbf3c84.gif -------------------------------------------------------------------------------- /img/tex-7015ea99e7b80644c1630cdfb0f6bbda.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7015ea99e7b80644c1630cdfb0f6bbda.gif -------------------------------------------------------------------------------- /img/tex-70e59a996bd69a0c21878b4093375e92.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-70e59a996bd69a0c21878b4093375e92.gif -------------------------------------------------------------------------------- /img/tex-777eeb07996381e00006e77dd1aaf39f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-777eeb07996381e00006e77dd1aaf39f.gif -------------------------------------------------------------------------------- /img/tex-7b7f9dbfea05c83784f8b85149852f08.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7b7f9dbfea05c83784f8b85149852f08.gif -------------------------------------------------------------------------------- /img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7b8b965ad4bca0e41ab51de7b31363a1.gif -------------------------------------------------------------------------------- /img/tex-7d627c4584744c44dde8a2e35bcfb90c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7d627c4584744c44dde8a2e35bcfb90c.gif -------------------------------------------------------------------------------- /img/tex-7e18dabda345d4f3a3642ecf7fa61ccf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7e18dabda345d4f3a3642ecf7fa61ccf.gif -------------------------------------------------------------------------------- /img/tex-7fc56270e7a70fa81a5935b72eacbe29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-7fc56270e7a70fa81a5935b72eacbe29.gif -------------------------------------------------------------------------------- /img/tex-83878c91171338902e0fe0fb97a8c47a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-83878c91171338902e0fe0fb97a8c47a.gif -------------------------------------------------------------------------------- /img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-865c0c0b4ab0e063e5caa3387c1a8741.gif -------------------------------------------------------------------------------- /img/tex-8a842403dafad0ee564a1a212d19e77a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8a842403dafad0ee564a1a212d19e77a.gif -------------------------------------------------------------------------------- /img/tex-8c06f77a048c7032b6258f4ceddcac77.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8c06f77a048c7032b6258f4ceddcac77.gif -------------------------------------------------------------------------------- /img/tex-8ce4b16b22b58894aa86c421e8759df3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8ce4b16b22b58894aa86c421e8759df3.gif -------------------------------------------------------------------------------- /img/tex-8d62e469fb30ed435a668eb5c035b1f6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8d62e469fb30ed435a668eb5c035b1f6.gif -------------------------------------------------------------------------------- /img/tex-8f43fce8dbdf3c4f8d0ac91f0de1d43d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8f43fce8dbdf3c4f8d0ac91f0de1d43d.gif -------------------------------------------------------------------------------- /img/tex-8fa14cdd754f91cc6554c9e71929cce7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-8fa14cdd754f91cc6554c9e71929cce7.gif -------------------------------------------------------------------------------- /img/tex-9081cb9b8d4cd5ee177a3287608f7424.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-9081cb9b8d4cd5ee177a3287608f7424.gif -------------------------------------------------------------------------------- /img/tex-99600e95adcc97c986df86d4b612cf52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-99600e95adcc97c986df86d4b612cf52.gif -------------------------------------------------------------------------------- /img/tex-9a7cc99da8feacd5e7efd172ae2b9b5d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-9a7cc99da8feacd5e7efd172ae2b9b5d.gif -------------------------------------------------------------------------------- /img/tex-9d5ed678fe57bcca610140957afab571.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-9d5ed678fe57bcca610140957afab571.gif -------------------------------------------------------------------------------- /img/tex-9dd4e461268c8034f5c8564e155c67a6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-9dd4e461268c8034f5c8564e155c67a6.gif -------------------------------------------------------------------------------- /img/tex-9ed438b9777ace57e974cb63995679ed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-9ed438b9777ace57e974cb63995679ed.gif -------------------------------------------------------------------------------- /img/tex-a061b9ec570e172274d24a31b7f2ec4e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a061b9ec570e172274d24a31b7f2ec4e.gif -------------------------------------------------------------------------------- /img/tex-a276b69c27fa2fc5adb0a238cb21baa3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a276b69c27fa2fc5adb0a238cb21baa3.gif -------------------------------------------------------------------------------- /img/tex-a438673491daae8148eae77373b6a467.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a438673491daae8148eae77373b6a467.gif -------------------------------------------------------------------------------- /img/tex-a57d522c3188c5cf8f0818e9d1a2946b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a57d522c3188c5cf8f0818e9d1a2946b.gif -------------------------------------------------------------------------------- /img/tex-a5f3c6a11b03839d46af9fb43c97c188.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a5f3c6a11b03839d46af9fb43c97c188.gif -------------------------------------------------------------------------------- /img/tex-a6b711ff5b6087f86069d31ba049add7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a6b711ff5b6087f86069d31ba049add7.gif -------------------------------------------------------------------------------- /img/tex-a97118fb9e8d7e006a466bfc0771f888.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-a97118fb9e8d7e006a466bfc0771f888.gif -------------------------------------------------------------------------------- /img/tex-ad6d5470eaff252c993327c248d56b0e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-ad6d5470eaff252c993327c248d56b0e.gif -------------------------------------------------------------------------------- /img/tex-b3d4a2c5b40d7af881f9d19730b6ea7c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-b3d4a2c5b40d7af881f9d19730b6ea7c.gif -------------------------------------------------------------------------------- /img/tex-b4ceec2c4656f5c1e7fc76c59c4f80f3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-b4ceec2c4656f5c1e7fc76c59c4f80f3.gif -------------------------------------------------------------------------------- /img/tex-b6253f470c6bf31d67e04d80d43704be.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-b6253f470c6bf31d67e04d80d43704be.gif -------------------------------------------------------------------------------- /img/tex-bde5f474d3e4c7e38ddd6440a38a7f4e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-bde5f474d3e4c7e38ddd6440a38a7f4e.gif -------------------------------------------------------------------------------- /img/tex-c39d1645d55ca4afb20c8d6a365615bb.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-c39d1645d55ca4afb20c8d6a365615bb.gif -------------------------------------------------------------------------------- /img/tex-c9f6d8557ce40f989fa727b5c0bb1ddf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-c9f6d8557ce40f989fa727b5c0bb1ddf.gif -------------------------------------------------------------------------------- /img/tex-cea485c1212579d0e0fb0f665f5a85dd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-cea485c1212579d0e0fb0f665f5a85dd.gif -------------------------------------------------------------------------------- /img/tex-d5530fdea73b725bbdb348dee89e4a20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-d5530fdea73b725bbdb348dee89e4a20.gif -------------------------------------------------------------------------------- /img/tex-d5cd57541fb4b75d5fdbd688f87323d5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-d5cd57541fb4b75d5fdbd688f87323d5.gif -------------------------------------------------------------------------------- /img/tex-d8dd7d0f3eb7145ca41c711457b7eb8f.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-d8dd7d0f3eb7145ca41c711457b7eb8f.gif -------------------------------------------------------------------------------- /img/tex-d945100c5fa6a400570dcacfb1fc9869.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-d945100c5fa6a400570dcacfb1fc9869.gif -------------------------------------------------------------------------------- /img/tex-dabc824c5f8ee13faaae5a59fec9afdc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-dabc824c5f8ee13faaae5a59fec9afdc.gif -------------------------------------------------------------------------------- /img/tex-ddc7076014b85741e2dbfe52ec40ed52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-ddc7076014b85741e2dbfe52ec40ed52.gif -------------------------------------------------------------------------------- /img/tex-de3f198290bfe64e8e3f289f20c44434.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-de3f198290bfe64e8e3f289f20c44434.gif -------------------------------------------------------------------------------- /img/tex-e125e16b9b9b9a753459b31c44e565da.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-e125e16b9b9b9a753459b31c44e565da.gif -------------------------------------------------------------------------------- /img/tex-e1671797c52e15f763380b45e841ec32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-e1671797c52e15f763380b45e841ec32.gif -------------------------------------------------------------------------------- /img/tex-e5a7472d780a5a032c7775cc5e3ce901.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-e5a7472d780a5a032c7775cc5e3ce901.gif -------------------------------------------------------------------------------- /img/tex-e8100be07fa5419af6c6738b934dfca0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-e8100be07fa5419af6c6738b934dfca0.gif -------------------------------------------------------------------------------- /img/tex-ea7e2e0d45588bedd672db7688459b46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-ea7e2e0d45588bedd672db7688459b46.gif -------------------------------------------------------------------------------- /img/tex-ecc57614c202a2c740598474fdbbb88e.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-ecc57614c202a2c740598474fdbbb88e.gif -------------------------------------------------------------------------------- /img/tex-f8281cafb08efe03bce3816f00fdd12d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-f8281cafb08efe03bce3816f00fdd12d.gif -------------------------------------------------------------------------------- /img/tex-f9a3b8e9e501458e8face47cae8826de.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-f9a3b8e9e501458e8face47cae8826de.gif -------------------------------------------------------------------------------- /img/tex-fc3b69ffc2761499a8f26feaaf2f3057.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-fc3b69ffc2761499a8f26feaaf2f3057.gif -------------------------------------------------------------------------------- /img/tex-fd6a329594a8718f6de1a6d5728eb7b7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizardforcel/ds-ai-tech-notes/1469c4004002af252265df9fc4d7e3d8ad5705fe/img/tex-fd6a329594a8718f6de1a6d5728eb7b7.gif -------------------------------------------------------------------------------- /src/process_tex.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var crypto = require('crypto') 3 | var request = require('sync-request') 4 | 5 | var doc_dir = process.argv[2] || '..' 6 | var img_dir = doc_dir + '/img' 7 | 8 | try { fs.mkdirSync(img_dir) } 9 | catch(e) {} 10 | 11 | function processTex(md) { 12 | 13 | var rm; 14 | while(rm = /\$(.+?)\$/g.exec(md)){ 15 | var tex = rm[1] 16 | //console.log(rm) 17 | var url = 'http://latex.codecogs.com/gif.latex?' 18 | + encodeURIComponent(tex) 19 | var tex_md5 = crypto.createHash("md5").update(tex).digest('hex') 20 | var img = request('get', url).getBody() 21 | 22 | // replace_all 23 | md = md.split(rm[0]).join(`![${tex}](img/tex-${tex_md5}.gif)`) 24 | fs.writeFileSync(`${img_dir}/tex-${tex_md5}.gif`, img) 25 | 26 | console.log(tex_md5) 27 | } 28 | 29 | return md 30 | 31 | } 32 | 33 | function main() { 34 | 35 | var flist = fs.readdirSync(doc_dir).filter(s => s.endsWith('.md')) 36 | 37 | for(var fname of flist) { 38 | 39 | fname = doc_dir + '/' + fname 40 | console.log(fname) 41 | 42 | var md = fs.readFileSync(fname, 'utf-8') 43 | md = processTex(md) 44 | fs.writeFileSync(fname, md) 45 | } 46 | 47 | console.log('done') 48 | 49 | } 50 | 51 | main() -------------------------------------------------------------------------------- /styles/ebook.css: -------------------------------------------------------------------------------- 1 | /* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */ 2 | /* Author: Nicolas Hery - http://nicolashery.com */ 3 | /* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */ 4 | /* Source: https://github.com/nicolahery/markdownpad-github */ 5 | 6 | /* RESET 7 | =============================================================================*/ 8 | 9 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 10 | margin: 0; 11 | padding: 0; 12 | border: 0; 13 | } 14 | 15 | /* BODY 16 | =============================================================================*/ 17 | 18 | body { 19 | font-family: Helvetica, arial, freesans, clean, sans-serif; 20 | font-size: 14px; 21 | line-height: 1.6; 22 | color: #333; 23 | background-color: #fff; 24 | padding: 20px; 25 | max-width: 960px; 26 | margin: 0 auto; 27 | } 28 | 29 | body>*:first-child { 30 | margin-top: 0 !important; 31 | } 32 | 33 | body>*:last-child { 34 | margin-bottom: 0 !important; 35 | } 36 | 37 | /* BLOCKS 38 | =============================================================================*/ 39 | 40 | p, blockquote, ul, ol, dl, table, pre { 41 | margin: 15px 0; 42 | } 43 | 44 | /* HEADERS 45 | =============================================================================*/ 46 | 47 | h1, h2, h3, h4, h5, h6 { 48 | margin: 20px 0 10px; 49 | padding: 0; 50 | font-weight: bold; 51 | -webkit-font-smoothing: antialiased; 52 | } 53 | 54 | h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code { 55 | font-size: inherit; 56 | } 57 | 58 | h1 { 59 | font-size: 24px; 60 | border-bottom: 1px solid #ccc; 61 | color: #000; 62 | } 63 | 64 | h2 { 65 | font-size: 18px; 66 | color: #000; 67 | } 68 | 69 | h3 { 70 | font-size: 14px; 71 | } 72 | 73 | h4 { 74 | font-size: 14px; 75 | } 76 | 77 | h5 { 78 | font-size: 14px; 79 | } 80 | 81 | h6 { 82 | color: #777; 83 | font-size: 14px; 84 | } 85 | 86 | body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child { 87 | margin-top: 0; 88 | padding-top: 0; 89 | } 90 | 91 | a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { 92 | margin-top: 0; 93 | padding-top: 0; 94 | } 95 | 96 | h1+p, h2+p, h3+p, h4+p, h5+p, h6+p { 97 | margin-top: 10px; 98 | } 99 | 100 | /* LINKS 101 | =============================================================================*/ 102 | 103 | a { 104 | color: #4183C4; 105 | text-decoration: none; 106 | } 107 | 108 | a:hover { 109 | text-decoration: underline; 110 | } 111 | 112 | /* LISTS 113 | =============================================================================*/ 114 | 115 | ul, ol { 116 | padding-left: 30px; 117 | } 118 | 119 | ul li > :first-child, 120 | ol li > :first-child, 121 | ul li ul:first-of-type, 122 | ol li ol:first-of-type, 123 | ul li ol:first-of-type, 124 | ol li ul:first-of-type { 125 | margin-top: 0px; 126 | } 127 | 128 | ul ul, ul ol, ol ol, ol ul { 129 | margin-bottom: 0; 130 | } 131 | 132 | dl { 133 | padding: 0; 134 | } 135 | 136 | dl dt { 137 | font-size: 14px; 138 | font-weight: bold; 139 | font-style: italic; 140 | padding: 0; 141 | margin: 15px 0 5px; 142 | } 143 | 144 | dl dt:first-child { 145 | padding: 0; 146 | } 147 | 148 | dl dt>:first-child { 149 | margin-top: 0px; 150 | } 151 | 152 | dl dt>:last-child { 153 | margin-bottom: 0px; 154 | } 155 | 156 | dl dd { 157 | margin: 0 0 15px; 158 | padding: 0 15px; 159 | } 160 | 161 | dl dd>:first-child { 162 | margin-top: 0px; 163 | } 164 | 165 | dl dd>:last-child { 166 | margin-bottom: 0px; 167 | } 168 | 169 | /* CODE 170 | =============================================================================*/ 171 | 172 | pre, code, tt { 173 | font-size: 12px; 174 | font-family: Consolas, "Liberation Mono", Courier, monospace; 175 | } 176 | 177 | code, tt { 178 | margin: 0 0px; 179 | padding: 0px 0px; 180 | white-space: nowrap; 181 | border: 1px solid #eaeaea; 182 | background-color: #f8f8f8; 183 | border-radius: 3px; 184 | } 185 | 186 | pre>code { 187 | margin: 0; 188 | padding: 0; 189 | white-space: pre; 190 | border: none; 191 | background: transparent; 192 | } 193 | 194 | pre { 195 | background-color: #f8f8f8; 196 | border: 1px solid #ccc; 197 | font-size: 13px; 198 | line-height: 19px; 199 | overflow: auto; 200 | padding: 6px 10px; 201 | border-radius: 3px; 202 | } 203 | 204 | pre code, pre tt { 205 | background-color: transparent; 206 | border: none; 207 | } 208 | 209 | kbd { 210 | -moz-border-bottom-colors: none; 211 | -moz-border-left-colors: none; 212 | -moz-border-right-colors: none; 213 | -moz-border-top-colors: none; 214 | background-color: #DDDDDD; 215 | background-image: linear-gradient(#F1F1F1, #DDDDDD); 216 | background-repeat: repeat-x; 217 | border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD; 218 | border-image: none; 219 | border-radius: 2px 2px 2px 2px; 220 | border-style: solid; 221 | border-width: 1px; 222 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 223 | line-height: 10px; 224 | padding: 1px 4px; 225 | } 226 | 227 | /* QUOTES 228 | =============================================================================*/ 229 | 230 | blockquote { 231 | border-left: 4px solid #DDD; 232 | padding: 0 15px; 233 | color: #777; 234 | } 235 | 236 | blockquote>:first-child { 237 | margin-top: 0px; 238 | } 239 | 240 | blockquote>:last-child { 241 | margin-bottom: 0px; 242 | } 243 | 244 | /* HORIZONTAL RULES 245 | =============================================================================*/ 246 | 247 | hr { 248 | clear: both; 249 | margin: 15px 0; 250 | height: 0px; 251 | overflow: hidden; 252 | border: none; 253 | background: transparent; 254 | border-bottom: 4px solid #ddd; 255 | padding: 0; 256 | } 257 | 258 | /* TABLES 259 | =============================================================================*/ 260 | 261 | table th { 262 | font-weight: bold; 263 | } 264 | 265 | table th, table td { 266 | border: 1px solid #ccc; 267 | padding: 6px 13px; 268 | } 269 | 270 | table tr { 271 | border-top: 1px solid #ccc; 272 | background-color: #fff; 273 | } 274 | 275 | table tr:nth-child(2n) { 276 | background-color: #f8f8f8; 277 | } 278 | 279 | /* IMAGES 280 | =============================================================================*/ 281 | 282 | img { 283 | max-width: 100% 284 | } --------------------------------------------------------------------------------