├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── datasets ├── boston.csv └── digits.csv └── src ├── decision_tree_regression.rs ├── k_means.rs ├── k_nearest_neighbors.rs ├── logistic_regression.rs ├── main.rs └── utils.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | orig/* 3 | *.ipynb 4 | /target 5 | **/*.rs.bk 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "ansi_term" 3 | version = "0.11.0" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 7 | ] 8 | 9 | [[package]] 10 | name = "atty" 11 | version = "0.2.11" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | dependencies = [ 14 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "autocfg" 21 | version = "0.1.2" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | 24 | [[package]] 25 | name = "bitflags" 26 | version = "1.0.4" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | 29 | [[package]] 30 | name = "clap" 31 | version = "2.32.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | dependencies = [ 34 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 35 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", 36 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 37 | "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 38 | "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 39 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 40 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 41 | ] 42 | 43 | [[package]] 44 | name = "cloudabi" 45 | version = "0.0.3" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "csv" 53 | version = "1.0.5" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | dependencies = [ 56 | "csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 57 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 58 | ] 59 | 60 | [[package]] 61 | name = "csv-core" 62 | version = "0.1.5" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | dependencies = [ 65 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 66 | ] 67 | 68 | [[package]] 69 | name = "either" 70 | version = "1.5.1" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | 73 | [[package]] 74 | name = "fuchsia-cprng" 75 | version = "0.1.1" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | 78 | [[package]] 79 | name = "heck" 80 | version = "0.3.1" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | dependencies = [ 83 | "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "itertools" 88 | version = "0.7.11" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | dependencies = [ 91 | "either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 92 | ] 93 | 94 | [[package]] 95 | name = "libc" 96 | version = "0.2.50" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | 99 | [[package]] 100 | name = "machine_learning_basics" 101 | version = "0.1.0" 102 | dependencies = [ 103 | "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 104 | "csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 105 | "ndarray 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", 106 | "ndarray-rand 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 107 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 108 | "quickersort 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 111 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 112 | "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 113 | ] 114 | 115 | [[package]] 116 | name = "matrixmultiply" 117 | version = "0.1.15" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | dependencies = [ 120 | "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "memchr" 125 | version = "2.2.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 129 | ] 130 | 131 | [[package]] 132 | name = "ndarray" 133 | version = "0.12.1" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | dependencies = [ 136 | "itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", 137 | "matrixmultiply 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", 138 | "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 139 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 140 | ] 141 | 142 | [[package]] 143 | name = "ndarray-rand" 144 | version = "0.9.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | dependencies = [ 147 | "ndarray 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", 148 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 149 | ] 150 | 151 | [[package]] 152 | name = "nodrop" 153 | version = "0.1.13" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | 156 | [[package]] 157 | name = "num-complex" 158 | version = "0.2.1" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | dependencies = [ 161 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 162 | ] 163 | 164 | [[package]] 165 | name = "num-traits" 166 | version = "0.2.6" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | 169 | [[package]] 170 | name = "proc-macro2" 171 | version = "0.4.27" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | dependencies = [ 174 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 175 | ] 176 | 177 | [[package]] 178 | name = "quickersort" 179 | version = "3.0.1" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | dependencies = [ 182 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 183 | "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 184 | ] 185 | 186 | [[package]] 187 | name = "quote" 188 | version = "0.6.11" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | dependencies = [ 191 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 192 | ] 193 | 194 | [[package]] 195 | name = "rand" 196 | version = "0.6.5" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | dependencies = [ 199 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 200 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 201 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 202 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 203 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 204 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 205 | "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 206 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 207 | "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 208 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 209 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 210 | ] 211 | 212 | [[package]] 213 | name = "rand_chacha" 214 | version = "0.1.1" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | dependencies = [ 217 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 218 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 219 | ] 220 | 221 | [[package]] 222 | name = "rand_core" 223 | version = "0.3.1" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | dependencies = [ 226 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 227 | ] 228 | 229 | [[package]] 230 | name = "rand_core" 231 | version = "0.4.0" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | 234 | [[package]] 235 | name = "rand_hc" 236 | version = "0.1.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | dependencies = [ 239 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 240 | ] 241 | 242 | [[package]] 243 | name = "rand_isaac" 244 | version = "0.1.1" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | dependencies = [ 247 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 248 | ] 249 | 250 | [[package]] 251 | name = "rand_jitter" 252 | version = "0.1.3" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | dependencies = [ 255 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 256 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 257 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 258 | ] 259 | 260 | [[package]] 261 | name = "rand_os" 262 | version = "0.1.3" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | dependencies = [ 265 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 266 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 267 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 268 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 269 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 270 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 271 | ] 272 | 273 | [[package]] 274 | name = "rand_pcg" 275 | version = "0.1.2" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | dependencies = [ 278 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 279 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 280 | ] 281 | 282 | [[package]] 283 | name = "rand_xorshift" 284 | version = "0.1.1" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | dependencies = [ 287 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 288 | ] 289 | 290 | [[package]] 291 | name = "rawpointer" 292 | version = "0.1.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | 295 | [[package]] 296 | name = "rdrand" 297 | version = "0.4.0" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | dependencies = [ 300 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 301 | ] 302 | 303 | [[package]] 304 | name = "redox_syscall" 305 | version = "0.1.51" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | 308 | [[package]] 309 | name = "redox_termios" 310 | version = "0.1.1" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | dependencies = [ 313 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 314 | ] 315 | 316 | [[package]] 317 | name = "serde" 318 | version = "1.0.89" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | 321 | [[package]] 322 | name = "strsim" 323 | version = "0.7.0" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | 326 | [[package]] 327 | name = "structopt" 328 | version = "0.2.15" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | dependencies = [ 331 | "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", 332 | "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", 333 | ] 334 | 335 | [[package]] 336 | name = "structopt-derive" 337 | version = "0.2.15" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | dependencies = [ 340 | "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 341 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 342 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 343 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 344 | ] 345 | 346 | [[package]] 347 | name = "syn" 348 | version = "0.15.29" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | dependencies = [ 351 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", 352 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 353 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 354 | ] 355 | 356 | [[package]] 357 | name = "termion" 358 | version = "1.5.1" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | dependencies = [ 361 | "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", 363 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 364 | ] 365 | 366 | [[package]] 367 | name = "textwrap" 368 | version = "0.10.0" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | dependencies = [ 371 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 372 | ] 373 | 374 | [[package]] 375 | name = "unicode-segmentation" 376 | version = "1.2.1" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | 379 | [[package]] 380 | name = "unicode-width" 381 | version = "0.1.5" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | 384 | [[package]] 385 | name = "unicode-xid" 386 | version = "0.1.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | 389 | [[package]] 390 | name = "unreachable" 391 | version = "1.0.0" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | dependencies = [ 394 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 395 | ] 396 | 397 | [[package]] 398 | name = "vec_map" 399 | version = "0.8.1" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | 402 | [[package]] 403 | name = "void" 404 | version = "1.0.2" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | 407 | [[package]] 408 | name = "winapi" 409 | version = "0.3.6" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | dependencies = [ 412 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 413 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 414 | ] 415 | 416 | [[package]] 417 | name = "winapi-i686-pc-windows-gnu" 418 | version = "0.4.0" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | 421 | [[package]] 422 | name = "winapi-x86_64-pc-windows-gnu" 423 | version = "0.4.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | 426 | [metadata] 427 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 428 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" 429 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" 430 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 431 | "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" 432 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 433 | "checksum csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd1c44c58078cfbeaf11fbb3eac9ae5534c23004ed770cc4bfb48e658ae4f04" 434 | "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65" 435 | "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" 436 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 437 | "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 438 | "checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" 439 | "checksum libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "aab692d7759f5cd8c859e169db98ae5b52c924add2af5fbbca11d12fefb567c1" 440 | "checksum matrixmultiply 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "dcad67dcec2d58ff56f6292582377e6921afdf3bfbd533e26fb8900ae575e002" 441 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" 442 | "checksum ndarray 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf380a8af901ad627594013a3bbac903ae0a6f94e176e47e46b5bbc1877b928" 443 | "checksum ndarray-rand 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a2b87ee9e6a97ea5447ba56903acc5afea3222b0939a2461b0e91e07e54250" 444 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 445 | "checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8" 446 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 447 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" 448 | "checksum quickersort 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "307c842cbfdc3956926dfda87716b7e425db6d4ce822a8246ca11e6ee9e5270b" 449 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 450 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 451 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 452 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 453 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 454 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 455 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 456 | "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" 457 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 458 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 459 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 460 | "checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" 461 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 462 | "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" 463 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" 464 | "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" 465 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 466 | "checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1" 467 | "checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6" 468 | "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" 469 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" 470 | "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" 471 | "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" 472 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" 473 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 474 | "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 475 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 476 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 477 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 478 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 479 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 480 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "machine_learning_basics" 3 | version = "0.1.0" 4 | authors = ["torstein "] 5 | 6 | [dependencies] 7 | csv = "1.0.0" 8 | serde = "1.0.70" 9 | structopt = "0.2.10" 10 | num-traits = "0.2.5" 11 | clap = "2.32.0" 12 | quickersort = "3.0.1" 13 | ndarray = "0.12.1" 14 | ndarray-rand = "0.9.0" 15 | rand = "0.6.5" 16 | rand_chacha = "0.1.1" 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 zotroneneis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Machine learning basics 2 | 3 | This repository contains implementations of basic machine learning algorithms in plain Rust. 4 | It is a fork of, and follows the spirit of, the original 5 | [machine learning basics in plain Python](). 6 | All algorithms are implemented from scratch without using additional machine learning libraries. 7 | The intention is to provide a basic understanding of the algorithms and their underlying structure, 8 | and how to port ML algorithms to Rust, *not* to provide the most efficient implementations. 9 | 10 | - [Logistic Regression](src/logistic_regression.rs) e.g. `cargo run -- lgr --n_iters 600 --learning_rate 0.009` 11 | - [K Nearest Neighbor](src/k_nearest_neighbors.rs) e.g. `cargo run -- knn -k 5` 12 | - [K Means Clustering](src/k_means.rs) e.g. `cargo run -- kmc -k 4` 13 | - [Decision tree for regression](src/decision_tree_regression.rs) e.g. `cargo run -- dtr --max_depth 4 --min_samples 2` 14 | 15 | ## Contribute 16 | Still missing: 17 | 18 | - Linear Regression 19 | - Perceptron 20 | - Simple neural network with one hidden layer 21 | - Multinomial Logistic Regression 22 | - Decision tree for classification 23 | - Reinforcement learning (e.g. Q-learning with a linear neural network) 24 | - Support Vector Machine 25 | 26 | ## Feedback 27 | 28 | If you have a favorite algorithm that should be included or spot a mistake, please let me know by creating a new issue. 29 | 30 | ## License 31 | 32 | See the LICENSE file for license rights and limitations (MIT). 33 | -------------------------------------------------------------------------------- /datasets/boston.csv: -------------------------------------------------------------------------------- 1 | ID,crim,zn,indus,chas,nox,rm,age,dis,rad,tax,ptratio,black,lstat,medv 2 | 1,0.00632,18,2.31,0,0.538,6.575,65.2,4.09,1,296,15.3,396.9,4.98,24 3 | 2,0.02731,0,7.07,0,0.469,6.421,78.9,4.9671,2,242,17.8,396.9,9.14,21.6 4 | 4,0.03237,0,2.18,0,0.458,6.998,45.8,6.0622,3,222,18.7,394.63,2.94,33.4 5 | 5,0.06905,0,2.18,0,0.458,7.147,54.2,6.0622,3,222,18.7,396.9,5.33,36.2 6 | 7,0.08829,12.5,7.87,0,0.524,6.012,66.6,5.5605,5,311,15.2,395.6,12.43,22.9 7 | 11,0.22489,12.5,7.87,0,0.524,6.377,94.3,6.3467,5,311,15.2,392.52,20.45,15 8 | 12,0.11747,12.5,7.87,0,0.524,6.009,82.9,6.2267,5,311,15.2,396.9,13.27,18.9 9 | 13,0.09378,12.5,7.87,0,0.524,5.889,39,5.4509,5,311,15.2,390.5,15.71,21.7 10 | 14,0.62976,0,8.14,0,0.538,5.949,61.8,4.7075,4,307,21,396.9,8.26,20.4 11 | 15,0.63796,0,8.14,0,0.538,6.096,84.5,4.4619,4,307,21,380.02,10.26,18.2 12 | 16,0.62739,0,8.14,0,0.538,5.834,56.5,4.4986,4,307,21,395.62,8.47,19.9 13 | 17,1.05393,0,8.14,0,0.538,5.935,29.3,4.4986,4,307,21,386.85,6.58,23.1 14 | 19,0.80271,0,8.14,0,0.538,5.456,36.6,3.7965,4,307,21,288.99,11.69,20.2 15 | 21,1.25179,0,8.14,0,0.538,5.57,98.1,3.7979,4,307,21,376.57,21.02,13.6 16 | 22,0.85204,0,8.14,0,0.538,5.965,89.2,4.0123,4,307,21,392.53,13.83,19.6 17 | 23,1.23247,0,8.14,0,0.538,6.142,91.7,3.9769,4,307,21,396.9,18.72,15.2 18 | 24,0.98843,0,8.14,0,0.538,5.813,100,4.0952,4,307,21,394.54,19.88,14.5 19 | 28,0.95577,0,8.14,0,0.538,6.047,88.8,4.4534,4,307,21,306.38,17.28,14.8 20 | 31,1.13081,0,8.14,0,0.538,5.713,94.1,4.233,4,307,21,360.17,22.6,12.7 21 | 32,1.35472,0,8.14,0,0.538,6.072,100,4.175,4,307,21,376.73,13.04,14.5 22 | 35,1.61282,0,8.14,0,0.538,6.096,96.9,3.7598,4,307,21,248.31,20.34,13.5 23 | 39,0.17505,0,5.96,0,0.499,5.966,30.2,3.8473,5,279,19.2,393.43,10.13,24.7 24 | 40,0.02763,75,2.95,0,0.428,6.595,21.8,5.4011,3,252,18.3,395.63,4.32,30.8 25 | 41,0.03359,75,2.95,0,0.428,7.024,15.8,5.4011,3,252,18.3,395.62,1.98,34.9 26 | 43,0.1415,0,6.91,0,0.448,6.169,6.6,5.7209,3,233,17.9,383.37,5.81,25.3 27 | 44,0.15936,0,6.91,0,0.448,6.211,6.5,5.7209,3,233,17.9,394.46,7.44,24.7 28 | 45,0.12269,0,6.91,0,0.448,6.069,40,5.7209,3,233,17.9,389.39,9.55,21.2 29 | 46,0.17142,0,6.91,0,0.448,5.682,33.8,5.1004,3,233,17.9,396.9,10.21,19.3 30 | 47,0.18836,0,6.91,0,0.448,5.786,33.3,5.1004,3,233,17.9,396.9,14.15,20 31 | 48,0.22927,0,6.91,0,0.448,6.03,85.5,5.6894,3,233,17.9,392.74,18.8,16.6 32 | 50,0.21977,0,6.91,0,0.448,5.602,62,6.0877,3,233,17.9,396.9,16.2,19.4 33 | 51,0.08873,21,5.64,0,0.439,5.963,45.7,6.8147,4,243,16.8,395.56,13.45,19.7 34 | 52,0.04337,21,5.64,0,0.439,6.115,63,6.8147,4,243,16.8,393.97,9.43,20.5 35 | 54,0.04981,21,5.64,0,0.439,5.998,21.4,6.8147,4,243,16.8,396.9,8.43,23.4 36 | 55,0.0136,75,4,0,0.41,5.888,47.6,7.3197,3,469,21.1,396.9,14.8,18.9 37 | 56,0.01311,90,1.22,0,0.403,7.249,21.9,8.6966,5,226,17.9,395.93,4.81,35.4 38 | 57,0.02055,85,0.74,0,0.41,6.383,35.7,9.1876,2,313,17.3,396.9,5.77,24.7 39 | 58,0.01432,100,1.32,0,0.411,6.816,40.5,8.3248,5,256,15.1,392.9,3.95,31.6 40 | 59,0.15445,25,5.13,0,0.453,6.145,29.2,7.8148,8,284,19.7,390.68,6.86,23.3 41 | 61,0.14932,25,5.13,0,0.453,5.741,66.2,7.2254,8,284,19.7,395.11,13.15,18.7 42 | 62,0.17171,25,5.13,0,0.453,5.966,93.4,6.8185,8,284,19.7,378.08,14.44,16 43 | 64,0.1265,25,5.13,0,0.453,6.762,43.4,7.9809,8,284,19.7,395.58,9.5,25 44 | 65,0.01951,17.5,1.38,0,0.4161,7.104,59.5,9.2229,3,216,18.6,393.24,8.05,33 45 | 66,0.03584,80,3.37,0,0.398,6.29,17.8,6.6115,4,337,16.1,396.9,4.67,23.5 46 | 67,0.04379,80,3.37,0,0.398,5.787,31.1,6.6115,4,337,16.1,396.9,10.24,19.4 47 | 68,0.05789,12.5,6.07,0,0.409,5.878,21.4,6.498,4,345,18.9,396.21,8.1,22 48 | 69,0.13554,12.5,6.07,0,0.409,5.594,36.8,6.498,4,345,18.9,396.9,13.09,17.4 49 | 71,0.08826,0,10.81,0,0.413,6.417,6.6,5.2873,4,305,19.2,383.73,6.72,24.2 50 | 73,0.09164,0,10.81,0,0.413,6.065,7.8,5.2873,4,305,19.2,390.91,5.52,22.8 51 | 74,0.19539,0,10.81,0,0.413,6.245,6.2,5.2873,4,305,19.2,377.17,7.54,23.4 52 | 75,0.07896,0,12.83,0,0.437,6.273,6,4.2515,5,398,18.7,394.92,6.78,24.1 53 | 76,0.09512,0,12.83,0,0.437,6.286,45,4.5026,5,398,18.7,383.23,8.94,21.4 54 | 77,0.10153,0,12.83,0,0.437,6.279,74.5,4.0522,5,398,18.7,373.66,11.97,20 55 | 78,0.08707,0,12.83,0,0.437,6.14,45.8,4.0905,5,398,18.7,386.96,10.27,20.8 56 | 81,0.04113,25,4.86,0,0.426,6.727,33.5,5.4007,4,281,19,396.9,5.29,28 57 | 82,0.04462,25,4.86,0,0.426,6.619,70.4,5.4007,4,281,19,395.63,7.22,23.9 58 | 84,0.03551,25,4.86,0,0.426,6.167,46.7,5.4007,4,281,19,390.64,7.51,22.9 59 | 85,0.05059,0,4.49,0,0.449,6.389,48,4.7794,3,247,18.5,396.9,9.62,23.9 60 | 86,0.05735,0,4.49,0,0.449,6.63,56.1,4.4377,3,247,18.5,392.3,6.53,26.6 61 | 87,0.05188,0,4.49,0,0.449,6.015,45.1,4.4272,3,247,18.5,395.99,12.86,22.5 62 | 88,0.07151,0,4.49,0,0.449,6.121,56.8,3.7476,3,247,18.5,395.15,8.44,22.2 63 | 89,0.0566,0,3.41,0,0.489,7.007,86.3,3.4217,2,270,17.8,396.9,5.5,23.6 64 | 90,0.05302,0,3.41,0,0.489,7.079,63.1,3.4145,2,270,17.8,396.06,5.7,28.7 65 | 91,0.04684,0,3.41,0,0.489,6.417,66.1,3.0923,2,270,17.8,392.18,8.81,22.6 66 | 94,0.02875,28,15.04,0,0.464,6.211,28.9,3.6659,4,270,18.2,396.33,6.21,25 67 | 95,0.04294,28,15.04,0,0.464,6.249,77.3,3.615,4,270,18.2,396.9,10.59,20.6 68 | 97,0.11504,0,2.89,0,0.445,6.163,69.6,3.4952,2,276,18,391.83,11.34,21.4 69 | 101,0.14866,0,8.56,0,0.52,6.727,79.9,2.7778,5,384,20.9,394.76,9.42,27.5 70 | 102,0.11432,0,8.56,0,0.52,6.781,71.3,2.8561,5,384,20.9,395.58,7.67,26.5 71 | 103,0.22876,0,8.56,0,0.52,6.405,85.4,2.7147,5,384,20.9,70.8,10.63,18.6 72 | 104,0.21161,0,8.56,0,0.52,6.137,87.4,2.7147,5,384,20.9,394.47,13.44,19.3 73 | 107,0.1712,0,8.56,0,0.52,5.836,91.9,2.211,5,384,20.9,395.67,18.66,19.5 74 | 108,0.13117,0,8.56,0,0.52,6.127,85.2,2.1224,5,384,20.9,387.69,14.09,20.4 75 | 109,0.12802,0,8.56,0,0.52,6.474,97.1,2.4329,5,384,20.9,395.24,12.27,19.8 76 | 110,0.26363,0,8.56,0,0.52,6.229,91.2,2.5451,5,384,20.9,391.23,15.55,19.4 77 | 112,0.10084,0,10.01,0,0.547,6.715,81.6,2.6775,6,432,17.8,395.59,10.16,22.8 78 | 115,0.14231,0,10.01,0,0.547,6.254,84.2,2.2565,6,432,17.8,388.74,10.45,18.5 79 | 117,0.13158,0,10.01,0,0.547,6.176,72.5,2.7301,6,432,17.8,393.3,12.04,21.2 80 | 118,0.15098,0,10.01,0,0.547,6.021,82.6,2.7474,6,432,17.8,394.51,10.3,19.2 81 | 119,0.13058,0,10.01,0,0.547,5.872,73.1,2.4775,6,432,17.8,338.63,15.37,20.4 82 | 120,0.14476,0,10.01,0,0.547,5.731,65.2,2.7592,6,432,17.8,391.5,13.61,19.3 83 | 121,0.06899,0,25.65,0,0.581,5.87,69.7,2.2577,2,188,19.1,389.15,14.37,22 84 | 122,0.07165,0,25.65,0,0.581,6.004,84.1,2.1974,2,188,19.1,377.67,14.27,20.3 85 | 123,0.09299,0,25.65,0,0.581,5.961,92.9,2.0869,2,188,19.1,378.09,17.93,20.5 86 | 124,0.15038,0,25.65,0,0.581,5.856,97,1.9444,2,188,19.1,370.31,25.41,17.3 87 | 125,0.09849,0,25.65,0,0.581,5.879,95.8,2.0063,2,188,19.1,379.38,17.58,18.8 88 | 127,0.38735,0,25.65,0,0.581,5.613,95.6,1.7572,2,188,19.1,359.29,27.26,15.7 89 | 128,0.25915,0,21.89,0,0.624,5.693,96,1.7883,4,437,21.2,392.11,17.19,16.2 90 | 129,0.32543,0,21.89,0,0.624,6.431,98.8,1.8125,4,437,21.2,396.9,15.39,18 91 | 132,1.19294,0,21.89,0,0.624,6.326,97.7,2.271,4,437,21.2,396.9,12.26,19.6 92 | 134,0.32982,0,21.89,0,0.624,5.822,95.4,2.4699,4,437,21.2,388.69,15.03,18.4 93 | 135,0.97617,0,21.89,0,0.624,5.757,98.4,2.346,4,437,21.2,262.76,17.31,15.6 94 | 137,0.32264,0,21.89,0,0.624,5.942,93.5,1.9669,4,437,21.2,378.25,16.9,17.4 95 | 138,0.35233,0,21.89,0,0.624,6.454,98.4,1.8498,4,437,21.2,394.08,14.59,17.1 96 | 139,0.2498,0,21.89,0,0.624,5.857,98.2,1.6686,4,437,21.2,392.04,21.32,13.3 97 | 140,0.54452,0,21.89,0,0.624,6.151,97.9,1.6687,4,437,21.2,396.9,18.46,17.8 98 | 142,1.62864,0,21.89,0,0.624,5.019,100,1.4394,4,437,21.2,396.9,34.41,14.4 99 | 143,3.32105,0,19.58,1,0.871,5.403,100,1.3216,5,403,14.7,396.9,26.82,13.4 100 | 146,2.37934,0,19.58,0,0.871,6.13,100,1.4191,5,403,14.7,172.91,27.8,13.8 101 | 148,2.36862,0,19.58,0,0.871,4.926,95.7,1.4608,5,403,14.7,391.71,29.53,14.6 102 | 149,2.33099,0,19.58,0,0.871,5.186,93.8,1.5296,5,403,14.7,356.99,28.32,17.8 103 | 150,2.73397,0,19.58,0,0.871,5.597,94.9,1.5257,5,403,14.7,351.85,21.45,15.4 104 | 151,1.6566,0,19.58,0,0.871,6.122,97.3,1.618,5,403,14.7,372.8,14.1,21.5 105 | 154,2.14918,0,19.58,0,0.871,5.709,98.5,1.6232,5,403,14.7,261.95,15.79,19.4 106 | 155,1.41385,0,19.58,1,0.871,6.129,96,1.7494,5,403,14.7,321.02,15.12,17 107 | 157,2.44668,0,19.58,0,0.871,5.272,94,1.7364,5,403,14.7,88.63,16.14,13.1 108 | 159,1.34284,0,19.58,0,0.605,6.066,100,1.7573,5,403,14.7,353.89,6.43,24.3 109 | 160,1.42502,0,19.58,0,0.871,6.51,100,1.7659,5,403,14.7,364.31,7.39,23.3 110 | 161,1.27346,0,19.58,1,0.605,6.25,92.6,1.7984,5,403,14.7,338.92,5.5,27 111 | 162,1.46336,0,19.58,0,0.605,7.489,90.8,1.9709,5,403,14.7,374.43,1.73,50 112 | 164,1.51902,0,19.58,1,0.605,8.375,93.9,2.162,5,403,14.7,388.45,3.32,50 113 | 165,2.24236,0,19.58,0,0.605,5.854,91.8,2.422,5,403,14.7,395.11,11.64,22.7 114 | 166,2.924,0,19.58,0,0.605,6.101,93,2.2834,5,403,14.7,240.16,9.81,25 115 | 167,2.01019,0,19.58,0,0.605,7.929,96.2,2.0459,5,403,14.7,369.3,3.7,50 116 | 168,1.80028,0,19.58,0,0.605,5.877,79.2,2.4259,5,403,14.7,227.61,12.14,23.8 117 | 170,2.44953,0,19.58,0,0.605,6.402,95.2,2.2625,5,403,14.7,330.04,11.32,22.3 118 | 171,1.20742,0,19.58,0,0.605,5.875,94.6,2.4259,5,403,14.7,292.29,14.43,17.4 119 | 172,2.3139,0,19.58,0,0.605,5.88,97.3,2.3887,5,403,14.7,348.13,12.03,19.1 120 | 173,0.13914,0,4.05,0,0.51,5.572,88.5,2.5961,5,296,16.6,396.9,14.69,23.1 121 | 174,0.09178,0,4.05,0,0.51,6.416,84.1,2.6463,5,296,16.6,395.5,9.04,23.6 122 | 175,0.08447,0,4.05,0,0.51,5.859,68.7,2.7019,5,296,16.6,393.23,9.64,22.6 123 | 176,0.06664,0,4.05,0,0.51,6.546,33.1,3.1323,5,296,16.6,390.96,5.33,29.4 124 | 177,0.07022,0,4.05,0,0.51,6.02,47.2,3.5549,5,296,16.6,393.23,10.11,23.2 125 | 178,0.05425,0,4.05,0,0.51,6.315,73.4,3.3175,5,296,16.6,395.6,6.29,24.6 126 | 179,0.06642,0,4.05,0,0.51,6.86,74.4,2.9153,5,296,16.6,391.27,6.92,29.9 127 | 180,0.0578,0,2.46,0,0.488,6.98,58.4,2.829,3,193,17.8,396.9,5.04,37.2 128 | 181,0.06588,0,2.46,0,0.488,7.765,83.3,2.741,3,193,17.8,395.56,7.56,39.8 129 | 182,0.06888,0,2.46,0,0.488,6.144,62.2,2.5979,3,193,17.8,396.9,9.45,36.2 130 | 183,0.09103,0,2.46,0,0.488,7.155,92.2,2.7006,3,193,17.8,394.12,4.82,37.9 131 | 184,0.10008,0,2.46,0,0.488,6.563,95.6,2.847,3,193,17.8,396.9,5.68,32.5 132 | 187,0.05602,0,2.46,0,0.488,7.831,53.6,3.1992,3,193,17.8,392.63,4.45,50 133 | 188,0.07875,45,3.44,0,0.437,6.782,41.1,3.7886,5,398,15.2,393.87,6.68,32 134 | 190,0.0837,45,3.44,0,0.437,7.185,38.9,4.5667,5,398,15.2,396.9,5.39,34.9 135 | 191,0.09068,45,3.44,0,0.437,6.951,21.5,6.4798,5,398,15.2,377.68,5.1,37 136 | 192,0.06911,45,3.44,0,0.437,6.739,30.8,6.4798,5,398,15.2,389.71,4.69,30.5 137 | 193,0.08664,45,3.44,0,0.437,7.178,26.3,6.4798,5,398,15.2,390.49,2.87,36.4 138 | 194,0.02187,60,2.93,0,0.401,6.8,9.9,6.2196,1,265,15.6,393.37,5.03,31.1 139 | 195,0.01439,60,2.93,0,0.401,6.604,18.8,6.2196,1,265,15.6,376.7,4.38,29.1 140 | 198,0.04666,80,1.52,0,0.404,7.107,36.6,7.309,2,329,12.6,354.31,8.61,30.3 141 | 201,0.01778,95,1.47,0,0.403,7.135,13.9,7.6534,3,402,17,384.3,4.45,32.9 142 | 202,0.03445,82.5,2.03,0,0.415,6.162,38.4,6.27,2,348,14.7,393.77,7.43,24.1 143 | 204,0.0351,95,2.68,0,0.4161,7.853,33.2,5.118,4,224,14.7,392.78,3.81,48.5 144 | 205,0.02009,95,2.68,0,0.4161,8.034,31.9,5.118,4,224,14.7,390.55,2.88,50 145 | 206,0.13642,0,10.59,0,0.489,5.891,22.3,3.9454,4,277,18.6,396.9,10.87,22.6 146 | 207,0.22969,0,10.59,0,0.489,6.326,52.5,4.3549,4,277,18.6,394.87,10.97,24.4 147 | 209,0.13587,0,10.59,1,0.489,6.064,59.1,4.2392,4,277,18.6,381.32,14.66,24.4 148 | 212,0.37578,0,10.59,1,0.489,5.404,88.6,3.665,4,277,18.6,395.24,23.98,19.3 149 | 214,0.14052,0,10.59,0,0.489,6.375,32.3,3.9454,4,277,18.6,385.81,9.38,28.1 150 | 215,0.28955,0,10.59,0,0.489,5.412,9.8,3.5875,4,277,18.6,348.93,29.55,23.7 151 | 217,0.0456,0,13.89,1,0.55,5.888,56,3.1121,5,276,16.4,392.8,13.51,23.3 152 | 222,0.40771,0,6.2,1,0.507,6.164,91.3,3.048,8,307,17.4,395.24,21.46,21.7 153 | 223,0.62356,0,6.2,1,0.507,6.879,77.7,3.2721,8,307,17.4,390.39,9.93,27.5 154 | 224,0.6147,0,6.2,0,0.507,6.618,80.8,3.2721,8,307,17.4,396.9,7.6,30.1 155 | 225,0.31533,0,6.2,0,0.504,8.266,78.3,2.8944,8,307,17.4,385.05,4.14,44.8 156 | 226,0.52693,0,6.2,0,0.504,8.725,83,2.8944,8,307,17.4,382,4.63,50 157 | 227,0.38214,0,6.2,0,0.504,8.04,86.5,3.2157,8,307,17.4,387.38,3.13,37.6 158 | 228,0.41238,0,6.2,0,0.504,7.163,79.9,3.2157,8,307,17.4,372.08,6.36,31.6 159 | 230,0.44178,0,6.2,0,0.504,6.552,21.4,3.3751,8,307,17.4,380.34,3.76,31.5 160 | 231,0.537,0,6.2,0,0.504,5.981,68.1,3.6715,8,307,17.4,378.35,11.65,24.3 161 | 233,0.57529,0,6.2,0,0.507,8.337,73.3,3.8384,8,307,17.4,385.91,2.47,41.7 162 | 234,0.33147,0,6.2,0,0.507,8.247,70.4,3.6519,8,307,17.4,378.95,3.95,48.3 163 | 235,0.44791,0,6.2,1,0.507,6.726,66.5,3.6519,8,307,17.4,360.2,8.05,29 164 | 236,0.33045,0,6.2,0,0.507,6.086,61.5,3.6519,8,307,17.4,376.75,10.88,24 165 | 237,0.52058,0,6.2,1,0.507,6.631,76.5,4.148,8,307,17.4,388.45,9.54,25.1 166 | 241,0.11329,30,4.93,0,0.428,6.897,54.3,6.3361,6,300,16.6,391.25,11.38,22 167 | 243,0.1029,30,4.93,0,0.428,6.358,52.9,7.0355,6,300,16.6,372.75,11.22,22.2 168 | 244,0.12757,30,4.93,0,0.428,6.393,7.8,7.0355,6,300,16.6,374.71,5.19,23.7 169 | 245,0.20608,22,5.86,0,0.431,5.593,76.5,7.9549,7,330,19.1,372.49,12.5,17.6 170 | 247,0.33983,22,5.86,0,0.431,6.108,34.9,8.0555,7,330,19.1,390.18,9.16,24.3 171 | 249,0.16439,22,5.86,0,0.431,6.433,49.1,7.8265,7,330,19.1,374.71,9.52,24.5 172 | 250,0.19073,22,5.86,0,0.431,6.718,17.5,7.8265,7,330,19.1,393.74,6.56,26.2 173 | 251,0.1403,22,5.86,0,0.431,6.487,13,7.3967,7,330,19.1,396.28,5.9,24.4 174 | 252,0.21409,22,5.86,0,0.431,6.438,8.9,7.3967,7,330,19.1,377.07,3.59,24.8 175 | 254,0.36894,22,5.86,0,0.431,8.259,8.4,8.9067,7,330,19.1,396.9,3.54,42.8 176 | 261,0.54011,20,3.97,0,0.647,7.203,81.8,2.1121,5,264,13,392.8,9.59,33.8 177 | 262,0.53412,20,3.97,0,0.647,7.52,89.4,2.1398,5,264,13,388.37,7.26,43.1 178 | 263,0.52014,20,3.97,0,0.647,8.398,91.5,2.2885,5,264,13,386.86,5.91,48.8 179 | 264,0.82526,20,3.97,0,0.647,7.327,94.5,2.0788,5,264,13,393.42,11.25,31 180 | 265,0.55007,20,3.97,0,0.647,7.206,91.6,1.9301,5,264,13,387.89,8.1,36.5 181 | 266,0.76162,20,3.97,0,0.647,5.56,62.8,1.9865,5,264,13,392.4,10.45,22.8 182 | 267,0.7857,20,3.97,0,0.647,7.014,84.6,2.1329,5,264,13,384.07,14.79,30.7 183 | 269,0.5405,20,3.97,0,0.575,7.47,52.6,2.872,5,264,13,390.3,3.16,43.5 184 | 272,0.16211,20,6.96,0,0.464,6.24,16.3,4.429,3,223,18.6,396.9,6.59,25.2 185 | 273,0.1146,20,6.96,0,0.464,6.538,58.7,3.9175,3,223,18.6,394.96,7.73,24.4 186 | 274,0.22188,20,6.96,1,0.464,7.691,51.8,4.3665,3,223,18.6,390.77,6.58,35.2 187 | 275,0.05644,40,6.41,1,0.447,6.758,32.9,4.0776,4,254,17.6,396.9,3.53,32.4 188 | 280,0.21038,20,3.33,0,0.4429,6.812,32.2,4.1007,5,216,14.9,396.9,4.85,35.1 189 | 282,0.03705,20,3.33,0,0.4429,6.968,37.2,5.2447,5,216,14.9,392.23,4.59,35.4 190 | 283,0.06129,20,3.33,1,0.4429,7.645,49.7,5.2119,5,216,14.9,377.07,3.01,46 191 | 284,0.01501,90,1.21,1,0.401,7.923,24.8,5.885,1,198,13.6,395.52,3.16,50 192 | 285,0.00906,90,2.97,0,0.4,7.088,20.8,7.3073,1,285,15.3,394.72,7.85,32.2 193 | 286,0.01096,55,2.25,0,0.389,6.453,31.9,7.3073,1,300,15.3,394.72,8.23,22 194 | 287,0.01965,80,1.76,0,0.385,6.23,31.5,9.0892,1,241,18.2,341.6,12.93,20.1 195 | 289,0.0459,52.5,5.32,0,0.405,6.315,45.6,7.3172,6,293,16.6,396.9,7.6,22.3 196 | 291,0.03502,80,4.95,0,0.411,6.861,27.9,5.1167,4,245,19.2,396.9,3.33,28.5 197 | 293,0.03615,80,4.95,0,0.411,6.63,23.4,5.1167,4,245,19.2,396.9,4.7,27.9 198 | 294,0.08265,0,13.92,0,0.437,6.127,18.4,5.5027,4,289,16,396.9,8.58,23.9 199 | 297,0.05372,0,13.92,0,0.437,6.549,51,5.9604,4,289,16,392.85,7.39,27.1 200 | 298,0.14103,0,13.92,0,0.437,5.79,58,6.32,4,289,16,396.9,15.84,20.3 201 | 302,0.03537,34,6.09,0,0.433,6.59,40.4,5.4917,7,329,16.1,395.75,9.5,22 202 | 303,0.09266,34,6.09,0,0.433,6.495,18.4,5.4917,7,329,16.1,383.61,8.67,26.4 203 | 304,0.1,34,6.09,0,0.433,6.982,17.7,5.4917,7,329,16.1,390.43,4.86,33.1 204 | 305,0.05515,33,2.18,0,0.472,7.236,41.1,4.022,7,222,18.4,393.68,6.93,36.1 205 | 306,0.05479,33,2.18,0,0.472,6.616,58.1,3.37,7,222,18.4,393.36,8.93,28.4 206 | 307,0.07503,33,2.18,0,0.472,7.42,71.9,3.0992,7,222,18.4,396.9,6.47,33.4 207 | 309,0.49298,0,9.9,0,0.544,6.635,82.5,3.3175,4,304,18.4,396.9,4.54,22.8 208 | 310,0.3494,0,9.9,0,0.544,5.972,76.7,3.1025,4,304,18.4,396.24,9.97,20.3 209 | 311,2.63548,0,9.9,0,0.544,4.973,37.8,2.5194,4,304,18.4,350.45,12.64,16.1 210 | 312,0.79041,0,9.9,0,0.544,6.122,52.8,2.6403,4,304,18.4,396.9,5.98,22.1 211 | 313,0.26169,0,9.9,0,0.544,6.023,90.4,2.834,4,304,18.4,396.3,11.72,19.4 212 | 316,0.25356,0,9.9,0,0.544,5.705,77.7,3.945,4,304,18.4,396.42,11.5,16.2 213 | 317,0.31827,0,9.9,0,0.544,5.914,83.2,3.9986,4,304,18.4,390.7,18.33,17.8 214 | 318,0.24522,0,9.9,0,0.544,5.782,71.7,4.0317,4,304,18.4,396.9,15.94,19.8 215 | 319,0.40202,0,9.9,0,0.544,6.382,67.2,3.5325,4,304,18.4,395.21,10.36,23.1 216 | 321,0.1676,0,7.38,0,0.493,6.426,52.3,4.5404,5,287,19.6,396.9,7.2,23.8 217 | 325,0.34109,0,7.38,0,0.493,6.415,40.1,4.7211,5,287,19.6,396.9,6.12,25 218 | 326,0.19186,0,7.38,0,0.493,6.431,14.7,5.4159,5,287,19.6,393.68,5.08,24.6 219 | 328,0.24103,0,7.38,0,0.493,6.083,43.7,5.4159,5,287,19.6,396.9,12.79,22.2 220 | 329,0.06617,0,3.24,0,0.46,5.868,25.8,5.2146,4,430,16.9,382.44,9.97,19.3 221 | 331,0.04544,0,3.24,0,0.46,6.144,32.2,5.8736,4,430,16.9,368.57,9.09,19.8 222 | 334,0.05083,0,5.19,0,0.515,6.316,38.1,6.4584,5,224,20.2,389.71,5.68,22.2 223 | 335,0.03738,0,5.19,0,0.515,6.31,38.5,6.4584,5,224,20.2,389.4,6.75,20.7 224 | 337,0.03427,0,5.19,0,0.515,5.869,46.3,5.2311,5,224,20.2,396.9,9.8,19.5 225 | 339,0.03306,0,5.19,0,0.515,6.059,37.3,4.8122,5,224,20.2,396.14,8.51,20.6 226 | 340,0.05497,0,5.19,0,0.515,5.985,45.4,4.8122,5,224,20.2,396.9,9.74,19 227 | 341,0.06151,0,5.19,0,0.515,5.968,58.5,4.8122,5,224,20.2,396.9,9.29,18.7 228 | 342,0.01301,35,1.52,0,0.442,7.241,49.3,7.0379,1,284,15.5,394.74,5.49,32.7 229 | 343,0.02498,0,1.89,0,0.518,6.54,59.7,6.2669,1,422,15.9,389.96,8.65,16.5 230 | 344,0.02543,55,3.78,0,0.484,6.696,56.4,5.7321,5,370,17.6,396.9,7.18,23.9 231 | 345,0.03049,55,3.78,0,0.484,6.874,28.1,6.4654,5,370,17.6,387.97,4.61,31.2 232 | 348,0.0187,85,4.15,0,0.429,6.516,27.7,8.5353,4,351,17.9,392.43,6.36,23.1 233 | 349,0.01501,80,2.01,0,0.435,6.635,29.7,8.344,4,280,17,390.94,5.99,24.5 234 | 350,0.02899,40,1.25,0,0.429,6.939,34.5,8.7921,1,335,19.7,389.85,5.89,26.6 235 | 353,0.07244,60,1.69,0,0.411,5.884,18.5,10.7103,4,411,18.3,392.33,7.79,18.6 236 | 357,8.98296,0,18.1,1,0.77,6.212,97.4,2.1222,24,666,20.2,377.73,17.6,17.8 237 | 358,3.8497,0,18.1,1,0.77,6.395,91,2.5052,24,666,20.2,391.34,13.27,21.7 238 | 359,5.20177,0,18.1,1,0.77,6.127,83.4,2.7227,24,666,20.2,395.43,11.48,22.7 239 | 360,4.26131,0,18.1,0,0.77,6.112,81.3,2.5091,24,666,20.2,390.74,12.67,22.6 240 | 361,4.54192,0,18.1,0,0.77,6.398,88,2.5182,24,666,20.2,374.56,7.79,25 241 | 363,3.67822,0,18.1,0,0.77,5.362,96.2,2.1036,24,666,20.2,380.79,10.19,20.8 242 | 366,4.55587,0,18.1,0,0.718,3.561,87.9,1.6132,24,666,20.2,354.7,7.12,27.5 243 | 367,3.69695,0,18.1,0,0.718,4.963,91.4,1.7523,24,666,20.2,316.03,14,21.9 244 | 368,13.5222,0,18.1,0,0.631,3.863,100,1.5106,24,666,20.2,131.42,13.33,23.1 245 | 369,4.89822,0,18.1,0,0.631,4.97,100,1.3325,24,666,20.2,375.52,3.26,50 246 | 371,6.53876,0,18.1,1,0.631,7.016,97.5,1.2024,24,666,20.2,392.05,2.96,50 247 | 372,9.2323,0,18.1,0,0.631,6.216,100,1.1691,24,666,20.2,366.15,9.53,50 248 | 373,8.26725,0,18.1,1,0.668,5.875,89.6,1.1296,24,666,20.2,347.88,8.88,50 249 | 374,11.1081,0,18.1,0,0.668,4.906,100,1.1742,24,666,20.2,396.9,34.77,13.8 250 | 375,18.4982,0,18.1,0,0.668,4.138,100,1.137,24,666,20.2,396.9,37.97,13.8 251 | 377,15.288,0,18.1,0,0.671,6.649,93.3,1.3449,24,666,20.2,363.02,23.24,13.9 252 | 378,9.82349,0,18.1,0,0.671,6.794,98.8,1.358,24,666,20.2,396.9,21.24,13.3 253 | 383,9.18702,0,18.1,0,0.7,5.536,100,1.5804,24,666,20.2,396.9,23.6,11.3 254 | 384,7.99248,0,18.1,0,0.7,5.52,100,1.5331,24,666,20.2,396.9,24.56,12.3 255 | 385,20.0849,0,18.1,0,0.7,4.368,91.2,1.4395,24,666,20.2,285.83,30.63,8.8 256 | 387,24.3938,0,18.1,0,0.7,4.652,100,1.4672,24,666,20.2,396.9,28.28,10.5 257 | 388,22.5971,0,18.1,0,0.7,5,89.5,1.5184,24,666,20.2,396.9,31.99,7.4 258 | 390,8.15174,0,18.1,0,0.7,5.39,98.9,1.7281,24,666,20.2,396.9,20.85,11.5 259 | 392,5.29305,0,18.1,0,0.7,6.051,82.5,2.1678,24,666,20.2,378.38,18.76,23.2 260 | 393,11.5779,0,18.1,0,0.7,5.036,97,1.77,24,666,20.2,396.9,25.68,9.7 261 | 395,13.3598,0,18.1,0,0.693,5.887,94.7,1.7821,24,666,20.2,396.9,16.35,12.7 262 | 397,5.87205,0,18.1,0,0.693,6.405,96,1.6768,24,666,20.2,396.9,19.37,12.5 263 | 399,38.3518,0,18.1,0,0.693,5.453,100,1.4896,24,666,20.2,396.9,30.59,5 264 | 401,25.0461,0,18.1,0,0.693,5.987,100,1.5888,24,666,20.2,396.9,26.77,5.6 265 | 402,14.2362,0,18.1,0,0.693,6.343,100,1.5741,24,666,20.2,396.9,20.32,7.2 266 | 404,24.8017,0,18.1,0,0.693,5.349,96,1.7028,24,666,20.2,396.9,19.77,8.3 267 | 408,11.9511,0,18.1,0,0.659,5.608,100,1.2852,24,666,20.2,332.09,12.13,27.9 268 | 409,7.40389,0,18.1,0,0.597,5.617,97.9,1.4547,24,666,20.2,314.64,26.4,17.2 269 | 414,28.6558,0,18.1,0,0.597,5.155,100,1.5894,24,666,20.2,210.97,20.08,16.3 270 | 415,45.7461,0,18.1,0,0.693,4.519,100,1.6582,24,666,20.2,88.27,36.98,7 271 | 416,18.0846,0,18.1,0,0.679,6.434,100,1.8347,24,666,20.2,27.25,29.05,7.2 272 | 418,25.9406,0,18.1,0,0.679,5.304,89.1,1.6475,24,666,20.2,127.36,26.64,10.4 273 | 419,73.5341,0,18.1,0,0.679,5.957,100,1.8026,24,666,20.2,16.45,20.62,8.8 274 | 420,11.8123,0,18.1,0,0.718,6.824,76.5,1.794,24,666,20.2,48.45,22.74,8.4 275 | 425,8.79212,0,18.1,0,0.584,5.565,70.6,2.0635,24,666,20.2,3.65,17.16,11.7 276 | 426,15.8603,0,18.1,0,0.679,5.896,95.4,1.9096,24,666,20.2,7.68,24.39,8.3 277 | 428,37.6619,0,18.1,0,0.679,6.202,78.7,1.8629,24,666,20.2,18.82,14.52,10.9 278 | 429,7.36711,0,18.1,0,0.679,6.193,78.1,1.9356,24,666,20.2,96.73,21.52,11 279 | 430,9.33889,0,18.1,0,0.679,6.38,95.6,1.9682,24,666,20.2,60.72,24.08,9.5 280 | 432,10.0623,0,18.1,0,0.584,6.833,94.3,2.0882,24,666,20.2,81.33,19.69,14.1 281 | 433,6.44405,0,18.1,0,0.584,6.425,74.8,2.2004,24,666,20.2,97.95,12.03,16.1 282 | 434,5.58107,0,18.1,0,0.713,6.436,87.9,2.3158,24,666,20.2,100.19,16.22,14.3 283 | 435,13.9134,0,18.1,0,0.713,6.208,95,2.2222,24,666,20.2,100.63,15.17,11.7 284 | 438,15.1772,0,18.1,0,0.74,6.152,100,1.9142,24,666,20.2,9.32,26.45,8.7 285 | 440,9.39063,0,18.1,0,0.74,5.627,93.9,1.8172,24,666,20.2,396.9,22.88,12.8 286 | 441,22.0511,0,18.1,0,0.74,5.818,92.4,1.8662,24,666,20.2,391.45,22.11,10.5 287 | 442,9.72418,0,18.1,0,0.74,6.406,97.2,2.0651,24,666,20.2,385.96,19.52,17.1 288 | 443,5.66637,0,18.1,0,0.74,6.219,100,2.0048,24,666,20.2,395.69,16.59,18.4 289 | 444,9.96654,0,18.1,0,0.74,6.485,100,1.9784,24,666,20.2,386.73,18.85,15.4 290 | 445,12.8023,0,18.1,0,0.74,5.854,96.6,1.8956,24,666,20.2,240.52,23.79,10.8 291 | 446,10.6718,0,18.1,0,0.74,6.459,94.8,1.9879,24,666,20.2,43.06,23.98,11.8 292 | 448,9.92485,0,18.1,0,0.74,6.251,96.6,2.198,24,666,20.2,388.52,16.44,12.6 293 | 449,9.32909,0,18.1,0,0.713,6.185,98.7,2.2616,24,666,20.2,396.9,18.13,14.1 294 | 452,5.44114,0,18.1,0,0.713,6.655,98.2,2.3552,24,666,20.2,355.29,17.73,15.2 295 | 453,5.09017,0,18.1,0,0.713,6.297,91.8,2.3682,24,666,20.2,385.09,17.27,16.1 296 | 454,8.24809,0,18.1,0,0.713,7.393,99.3,2.4527,24,666,20.2,375.87,16.74,17.8 297 | 456,4.75237,0,18.1,0,0.713,6.525,86.5,2.4358,24,666,20.2,50.92,18.13,14.1 298 | 458,8.20058,0,18.1,0,0.713,5.936,80.3,2.7792,24,666,20.2,3.5,16.94,13.5 299 | 459,7.75223,0,18.1,0,0.713,6.301,83.7,2.7831,24,666,20.2,272.21,16.23,14.9 300 | 460,6.80117,0,18.1,0,0.713,6.081,84.4,2.7175,24,666,20.2,396.9,14.7,20 301 | 461,4.81213,0,18.1,0,0.713,6.701,90,2.5975,24,666,20.2,255.23,16.42,16.4 302 | 462,3.69311,0,18.1,0,0.713,6.376,88.4,2.5671,24,666,20.2,391.43,14.65,17.7 303 | 463,6.65492,0,18.1,0,0.713,6.317,83,2.7344,24,666,20.2,396.9,13.99,19.5 304 | 464,5.82115,0,18.1,0,0.713,6.513,89.9,2.8016,24,666,20.2,393.82,10.29,20.2 305 | 465,7.83932,0,18.1,0,0.655,6.209,65.4,2.9634,24,666,20.2,396.9,13.22,21.4 306 | 466,3.1636,0,18.1,0,0.655,5.759,48.2,3.0665,24,666,20.2,334.4,14.13,19.9 307 | 467,3.77498,0,18.1,0,0.655,5.952,84.7,2.8715,24,666,20.2,22.01,17.15,19 308 | 468,4.42228,0,18.1,0,0.584,6.003,94.5,2.5403,24,666,20.2,331.29,21.32,19.1 309 | 469,15.5757,0,18.1,0,0.58,5.926,71,2.9084,24,666,20.2,368.74,18.13,19.1 310 | 470,13.0751,0,18.1,0,0.58,5.713,56.7,2.8237,24,666,20.2,396.9,14.76,20.1 311 | 472,4.03841,0,18.1,0,0.532,6.229,90.7,3.0993,24,666,20.2,395.33,12.87,19.6 312 | 473,3.56868,0,18.1,0,0.58,6.437,75,2.8965,24,666,20.2,393.37,14.36,23.2 313 | 475,8.05579,0,18.1,0,0.584,5.427,95.4,2.4298,24,666,20.2,352.58,18.14,13.8 314 | 477,4.87141,0,18.1,0,0.614,6.484,93.6,2.3053,24,666,20.2,396.21,18.68,16.7 315 | 478,15.0234,0,18.1,0,0.614,5.304,97.3,2.1007,24,666,20.2,349.48,24.91,12 316 | 479,10.233,0,18.1,0,0.614,6.185,96.7,2.1705,24,666,20.2,379.7,18.03,14.6 317 | 480,14.3337,0,18.1,0,0.614,6.229,88,1.9512,24,666,20.2,383.32,13.11,21.4 318 | 481,5.82401,0,18.1,0,0.532,6.242,64.7,3.4242,24,666,20.2,396.9,10.74,23 319 | 482,5.70818,0,18.1,0,0.532,6.75,74.9,3.3317,24,666,20.2,393.07,7.74,23.7 320 | 484,2.81838,0,18.1,0,0.532,5.762,40.3,4.0983,24,666,20.2,392.92,10.42,21.8 321 | 485,2.37857,0,18.1,0,0.583,5.871,41.9,3.724,24,666,20.2,370.73,13.34,20.6 322 | 487,5.69175,0,18.1,0,0.583,6.114,79.8,3.5459,24,666,20.2,392.68,14.98,19.1 323 | 488,4.83567,0,18.1,0,0.583,5.905,53.2,3.1523,24,666,20.2,388.22,11.45,20.6 324 | 489,0.15086,0,27.74,0,0.609,5.454,92.7,1.8209,4,711,20.1,395.09,18.06,15.2 325 | 491,0.20746,0,27.74,0,0.609,5.093,98,1.8226,4,711,20.1,318.43,29.68,8.1 326 | 492,0.10574,0,27.74,0,0.609,5.983,98.8,1.8681,4,711,20.1,390.11,18.07,13.6 327 | 493,0.11132,0,27.74,0,0.609,5.983,83.5,2.1099,4,711,20.1,396.9,13.35,20.1 328 | 494,0.17331,0,9.69,0,0.585,5.707,54,2.3817,6,391,19.2,396.9,12.01,21.8 329 | 498,0.26838,0,9.69,0,0.585,5.794,70.6,2.8927,6,391,19.2,396.9,14.1,18.3 330 | 500,0.17783,0,9.69,0,0.585,5.569,73.5,2.3999,6,391,19.2,395.77,15.1,17.5 331 | 502,0.06263,0,11.93,0,0.573,6.593,69.1,2.4786,1,273,21,391.99,9.67,22.4 332 | 503,0.04527,0,11.93,0,0.573,6.12,76.7,2.2875,1,273,21,396.9,9.08,20.6 333 | 504,0.06076,0,11.93,0,0.573,6.976,91,2.1675,1,273,21,396.9,5.64,23.9 334 | 506,0.04741,0,11.93,0,0.573,6.03,80.8,2.505,1,273,21,396.9,7.88,11.9 335 | -------------------------------------------------------------------------------- /src/decision_tree_regression.rs: -------------------------------------------------------------------------------- 1 | use super::RngSeed; 2 | use csv; 3 | use ndarray::*; 4 | use ndarray_rand::RandomExt; 5 | use rand::distributions::StandardNormal; 6 | use std::f64; 7 | use utils::{mean, shuffle2, train_test_split}; 8 | 9 | enum TreeNode { 10 | Leaf { 11 | value: f64, 12 | }, 13 | Node { 14 | feature_idx: usize, 15 | threshold: f64, 16 | left: Box, 17 | right: Box, 18 | }, 19 | } 20 | 21 | struct DataSplit { 22 | // x's have 1 sample per row, that is: 23 | // x[sample_idx][feature_idx] = feature_value 24 | x_left: Array2, 25 | // y[sample_idx] = target_value 26 | y_left: Array1, 27 | x_right: Array2, 28 | y_right: Array1, 29 | } 30 | 31 | impl TreeNode { 32 | /// Construct a new decision tree. 33 | /// 'x': features/inputs 34 | /// 'y': targets/outputs to regress 35 | /// 'max_depth': Maximum number of splits from root to leaf node that the tree can grow. 36 | /// Lower values decrease overfitting. 37 | /// 'min_samples': The minimum number of samples left in the data set in 38 | /// order to perform a split. Larger values decrease overfitting. 39 | pub fn new(x: Array2, y: Array1, max_depth: usize, min_samples: usize) -> TreeNode { 40 | assert!(max_depth >= 1); 41 | assert!(min_samples >= 1); 42 | TreeNode::_new(x, y, 1, max_depth, min_samples) 43 | } 44 | 45 | fn _new( 46 | x: Array2, 47 | y: Array1, 48 | depth: usize, 49 | max_depth: usize, 50 | min_samples: usize, 51 | ) -> TreeNode { 52 | let (feature_idx, threshold, dataset) = best_split(x, y); 53 | let (n_left_samples, n_right_samples) = (dataset.x_left.rows(), dataset.x_right.rows()); 54 | let (left_node, right_node) = if depth >= max_depth { 55 | ( 56 | TreeNode::new_terminal(&dataset.y_left), 57 | TreeNode::new_terminal(&dataset.y_right), 58 | ) 59 | } else { 60 | // If there are enough samples remaining in the branch, 61 | // then construct the tree recursively. 62 | let left = if n_left_samples < min_samples { 63 | TreeNode::new_terminal(&dataset.y_left) 64 | } else { 65 | TreeNode::_new( 66 | dataset.x_left, 67 | dataset.y_left, 68 | depth + 1, 69 | max_depth, 70 | min_samples, 71 | ) 72 | }; 73 | let right = if n_right_samples < min_samples { 74 | TreeNode::new_terminal(&dataset.y_right) 75 | } else { 76 | TreeNode::_new( 77 | dataset.x_right, 78 | dataset.y_right, 79 | depth + 1, 80 | max_depth, 81 | min_samples, 82 | ) 83 | }; 84 | (left, right) 85 | }; 86 | // Construct a new tree node. The left node classifies samples that have 87 | // features 'feature_idx' less than the threshold. 88 | TreeNode::Node { 89 | feature_idx, 90 | threshold, 91 | left: Box::new(left_node), 92 | right: Box::new(right_node), 93 | } 94 | } 95 | 96 | fn new_terminal(y: &Array1) -> TreeNode { 97 | TreeNode::Leaf { value: mean(y) } 98 | } 99 | 100 | /// Given a set of features 'example', predict the target value 101 | pub fn predict(&self, example: ArrayView1) -> f64 { 102 | // Recursively traverse the tree downwards until a leaf node is reached. 103 | match self { 104 | TreeNode::Leaf { value } => *value, 105 | TreeNode::Node { 106 | feature_idx, 107 | threshold, 108 | left, 109 | right, 110 | } => { 111 | if example[[*feature_idx]] < *threshold { 112 | left.predict(example) 113 | } else { 114 | right.predict(example) 115 | } 116 | } 117 | } 118 | } 119 | 120 | /// Evaluate decision tree performance on a data set 121 | pub fn test(&self, data_x: Array2, data_y: Array1) { 122 | let n_test = data_y.len(); 123 | let mut mse = 0.0; 124 | for i in 0..n_test { 125 | let result = self.predict(data_x.slice(s![i, ..])); 126 | mse += (data_y[[i]] - result).powf(2.0); 127 | } 128 | mse *= 1.0 / n_test as f64; 129 | println!("{:?}", mse); 130 | } 131 | } 132 | 133 | /// Split the data set into two; the left set containing the entries with the given feature 134 | /// valued less than the threshold, and the right set the entries greater than 135 | /// the threshold. 136 | fn split(x: &Array2, y: &Array1, feature_idx: usize, threshold: f64) -> DataSplit { 137 | let (mut lt, mut gt): (Vec, Vec) = (Vec::new(), Vec::new()); 138 | for (i, row) in x.outer_iter().enumerate() { 139 | if row[[feature_idx]] < threshold { 140 | lt.push(i); 141 | } else { 142 | gt.push(i); 143 | } 144 | } 145 | DataSplit { 146 | x_left: x.select(Axis(0), <), 147 | y_left: y.select(Axis(0), <), 148 | x_right: x.select(Axis(0), >), 149 | y_right: y.select(Axis(0), >), 150 | } 151 | } 152 | 153 | /// Find the best feature and feature threshold to split on. 154 | fn best_split(x: Array2, y: Array1) -> (usize, f64, DataSplit) { 155 | let mut best_feature_idx = 0; 156 | let mut best_threshold = x[[0, 0]]; 157 | let mut best_dataset = split(&x, &y, best_feature_idx, best_threshold); 158 | let mut best_cost = f64::MAX; 159 | let rs = x.rows(); 160 | for feature_idx in 0..x.cols() { 161 | for sample_idx in 0..rs { 162 | let threshold = x[[sample_idx, feature_idx]]; 163 | let dataset = split(&x, &y, feature_idx, threshold); 164 | let cost = get_cost(&dataset.y_left, &dataset.y_right); 165 | if cost < best_cost { 166 | best_feature_idx = feature_idx; 167 | best_threshold = threshold; 168 | best_dataset = dataset; 169 | best_cost = cost; 170 | } 171 | } 172 | } 173 | (best_feature_idx, best_threshold, best_dataset) 174 | } 175 | 176 | /// The Mean Squared Error for a given split, pretending that each node after the split 177 | /// is a terminal node. The MSE for each subbranch is 178 | /// normalized by how many samples end up in the branch and then added together. 179 | fn get_cost(y_left: &Array1, y_right: &Array1) -> f64 { 180 | // The MSE on the given targets (which are from the training data set), 181 | // assuming the node is a terminal node 182 | fn mse(y: &Array1, n: usize) -> f64 { 183 | let inv = 1.0 / n as f64; 184 | let y_hat = inv * y.scalar_sum(); 185 | inv * (y - y_hat).mapv(|e| e.powf(2.0)).scalar_sum() 186 | } 187 | let (n_left, n_right) = (y_left.len(), y_right.len()); 188 | let mse_left = if n_left > 0 { mse(y_left, n_left) } else { 0.0 }; 189 | let mse_right = if n_right > 0 { 190 | mse(y_right, n_right) 191 | } else { 192 | 0.0 193 | }; 194 | let (n_left, n_right) = (n_left as f64, n_right as f64); 195 | let n_total = n_left + n_right; 196 | (n_left / n_total) * mse_left + (n_right / n_total) * mse_right 197 | } 198 | 199 | /// Load the Boston Housing data set from file, 200 | /// build the decision tree with the given parameters 201 | /// and test how the decision tree performs. 202 | /// TODO load boston into python original; compare results 203 | pub fn run( 204 | max_depth: usize, 205 | min_samples: usize, 206 | train_test_split_ratio: f64, 207 | rng_seed: Option, 208 | ) { 209 | let file_path = "datasets/boston.csv"; 210 | let mut rdr = csv::Reader::from_path(file_path).unwrap(); 211 | let n_samples = 333; // rdr.records().count(); 212 | let n_features = rdr.headers().unwrap().len() - 1; 213 | let mut data_x: Array2 = Array::zeros((n_samples, n_features + 1)); 214 | let mut data_y: Array1 = Array::zeros(n_samples); 215 | for (i, result) in rdr.records().enumerate() { 216 | let r = result.unwrap(); 217 | let y: f64 = r.get(n_features).expect("idx").parse().expect("parse"); 218 | data_y[[i]] = y; 219 | let x: Array1 = r.into_iter() 220 | .take(n_features) 221 | .map(|e| e.parse().unwrap()) 222 | .collect(); 223 | data_x.slice_mut(s![i, ..-1]).assign(&x); 224 | } 225 | let (data_x, data_y) = shuffle2(data_x, data_y, rng_seed); 226 | let dataset = train_test_split(data_x, data_y, train_test_split_ratio); 227 | let dtree = TreeNode::new(dataset.x_train, dataset.y_train, max_depth, min_samples); 228 | dtree.test(dataset.x_test, dataset.y_test); 229 | } 230 | 231 | /// Same benchmark as in original repo 232 | pub fn run_rand( 233 | max_depth: usize, 234 | min_samples: usize, 235 | train_test_split_ratio: f64, 236 | _rng_seed: Option, 237 | ) { 238 | let x: Array1 = Array::linspace(3.0, 3.0, 400); 239 | let y = x.mapv(|e| e.powf(2.0)) + Array::random(400, StandardNormal); 240 | let x = x.into_shape((400, 1)).unwrap(); 241 | let dataset = train_test_split(x, y, train_test_split_ratio); 242 | let dtree = TreeNode::new(dataset.x_train, dataset.y_train, max_depth, min_samples); 243 | dtree.test(dataset.x_test, dataset.y_test); 244 | } 245 | -------------------------------------------------------------------------------- /src/k_means.rs: -------------------------------------------------------------------------------- 1 | use super::RngSeed; 2 | use ndarray::*; 3 | use std::f64; 4 | use utils::{l2_distance, make_blobs, shuffle2, train_test_split}; 5 | 6 | /// K Means unsupervised clustering 7 | struct KMeans { 8 | centers: Array2, 9 | k: usize, 10 | } 11 | 12 | impl KMeans { 13 | pub fn new(x: Array2, k: usize) -> KMeans { 14 | // Initialize centers by picking random samples from the data set 15 | let centers_i: Vec = (0..k).collect(); 16 | let mut centers: Array2 = x.select(Axis(0), ¢ers_i); 17 | 18 | // Keep track of whether the assignment of data points 19 | // to the clusters has changed. When it stops changing, the model has converged. 20 | let mut assigns: Array1 = Array::zeros(x.rows()); 21 | 22 | loop { 23 | // Assign each datapoint to the closest cluster. 24 | let new_assigns: Array1 = x.outer_iter() 25 | .map(|example| KMeans::_predict(¢ers, example)) 26 | .collect(); 27 | if assigns == new_assigns { 28 | break; 29 | } 30 | // Update the current estimates of the cluster centers by setting 31 | // them to the mean of all instance belonging to that cluster 32 | for id in 0..k { 33 | // Indecies of data points classified as 'id' 34 | let points_idx: Vec = new_assigns 35 | .iter() 36 | .enumerate() 37 | .filter(|(_, class)| **class == id) 38 | .map(|(i, _)| i) 39 | .collect(); 40 | assert!( 41 | points_idx.len() > 0, 42 | format!("Nothing classified as class: {}", id) 43 | ); 44 | let datapoints = x.select(Axis(0), &points_idx); 45 | assert!(datapoints.len() > 0); 46 | // The new center is the mean of the data points classified as 'id' 47 | let n = datapoints.len_of(Axis(0)) as f64; 48 | let new_center = datapoints.sum_axis(Axis(0)) / n; 49 | centers.slice_mut(s![id, ..]).assign(&new_center); 50 | } 51 | assigns = new_assigns; 52 | } 53 | KMeans { centers, k } 54 | } 55 | 56 | fn _predict(centers: &Array2, example: ArrayView1) -> usize { 57 | // Compute the L2 distance from the example to every cluster. 58 | // The nearest cluster is our prediction 59 | centers 60 | .outer_iter() 61 | .map(|cluster| l2_distance(&cluster, &example)) 62 | .enumerate() 63 | // Argmin over iterator (index of cluster with shortest distance from example) 64 | .fold( 65 | (0, f64::MAX), 66 | |(imin, emin), (i, e)| if e < emin { (i, e) } else { (imin, emin) }, 67 | ) 68 | .0 69 | } 70 | /// Given a set of features 'example', output a classification 71 | pub fn predict(&self, example: ArrayView1) -> usize { 72 | KMeans::_predict(&self.centers, example) 73 | } 74 | 75 | pub fn test(&self, data_x: Array2, data_y: Array1) { 76 | let preds: Array1 = data_x 77 | .outer_iter() 78 | .map(|example| self.predict(example)) 79 | .collect(); 80 | // We don't know the correspondence between predicted and actual labels. 81 | // Finding the best correspondence requires testing (k!) combinations. 82 | // We use "Heap's algorithm" for creating all possible permutations 83 | // of the range 0..k 84 | let mut mapping: Array1 = Array::from_vec((0..self.k).collect()); 85 | let mut c = Array::zeros(self.k); 86 | let mut i = 0; 87 | let mut n_correct_best = 0; 88 | while i < self.k { 89 | if c[[i]] < i { 90 | // Find the amount of correct predictions for the current mapping 91 | let n_correct = preds 92 | .iter() 93 | .zip(data_y.iter()) 94 | .fold(0, |n, (pred, actual)| { 95 | if mapping[[*pred]] == *actual { 96 | n + 1 97 | } else { 98 | n 99 | } 100 | }); 101 | if n_correct > n_correct_best { 102 | n_correct_best = n_correct; 103 | } 104 | if i % 2 == 0 { 105 | mapping.swap(0, i); 106 | } else { 107 | mapping.swap(c[[i]], i); 108 | } 109 | c[[i]] += 1; 110 | i = 0; 111 | } else { 112 | c[[i]] = 0; 113 | i += 1; 114 | } 115 | } 116 | let acc = n_correct_best as f64 / data_y.len() as f64; 117 | println!( 118 | "{} of {} correct, accuracy: {} %", 119 | n_correct_best, 120 | data_y.len(), 121 | acc * 100.0 122 | ); 123 | } 124 | } 125 | 126 | pub fn run(k: usize, train_test_split_ratio: f64, rng_seed: Option) { 127 | let (x, y): (Array2, Array1) = make_blobs(1000, 2, k); 128 | let (x, y) = shuffle2(x, y, rng_seed); 129 | let dataset = train_test_split(x, y, train_test_split_ratio); 130 | let kmeans = KMeans::new(dataset.x_train, k); 131 | kmeans.test(dataset.x_test, dataset.y_test); 132 | } 133 | -------------------------------------------------------------------------------- /src/k_nearest_neighbors.rs: -------------------------------------------------------------------------------- 1 | use super::RngSeed; 2 | use csv; 3 | use ndarray::*; 4 | use std::collections::HashMap; 5 | use std::hash::Hash; 6 | use std::ops::AddAssign; 7 | use utils::{argsort_floats_1d, shuffle2, train_test_split}; 8 | 9 | /// Computes the euclidean distance between each example in the training data 10 | /// and a new input example 11 | fn euclid_distance(data_x: &Array2, example: &ArrayView1) -> Array1 { 12 | let mut x1: Array2 = data_x - example; 13 | x1.mapv_inplace(|e| e.powf(2.0)); 14 | let mut x3: Array1 = x1.map_axis(Axis(0), |row| row.scalar_sum()); 15 | x3.mapv_inplace(f64::sqrt); 16 | x3 17 | } 18 | 19 | /// Given the data set 'data_x' and 'data_y', predict the label of 'example' 20 | /// using the 'k' nearest neighbors 21 | fn predict( 22 | data_x: &Array2, 23 | data_y: &Array1, 24 | example: &ArrayView1, 25 | k: usize, 26 | ) -> Y { 27 | let dists = euclid_distance(data_x, example); 28 | let mut dists_ix = argsort_floats_1d(&dists); 29 | // Indecies of the 'k' smallest distance data entries 30 | dists_ix.slice_collapse(s![..k]); 31 | // Labels of 'k' nearest entries 32 | let k_ys: Array1 = dists_ix.map(|ix| data_y[[*ix]].clone()); 33 | // Group targets by their count 34 | let mut y_counts: HashMap = HashMap::new(); 35 | for y in k_ys.iter() { 36 | if y_counts.contains_key(&y) { 37 | y_counts.get_mut(&y).unwrap().add_assign(1); 38 | } else { 39 | // TODO should this not be possible without cloning, since its into_iter 40 | y_counts.insert(y.clone(), 1); 41 | } 42 | } 43 | // Return the most common label among 'k' nearest neighbors 44 | y_counts 45 | .into_iter() 46 | .max_by(|(_, cnt1), (_, cnt2)| cnt1.cmp(&cnt2)) 47 | .unwrap() 48 | .0 49 | } 50 | 51 | pub fn run(k: usize, train_test_split_ratio: f64, rng_seed: Option) { 52 | // Load data from csv file into arrays 53 | let file_path = "datasets/digits.csv"; 54 | let mut rdr = csv::Reader::from_path(file_path).unwrap(); 55 | let n_samples = 1796; 56 | // let n_samples = rdr.records().count(); 57 | let n_features = rdr.headers().unwrap().len() - 1; 58 | let mut data_x: Array2 = Array::zeros((n_samples, n_features + 1)); 59 | let mut data_y: Array1 = Array::zeros(n_samples); 60 | for (i, result) in rdr.records().enumerate() { 61 | let r = result.unwrap(); 62 | // The last entry of each row in the csv file is the target/label 63 | let y = r.get(n_features).expect("idx").parse().expect("parse"); 64 | data_y[[i]] = y; 65 | let x: Array1 = r 66 | .into_iter() 67 | .take(n_features) 68 | .map(|e| e.parse().unwrap()) 69 | .collect(); 70 | data_x.slice_mut(s![i, ..-1]).assign(&x); 71 | } 72 | let (data_x, data_y) = shuffle2(data_x, data_y, rng_seed); 73 | let dataset = train_test_split(data_x, data_y, train_test_split_ratio); 74 | 75 | // Compute accuracy on test set 76 | let y_preds: Array1 = dataset 77 | .x_test 78 | .outer_iter() 79 | .map(|example| predict(&dataset.x_train, &dataset.y_train, &example, k)) 80 | .collect(); 81 | let n_eq = 82 | y_preds 83 | .into_iter() 84 | .zip(dataset.y_test.into_iter()) 85 | .fold( 86 | 0, 87 | |acc, (y_pred, y_targ)| if y_pred == y_targ { acc + 1 } else { acc }, 88 | ); 89 | let test_acc: f64 = (n_eq as f64) / (y_preds.len() as f64) * 100.00; 90 | println!("{}", test_acc); 91 | } 92 | -------------------------------------------------------------------------------- /src/logistic_regression.rs: -------------------------------------------------------------------------------- 1 | use ndarray::*; 2 | use std::ops::SubAssign; 3 | use utils::{make_blobs, shuffle2, sigmoid, train_test_split}; 4 | 5 | struct LogisticRegressor { 6 | weights: Array1, 7 | bias: f64, 8 | } 9 | 10 | impl LogisticRegressor { 11 | /// Construct and train a logistic regressor. 12 | /// x: a matrix [n_samples, n_features] of examples 13 | /// y: a vector [n_samples] of targets 14 | /// n_iters: how many training iterations 15 | /// learning_rate: for gradient descent 16 | pub fn new( 17 | x: Array2, 18 | y: Array1, 19 | n_iters: usize, 20 | learning_rate: f64, 21 | ) -> LogisticRegressor { 22 | let scale = 1.0 / x.rows() as f64; 23 | let n_features = x.cols(); 24 | let mut lgr = LogisticRegressor { 25 | weights: Array::zeros(n_features), 26 | bias: 0.0, 27 | }; 28 | for i in 0..n_iters { 29 | let y_pred = lgr.act(&x); 30 | // Negative categorical cross entropy for each data point 31 | let crents = y.clone() * y_pred.mapv(f64::ln) 32 | + (1.0 - y.clone()) * (1.0 - y_pred.clone()).mapv(f64::ln); 33 | // Average cross entropy for data set 34 | let cost = -scale * crents.scalar_sum(); 35 | // Compute gradients for weights and bias 36 | let err = y_pred - y.clone(); 37 | let dw: Array1 = scale * err.dot(&x); 38 | let db: f64 = scale * err.scalar_sum(); 39 | // Update parameters with (non-stochastic) gradient descent 40 | lgr.weights.sub_assign(&(learning_rate * dw)); 41 | lgr.bias.sub_assign(learning_rate * db); 42 | if i % 100 == 0 { 43 | println!("Cost iteration {}: {}", i, cost); 44 | } 45 | } 46 | lgr 47 | } 48 | 49 | /// Given a matrix [n_samples, n_features] of examples 'x', 50 | /// for each examples (row) compute the sigmoid of a linear combination 51 | /// of the example. Returns a matrix of size [n_samples] 52 | fn act>(&self, x: &ArrayBase) -> Array1 { 53 | let mut out = x.dot(&self.weights) + self.bias; 54 | out.mapv_inplace(sigmoid); 55 | out 56 | } 57 | 58 | /// Predicts binary label for an example. 59 | pub fn predict>(&self, example: ArrayBase) -> f64 { 60 | let mut y_pred = self.act(&example.insert_axis(Axis(0))); 61 | // Threshold to 1's and 0's 62 | y_pred.mapv_inplace(|e| if e > 0.5 { 1.0 } else { 0.0 }); 63 | y_pred[[0]] 64 | } 65 | 66 | /// Evaluate regressor performance on a data set 67 | pub fn test(&self, x: &Array2, y: &Array1) -> f64 { 68 | let y_preds: Array1 = x 69 | .outer_iter() 70 | .map(|example| self.predict(example)) 71 | .collect(); 72 | let acc = 100.0 - (y - &y_preds).mapv(f64::abs).mean_axis(Axis(0)) * 100.0; 73 | acc[[]] 74 | } 75 | } 76 | 77 | pub fn run( 78 | n_iters: usize, 79 | learning_rate: f64, 80 | train_test_split_ratio: f64, 81 | rng_seed: Option<[u8; 32]>, 82 | ) { 83 | let (x, y): (Array2, Array1) = make_blobs(1000, 2, 2); 84 | let (x, y) = shuffle2(x, y, rng_seed); 85 | let y = y.mapv(|e| e as f64); 86 | let dataset = train_test_split(x, y, train_test_split_ratio); 87 | let lgr = LogisticRegressor::new( 88 | dataset.x_train.clone(), 89 | dataset.y_train.clone(), 90 | n_iters, 91 | learning_rate, 92 | ); 93 | println!( 94 | "Training set accuracy: {} %", 95 | lgr.test(&dataset.x_train, &dataset.y_train) 96 | ); 97 | println!( 98 | "Test set accuracy: {} %", 99 | lgr.test(&dataset.x_test, &dataset.y_test) 100 | );; 101 | } 102 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | extern crate csv; 3 | extern crate ndarray; 4 | extern crate ndarray_rand; 5 | extern crate num_traits; 6 | extern crate rand; 7 | extern crate rand_chacha; 8 | extern crate serde; 9 | extern crate structopt; 10 | #[macro_use] 11 | extern crate clap; 12 | 13 | mod decision_tree_regression; 14 | mod k_means; 15 | mod k_nearest_neighbors; 16 | mod logistic_regression; 17 | mod support_vector_machine; 18 | mod test; 19 | mod utils; 20 | 21 | use structopt::StructOpt; 22 | 23 | type RngSeed = [u8; 32]; 24 | const RNG_SEED: RngSeed = [0; 32]; 25 | 26 | arg_enum! { 27 | #[derive(PartialEq, Debug)] 28 | pub enum Algo { 29 | DTR, 30 | KNN, 31 | LGR, 32 | SVM, 33 | KMC 34 | } 35 | } 36 | 37 | #[derive(StructOpt, Debug)] 38 | #[structopt(name = "ML Basics")] 39 | pub struct Opt { 40 | /// DTR: Decision Tree Regression. 41 | /// KNN: K Nearest Neighbors. 42 | /// LGR: Logistic Regression. 43 | /// SVM: Support Vector Machine. 44 | /// KMC: K Means Clustering. 45 | #[structopt(raw(possible_values = "&Algo::variants()", case_insensitive = "true"))] 46 | algo: Algo, 47 | 48 | /// Decision tree: Max tree depth 49 | #[structopt(long = "max_depth", default_value = "4")] 50 | max_depth: usize, 51 | 52 | /// Decision tree: Minimum number of samples 53 | #[structopt(long = "min_samples", default_value = "2")] 54 | min_samples: usize, 55 | 56 | /// 'K' parameter for K Nearest Neighors and K Means 57 | #[structopt(short = "k", default_value = "5")] 58 | k: usize, 59 | 60 | /// Logistic regression: Learning rate 61 | #[structopt(long = "learning_rate", short = "a", default_value = "0.009")] 62 | learning_rate: f64, 63 | 64 | /// Logistic regression: Number of training iterations 65 | #[structopt(long = "n_iters", short = "n", default_value = "600")] 66 | n_iters: usize, 67 | 68 | /// Use random seed instead of a fixed seed for the RNG 69 | #[structopt(short = "r", long = "rand_rng")] 70 | rand_rng: bool, 71 | 72 | /// Train test data set split percent 73 | #[structopt(long = "tts", default_value = "0.75")] 74 | train_test_split_ratio: f64, 75 | } 76 | 77 | fn main() { 78 | let opt = Opt::from_args(); 79 | let rng_seed = if opt.rand_rng { None } else { Some(RNG_SEED) }; 80 | let tts = opt.train_test_split_ratio; 81 | match opt.algo { 82 | Algo::DTR => decision_tree_regression::run(opt.max_depth, opt.min_samples, tts, rng_seed), 83 | Algo::KNN => k_nearest_neighbors::run(opt.k, tts, rng_seed), 84 | Algo::LGR => logistic_regression::run(opt.n_iters, opt.learning_rate, tts, rng_seed), 85 | Algo::SVM => logistic_regression::run(opt.n_iters, opt.learning_rate, tts, rng_seed), 86 | Algo::KMC => k_means::run(opt.k, tts, rng_seed), 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use super::RngSeed; 2 | use ndarray::*; 3 | use ndarray_rand::RandomExt; 4 | use num_traits::identities::Zero; 5 | use num_traits::Float; 6 | use rand::distributions::StandardNormal; 7 | use rand::distributions::Uniform; 8 | use rand::seq::SliceRandom; 9 | use rand::{thread_rng, SeedableRng}; 10 | use rand_chacha::ChaChaRng; 11 | use std::fmt::Debug; 12 | use std::str::FromStr; 13 | 14 | /// Computes the euclidean distance (aka L2 distance) 15 | /// between two vectors 16 | pub fn l2_distance(vec1: &ArrayView1, vec2: &ArrayView1) -> f64 { 17 | let mut x1: Array1 = vec1 - vec2; 18 | x1.mapv_inplace(|e| e.powf(2.0)); 19 | x1.scalar_sum().sqrt() 20 | } 21 | 22 | pub fn mean(arr: &Array) -> f64 { 23 | arr.scalar_sum() / arr.len() as f64 24 | } 25 | 26 | /// Argsort of a 1D array 27 | // pub fn argsort_1d(arr: &Array1) -> Array1 { 28 | // let mut zipped: Array1<(usize, &E)> = arr.into_iter().enumerate().collect(); 29 | // zipped 30 | // .as_slice_mut() 31 | // .unwrap() 32 | // .sort_unstable_by_key(|&(_, val)| val); 33 | // zipped.map(|(idx, _)| *idx) 34 | // } 35 | 36 | /// Argsort of a 1D array of floats 37 | pub fn argsort_floats_1d(arr: &Array1) -> Array1 { 38 | let mut zipped: Array1<(usize, &E)> = arr.into_iter().enumerate().collect(); 39 | zipped 40 | .as_slice_mut() 41 | .unwrap() 42 | .sort_unstable_by( 43 | &|(_, x): &(_, &E), (_, y): &(_, &E)| match x.partial_cmp(y) { 44 | Some(ord) => ord, 45 | None => panic!("Attempting to sort NaN's"), 46 | }, 47 | ); 48 | zipped.map(|(i, _)| *i) 49 | } 50 | 51 | #[derive(Debug)] 52 | pub struct Dataset { 53 | pub x_train: Array2, 54 | pub y_train: Array1, 55 | pub x_test: Array2, 56 | pub y_test: Array1, 57 | } 58 | 59 | /// Shuffle the first axis of two arrays in unison 60 | pub fn shuffle2( 61 | arr1: ArrayBase, 62 | arr2: ArrayBase, 63 | rng_seed: Option, 64 | ) -> (Array, Array) 65 | where 66 | B1: Data, 67 | B2: Data, 68 | E1: Copy, 69 | E2: Copy, 70 | D1: Dimension + RemoveAxis, 71 | D2: Dimension + RemoveAxis, 72 | { 73 | let mut indecies: Vec = (0..arr1.len_of(Axis(0))).collect(); 74 | match rng_seed { 75 | Some(seed) => { 76 | indecies.shuffle(&mut ChaChaRng::from_seed(seed)); 77 | } 78 | _ => { 79 | indecies.shuffle(&mut thread_rng()); 80 | } 81 | }; 82 | let arr1 = arr1.select(Axis(0), &indecies); 83 | let arr2 = arr2.select(Axis(0), &indecies); 84 | (arr1, arr2) 85 | } 86 | 87 | /// Shuffle two 1D arrays in place and in unison 88 | // pub fn shuffle_1d_inplace( 89 | // arr1: &mut Array1, 90 | // arr2: &mut Array1, 91 | // rng_seed: Option, 92 | // ) { 93 | // let mut indecies: Vec = (0..arr1.len_of(Axis(0))).collect(); 94 | // match rng_seed { 95 | // Some(seed) => { 96 | // let rng = &mut ChaChaRng::from_seed(seed); 97 | // arr1.as_slice_mut().unwrap().shuffle(rng); 98 | // indecies.shuffle(rng); 99 | // } 100 | // _ => { 101 | // indecies.shuffle(&mut thread_rng()); 102 | // } 103 | // }; 104 | // for (from, to) in indecies.into_iter().enumerate() { 105 | // arr1.swap(from, to); 106 | // arr2.swap(from, to); 107 | // } 108 | // } 109 | 110 | /// Shuffle the data set, then split into training and test set with ratio 'train_test_split_ratio'. 111 | pub fn train_test_split( 112 | data_x: Array2, 113 | data_y: Array1, 114 | train_test_split_ratio: f64, 115 | ) -> Dataset 116 | where 117 | X: Copy + FromStr + Zero + Debug, 118 | Y: Copy + FromStr + Zero + Debug, 119 | { 120 | let n_samples = data_x.rows(); 121 | let n_features = data_x.cols(); 122 | let n_train = (train_test_split_ratio * n_samples as f64) as usize; 123 | let n_test = n_samples - n_train; 124 | let mut x_train: Array2 = Array::zeros((n_train, n_features)); 125 | let mut y_train: Array1 = Array::zeros(n_train); 126 | let mut x_test: Array2 = Array::zeros((n_test, n_features)); 127 | let mut y_test: Array1 = Array::zeros(n_test); 128 | for (i, (x, y)) in data_x.outer_iter().zip(data_y.into_iter()).enumerate() { 129 | if i < n_train { 130 | x_train.slice_mut(s![i, ..]).assign(&x); 131 | y_train[[i]] = *y; 132 | } else { 133 | x_test.slice_mut(s![i - n_train, ..]).assign(&x); 134 | y_test[[i - n_train]] = *y; 135 | }; 136 | } 137 | Dataset { 138 | x_train, 139 | y_train, 140 | x_test, 141 | y_test, 142 | } 143 | } 144 | 145 | /// Generate isotropic Gaussian blobs for clustering. 146 | /// Parameters 147 | /// ---------- 148 | /// n_samples : The total number of points equally divided among clusters. 149 | /// n_features : The number of features for each sample. 150 | /// centers : The number of centers to generate 151 | /// 152 | /// Returns 153 | /// ------- 154 | /// X : array of shape [n_samples, n_features] 155 | /// The generated samples. 156 | /// y : array of shape [n_samples] 157 | /// The label of the samples. 158 | pub fn make_blobs( 159 | n_samples: usize, 160 | n_features: usize, 161 | n_centers: usize, 162 | ) -> (Array2, Array1) { 163 | let centers: Array2 = Array::random((n_centers, n_features), Uniform::new(-10.0, 10.0)); 164 | // let cluster_std: Array1 = Array::ones(n_centers); 165 | let mut n_samples_per_center: Array1 = 166 | Array::ones(n_centers) * (n_samples as f64 / n_centers as f64) as usize; 167 | for i in 0..(n_samples % n_centers) { 168 | n_samples_per_center[[i]] += 1; 169 | } 170 | let mut x = Array::zeros((n_samples, n_features)); 171 | let mut y = Array::zeros(n_samples); 172 | let mut n_added = 0; 173 | for (i, n) in n_samples_per_center.into_iter().enumerate() { 174 | let noise: Array2 = Array::random((*n, n_features), StandardNormal); 175 | let xi = noise + centers.slice(s![i, ..]); 176 | x.slice_mut(s![n_added..n_added + n, ..]).assign(&xi); 177 | y.slice_mut(s![n_added..n_added + n]).assign(&array![i]); 178 | n_added += n; 179 | } 180 | shuffle2(x, y, None) 181 | } 182 | 183 | /// The sigmoid function, also known as the logistic function 184 | pub fn sigmoid(a: f64) -> f64 { 185 | 1.0 / (1.0 + (-a).exp()) 186 | } 187 | --------------------------------------------------------------------------------