├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.clj ├── deps.edn ├── dev └── scratch.clj ├── doc └── intro.md ├── poetry.lock ├── pom.xml ├── pyproject.toml ├── python.edn ├── src └── scicloj │ ├── sklearn_clj.clj │ └── sklearn_clj │ ├── metamorph.clj │ ├── ml.clj │ └── sklearn_wrapper.clj ├── test └── scicloj │ ├── cat_test.clj │ ├── iris_test.clj │ ├── metamorph_test.clj │ ├── perf_test.clj │ ├── regression_test.clj │ ├── sklearn_clj_test.clj │ └── sklearn_wrapper_test.clj ├── tests.edn └── train_delay.py /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/java:11-bullseye 2 | 3 | RUN bash -c "bash < <(curl -s https://raw.githubusercontent.com/babashka/babashka/master/install)" 4 | RUN bash -c "bash < <(curl -s https://raw.githubusercontent.com/clojure-lsp/clojure-lsp/master/install)" 5 | 6 | RUN curl "https://raw.githubusercontent.com/behrica/enrich-classpath/logProgress/tools.deps/src/cider/enrich_classpath/clojure.sh" -o /usr/local/bin/enrich_clojure.sh && \ 7 | chmod +x /usr/local/bin/enrich_clojure.sh 8 | 9 | COPY <<-EOT /usr/local/bin/enriched_clojure 10 | #!/bin/bash 11 | 12 | enrich_clojure.sh /home/vscode/.asdf/shims/clojure "\$@" 13 | 14 | EOT 15 | RUN chmod +x /usr/local/bin/enriched_clojure 16 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "remoteUser" : "vscode", 3 | "name" : "sklearn clj", 4 | "build" : { 5 | "dockerfile" : "Dockerfile" 6 | }, 7 | "remoteEnv" : { 8 | "PATH" : "${containerEnv:PATH}:/home/vscode/.asdf/shims" 9 | }, 10 | "customizations" : { 11 | "vscode" : { 12 | "settings" : { }, 13 | "extensions" : [ "betterthantomorrow.calva" ] 14 | } 15 | }, 16 | "features" : { 17 | "ghcr.io/devcontainers-contrib/features/clojure-asdf:2" : { }, 18 | "ghcr.io/devcontainers-contrib/features/bash-command:1" : { 19 | "command" : "apt-get update && apt-get install -y rlwrap" 20 | }, 21 | "ghcr.io/devcontainers/features/python:1" : { }, 22 | "ghcr.io/devcontainers-contrib/features/poetry:2" : { } 23 | }, 24 | "postCreateCommand" : {"setupClojure": "sudo ln -fs /home/vscode/.asdf/shims/clojure /usr/local/bin/", 25 | "setupPython" : "mkdir -p .venv && poetry install"}, 26 | "postStartCommand": "clojure -Atest -Sthreads 1 -P" 27 | 28 | 29 | } -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | ci: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: run CI 16 | uses: devcontainers/ci@v0.3 17 | with: 18 | runCmd: clj -T:build ci 19 | push: never 20 | 21 | 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /classes 3 | /checkouts 4 | *.jar 5 | *.class 6 | /.cpcache 7 | /.lein-* 8 | /.nrepl-history 9 | /.nrepl-port 10 | .hgignore 11 | .hg/ 12 | .clj-kondo/ 13 | .lsp/ 14 | .settings/ 15 | .project 16 | .classpath 17 | /.calva/ 18 | /.portal/ 19 | .clerk 20 | .vscode 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | * 0.5 5 | * use latest metamorph.ml 6 | * options in malli format 7 | 8 | * 0.4.1 9 | * support single-case-capital params (#5) 10 | * fixes #8 regressors use predict_prob by default, which is not defined or most/all regressors 11 | * fixes #9 certain options cannot be passed to models 12 | * fixes #10 FixedThresholdClassifier and TunedThresholdClassifierCV 13 | -> compatibilty wit latest sklearn 14 | 15 | * 0.4.0 16 | * fix result of predict to be a probability distribution 17 | * fixed serialization of contexts containing sklearn-clj models 18 | * allow reverse-mapping of categorical variables of prediction 19 | * 0.3.6 20 | * added model attributes to train results 21 | * 0.3.5 22 | * require full module path for estimators 23 | * added method to retrieve all attributes of trained model as map 24 | 25 | * 0.3.0 26 | * adapted to libpython-clj 2.0.0-BETA-12 27 | * zero copy 28 | * 0.2.1 29 | * added fit-transform 30 | * more robust 31 | * more tests 32 | * 0.2.0 33 | * adapted to latest metamorph 34 | * 0.1.0 35 | * first version 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC 2 | LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM 3 | CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 4 | 5 | 1. DEFINITIONS 6 | 7 | "Contribution" means: 8 | 9 | a) in the case of the initial Contributor, the initial code and 10 | documentation distributed under this Agreement, and 11 | 12 | b) in the case of each subsequent Contributor: 13 | 14 | i) changes to the Program, and 15 | 16 | ii) additions to the Program; 17 | 18 | where such changes and/or additions to the Program originate from and are 19 | distributed by that particular Contributor. A Contribution 'originates' from 20 | a Contributor if it was added to the Program by such Contributor itself or 21 | anyone acting on such Contributor's behalf. Contributions do not include 22 | additions to the Program which: (i) are separate modules of software 23 | distributed in conjunction with the Program under their own license 24 | agreement, and (ii) are not derivative works of the Program. 25 | 26 | "Contributor" means any person or entity that distributes the Program. 27 | 28 | "Licensed Patents" mean patent claims licensable by a Contributor which are 29 | necessarily infringed by the use or sale of its Contribution alone or when 30 | combined with the Program. 31 | 32 | "Program" means the Contributions distributed in accordance with this 33 | Agreement. 34 | 35 | "Recipient" means anyone who receives the Program under this Agreement, 36 | including all Contributors. 37 | 38 | 2. GRANT OF RIGHTS 39 | 40 | a) Subject to the terms of this Agreement, each Contributor hereby grants 41 | Recipient a non-exclusive, worldwide, royalty-free copyright license to 42 | reproduce, prepare derivative works of, publicly display, publicly perform, 43 | distribute and sublicense the Contribution of such Contributor, if any, and 44 | such derivative works, in source code and object code form. 45 | 46 | b) Subject to the terms of this Agreement, each Contributor hereby grants 47 | Recipient a non-exclusive, worldwide, royalty-free patent license under 48 | Licensed Patents to make, use, sell, offer to sell, import and otherwise 49 | transfer the Contribution of such Contributor, if any, in source code and 50 | object code form. This patent license shall apply to the combination of the 51 | Contribution and the Program if, at the time the Contribution is added by the 52 | Contributor, such addition of the Contribution causes such combination to be 53 | covered by the Licensed Patents. The patent license shall not apply to any 54 | other combinations which include the Contribution. No hardware per se is 55 | licensed hereunder. 56 | 57 | c) Recipient understands that although each Contributor grants the licenses 58 | to its Contributions set forth herein, no assurances are provided by any 59 | Contributor that the Program does not infringe the patent or other 60 | intellectual property rights of any other entity. Each Contributor disclaims 61 | any liability to Recipient for claims brought by any other entity based on 62 | infringement of intellectual property rights or otherwise. As a condition to 63 | exercising the rights and licenses granted hereunder, each Recipient hereby 64 | assumes sole responsibility to secure any other intellectual property rights 65 | needed, if any. For example, if a third party patent license is required to 66 | allow Recipient to distribute the Program, it is Recipient's responsibility 67 | to acquire that license before distributing the Program. 68 | 69 | d) Each Contributor represents that to its knowledge it has sufficient 70 | copyright rights in its Contribution, if any, to grant the copyright license 71 | set forth in this Agreement. 72 | 73 | 3. REQUIREMENTS 74 | 75 | A Contributor may choose to distribute the Program in object code form under 76 | its own license agreement, provided that: 77 | 78 | a) it complies with the terms and conditions of this Agreement; and 79 | 80 | b) its license agreement: 81 | 82 | i) effectively disclaims on behalf of all Contributors all warranties and 83 | conditions, express and implied, including warranties or conditions of title 84 | and non-infringement, and implied warranties or conditions of merchantability 85 | and fitness for a particular purpose; 86 | 87 | ii) effectively excludes on behalf of all Contributors all liability for 88 | damages, including direct, indirect, special, incidental and consequential 89 | damages, such as lost profits; 90 | 91 | iii) states that any provisions which differ from this Agreement are offered 92 | by that Contributor alone and not by any other party; and 93 | 94 | iv) states that source code for the Program is available from such 95 | Contributor, and informs licensees how to obtain it in a reasonable manner on 96 | or through a medium customarily used for software exchange. 97 | 98 | When the Program is made available in source code form: 99 | 100 | a) it must be made available under this Agreement; and 101 | 102 | b) a copy of this Agreement must be included with each copy of the Program. 103 | 104 | Contributors may not remove or alter any copyright notices contained within 105 | the Program. 106 | 107 | Each Contributor must identify itself as the originator of its Contribution, 108 | if any, in a manner that reasonably allows subsequent Recipients to identify 109 | the originator of the Contribution. 110 | 111 | 4. COMMERCIAL DISTRIBUTION 112 | 113 | Commercial distributors of software may accept certain responsibilities with 114 | respect to end users, business partners and the like. While this license is 115 | intended to facilitate the commercial use of the Program, the Contributor who 116 | includes the Program in a commercial product offering should do so in a 117 | manner which does not create potential liability for other Contributors. 118 | Therefore, if a Contributor includes the Program in a commercial product 119 | offering, such Contributor ("Commercial Contributor") hereby agrees to defend 120 | and indemnify every other Contributor ("Indemnified Contributor") against any 121 | losses, damages and costs (collectively "Losses") arising from claims, 122 | lawsuits and other legal actions brought by a third party against the 123 | Indemnified Contributor to the extent caused by the acts or omissions of such 124 | Commercial Contributor in connection with its distribution of the Program in 125 | a commercial product offering. The obligations in this section do not apply 126 | to any claims or Losses relating to any actual or alleged intellectual 127 | property infringement. In order to qualify, an Indemnified Contributor must: 128 | a) promptly notify the Commercial Contributor in writing of such claim, and 129 | b) allow the Commercial Contributor tocontrol, and cooperate with the 130 | Commercial Contributor in, the defense and any related settlement 131 | negotiations. The Indemnified Contributor may participate in any such claim 132 | at its own expense. 133 | 134 | For example, a Contributor might include the Program in a commercial product 135 | offering, Product X. That Contributor is then a Commercial Contributor. If 136 | that Commercial Contributor then makes performance claims, or offers 137 | warranties related to Product X, those performance claims and warranties are 138 | such Commercial Contributor's responsibility alone. Under this section, the 139 | Commercial Contributor would have to defend claims against the other 140 | Contributors related to those performance claims and warranties, and if a 141 | court requires any other Contributor to pay any damages as a result, the 142 | Commercial Contributor must pay those damages. 143 | 144 | 5. NO WARRANTY 145 | 146 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON 147 | AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER 148 | EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR 149 | CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A 150 | PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the 151 | appropriateness of using and distributing the Program and assumes all risks 152 | associated with its exercise of rights under this Agreement , including but 153 | not limited to the risks and costs of program errors, compliance with 154 | applicable laws, damage to or loss of data, programs or equipment, and 155 | unavailability or interruption of operations. 156 | 157 | 6. DISCLAIMER OF LIABILITY 158 | 159 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY 160 | CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, 161 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION 162 | LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 163 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 164 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 165 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY 166 | OF SUCH DAMAGES. 167 | 168 | 7. GENERAL 169 | 170 | If any provision of this Agreement is invalid or unenforceable under 171 | applicable law, it shall not affect the validity or enforceability of the 172 | remainder of the terms of this Agreement, and without further action by the 173 | parties hereto, such provision shall be reformed to the minimum extent 174 | necessary to make such provision valid and enforceable. 175 | 176 | If Recipient institutes patent litigation against any entity (including a 177 | cross-claim or counterclaim in a lawsuit) alleging that the Program itself 178 | (excluding combinations of the Program with other software or hardware) 179 | infringes such Recipient's patent(s), then such Recipient's rights granted 180 | under Section 2(b) shall terminate as of the date such litigation is filed. 181 | 182 | All Recipient's rights under this Agreement shall terminate if it fails to 183 | comply with any of the material terms or conditions of this Agreement and 184 | does not cure such failure in a reasonable period of time after becoming 185 | aware of such noncompliance. If all Recipient's rights under this Agreement 186 | terminate, Recipient agrees to cease use and distribution of the Program as 187 | soon as reasonably practicable. However, Recipient's obligations under this 188 | Agreement and any licenses granted by Recipient relating to the Program shall 189 | continue and survive. 190 | 191 | Everyone is permitted to copy and distribute copies of this Agreement, but in 192 | order to avoid inconsistency the Agreement is copyrighted and may only be 193 | modified in the following manner. The Agreement Steward reserves the right to 194 | publish new versions (including revisions) of this Agreement from time to 195 | time. No one other than the Agreement Steward has the right to modify this 196 | Agreement. The Eclipse Foundation is the initial Agreement Steward. The 197 | Eclipse Foundation may assign the responsibility to serve as the Agreement 198 | Steward to a suitable separate entity. Each new version of the Agreement will 199 | be given a distinguishing version number. The Program (including 200 | Contributions) may always be distributed subject to the version of the 201 | Agreement under which it was received. In addition, after a new version of 202 | the Agreement is published, Contributor may elect to distribute the Program 203 | (including its Contributions) under the new version. Except as expressly 204 | stated in Sections 2(a) and 2(b) above, Recipient receives no rights or 205 | licenses to the intellectual property of any Contributor under this 206 | Agreement, whether expressly, by implication, estoppel or otherwise. All 207 | rights in the Program not expressly granted under this Agreement are 208 | reserved. 209 | 210 | This Agreement is governed by the laws of the State of New York and the 211 | intellectual property laws of the United States of America. No party to this 212 | Agreement will bring a legal action under this Agreement more than one year 213 | after the cause of action arose. Each party waives its rights to a jury trial 214 | in any resulting litigation. 215 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CI](https://github.com/scicloj/sklearn-clj/actions/workflows/ci.yml/badge.svg) 2 | [![Clojars Project](https://img.shields.io/clojars/v/org.scicloj/sklearn-clj.svg)](https://clojars.org/org.scicloj/sklearn-clj) 3 | 4 | # sklearn-clj 5 | 6 | This library gives easy access in Clojure to all estimators and models from python [scikit-learn,](https://scikit-learn.org/) 7 | using internally libpython-clj. 8 | 9 | 10 | It uses a tech.ml.dataset for input and output and converts this data structures to and from python as needed. This "should" be zero copy now. 11 | 12 | As all estimators and models in sklearn uses the same interface, it works for all estimators. 13 | 14 | A opinionated tutorial is [here](https://scicloj.github.io/clojure-data-tutorials/projects/ml/sklearn-clj/) 15 | 16 | ## Usage 17 | 18 | Setup libpython-clj including sklearn. 19 | 20 | If you need to call `py/initialize!` as part of your libpython-clj setup, this needs to happen before require 21 | the other namesspaces. This can be done easely by adding a `user.clj` file which contains the call to `py/initialize!` 22 | 23 | See here https://github.com/clj-python/libpython-clj#usage for more information how to setup libpython-clj. 24 | 25 | 26 | 27 | ```clojure 28 | 29 | 30 | (require 31 | '[libpython-clj2.python :refer [py.-]] 32 | '[tech.v3.dataset :as ds] 33 | '[tech.v3.dataset.modelling :as ds-mod] 34 | '[scicloj.sklearn-clj :refer :all] 35 | ) 36 | 37 | ;; example train and test dataset 38 | 39 | (def train-ds 40 | (-> (ds/->dataset {:x1 [1 1 2 2] 41 | :x2 [1 2 2 3] 42 | :y [6 8 9 11]}) 43 | (ds-mod/set-inference-target :y))) 44 | 45 | (def test-ds 46 | (-> 47 | (ds/->dataset {:x1 [3] 48 | :x2 [5] 49 | :y [0]}) 50 | (ds-mod/set-inference-target :y))) 51 | 52 | ;; fit a liner expression model from sklearn, class sklearn.linear_model.LinearRegression 53 | 54 | (def lin-reg 55 | (fit train-ds :sklearn.linear-model :linear-regression )) 56 | 57 | ;; Call predict with new data on the estimator 58 | (predict test-ds lin-reg {}) 59 | ;; => _unnamed [1 3]: 60 | ;; | :x1 | :x2 | :y | 61 | ;; |-----|-----|------| 62 | ;; | 3 | 5 | 16.0 | 63 | 64 | ;; use an other estimator, this time: sklearn.preprocessing.StandardScaler 65 | (def data 66 | (ds/->dataset {:x1 [0 0 1 1] 67 | :x2 [0 0 1 1]})) 68 | 69 | ;; fit the scaler on data 70 | (def scaler 71 | (fit data :sklearn.preprocessing :standard-scaler)) 72 | 73 | (py.- scaler mean_) 74 | ;; => [0.5 0.5] 75 | ;; 76 | 77 | ;; apply the scaling on new data 78 | (transform (ds/->dataset {:x1 [2] :x2 [2]}) scaler) 79 | ;; => :_unnamed [1 2]: 80 | ;; | :x1 | :x2 | 81 | ;; |-----|-----| 82 | ;; | 3.0 | 3.0 | 83 | 84 | ``` 85 | 86 | The library provides as well an adaptor to the scicloj [metamorph](https://github.com/scicloj/metamorph) library, in order to use the estimators inside a metamorph pipeline. 87 | 88 | 89 | ```clojure 90 | (require '[scicloj.sklearn-clj.metamorph :as sklearn-mm]) 91 | 92 | ;; adding this as a pipeline operation somewhere in the pipeline 93 | ;; The estimate functon will do the right thing, depending on the :metamorph/mode key being 94 | ;; :fit or :transform , namely calling "fit" on :fit and "predict" on :transform 95 | (sklearn-mm/estimate :sklearn.linear-model :linear-regression {}) 96 | ``` 97 | 98 | 99 | Alternatively the models can be integrated in tech.ml / [scicloj.ml](https://github.com/scicloj/scicloj.ml) 100 | 101 | ``` clojure 102 | (require '[scicloj.sklearn-clj.ml]) ;; registers all models 103 | (require '[scicloj.ml.core :as ml] 104 | '[scicloj.ml.metamorph :as mm] 105 | '[scicloj.ml.dataset :as ds] 106 | '[libpython-clj2.python :refer [py. py.-]]) 107 | 108 | (def iris 109 | (-> 110 | (ds/dataset 111 | "https://raw.githubusercontent.com/scicloj/metamorph.ml/main/test/data/iris.csv" {:key-fn keyword}))) 112 | 113 | 114 | (def pipe-fn 115 | (ml/pipeline 116 | (mm/set-inference-target :species) 117 | (mm/categorical->number [:species]) 118 | {:metamorph/id :model} 119 | (mm/model {:model-type :sklearn.classification/logistic-regression}))) 120 | 121 | (def trained-ctx (ml/fit-pipe iris pipe-fn)) 122 | 123 | (def model-object 124 | (-> trained-ctx :model :model-data :model)) 125 | 126 | 127 | (py.- model-object coef_) 128 | ;; => [[ 0.53399346 -0.31779319 -0.20533681 -0.93955019] 129 | ;; [-0.42332856 0.96165291 -2.51935878 -1.08617922] 130 | ;; [-0.1106649 -0.64385972 2.72469559 2.02572941]] 131 | 132 | ``` 133 | 134 | All available models with their key, options and complete documentation are listed here: 135 | 136 | 137 | 138 | https://scicloj.github.io/scicloj.ml-tutorials/userguide-sklearnclj.html 139 | 140 | ## License 141 | 142 | Copyright © 2021 Scicloj 143 | 144 | Distributed under the Eclipse Public License either version 1.0 or (at 145 | your option) any later version. 146 | -------------------------------------------------------------------------------- /build.clj: -------------------------------------------------------------------------------- 1 | (ns build 2 | (:refer-clojure :exclude [test]) 3 | (:require [clojure.tools.build.api :as b] ; for b/git-count-revs 4 | [org.corfield.build :as bb])) 5 | 6 | (def lib 'org.scicloj/sklearn-clj) 7 | ; alternatively, use MAJOR.MINOR.COMMITS: 8 | ;;(def version (format "0.2.%s" (b/git-count-revs nil))) 9 | (def version "0.5") 10 | 11 | (defn test "Run the tests." [opts] 12 | (-> opts 13 | (assoc :aliases [:runner]) 14 | (bb/run-tests))) 15 | 16 | (defn ci "Run the CI pipeline of tests (and build the JAR)." [opts] 17 | (-> opts 18 | (assoc :lib lib :version version :aliases [:runner]) 19 | (bb/run-tests) 20 | (bb/clean) 21 | (bb/jar))) 22 | 23 | (defn ci-no-test "Run the CI pipeline of tests (and build the JAR)." [opts] 24 | (-> opts 25 | (assoc :lib lib :version version) 26 | (bb/clean) 27 | (bb/jar))) 28 | (defn install "Install the JAR locally." [opts] 29 | (-> opts 30 | (assoc :lib lib :version version) 31 | (bb/install))) 32 | 33 | (defn deploy "Deploy the JAR to Clojars." [opts] 34 | (-> opts 35 | (assoc :lib lib :version version) 36 | (bb/deploy))) 37 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src" "resources"] 2 | :deps {org.clojure/clojure {:mvn/version "1.12.0"} 3 | clj-python/libpython-clj {:mvn/version "2.026"} 4 | org.scicloj/metamorph.ml {:mvn/version "1.0"} 5 | } 6 | :aliases 7 | { 8 | :build {:extra-deps {io.github.seancorfield/build-clj 9 | {:git/tag "v0.5.2" :git/sha "8f75b81"}} 10 | :ns-default build} 11 | :test {:extra-paths ["test"] 12 | :extra-deps {org.clojure/test.check {:mvn/version "1.1.0"} 13 | 14 | org.scicloj/scicloj.ml.smile {:mvn/version "7.5.0"}}} 15 | 16 | :runner {:main-opts ["-m" "kaocha.runner"] 17 | :extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}} 18 | 19 | :deploy {:extra-deps {slipset/deps-deploy {:mvn/version "RELEASE"}} 20 | :exec-fn deps-deploy.deps-deploy/deploy 21 | :exec-args {:installer :remote 22 | :sign-releases? false 23 | :artifact "target/sklearn-clj-0.5.jar"}}}} 24 | -------------------------------------------------------------------------------- /dev/scratch.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.scratch) 2 | 3 | (comment 4 | 5 | (require '[scicloj.sklearn-clj.ml]) ;; registers all models 6 | (require '[scicloj.ml.core :as ml] 7 | '[scicloj.ml.metamorph :as mm] 8 | '[scicloj.ml.dataset :as ds] 9 | '[tech.v3.libs.smile.data :as smile-data] 10 | '[camel-snake-kebab.core :as csk] 11 | '[libpython-clj2.python :refer [py. py.-]] 12 | '[scicloj.sklearn-clj.metamorph :as sklearn-mm] 13 | '[smile.manifold :as smile-mf]) 14 | 15 | (def pinguins 16 | (-> 17 | (ds/dataset 18 | "https://github.com/allisonhorst/palmerpenguins/raw/5b5891f01b52ae26ad8cb9755ec93672f49328a8/data/penguins_size.csv" 19 | {:key-fn csk/->kebab-case-keyword}))) 20 | 21 | (defn fit-smile-umap [] 22 | (fn [{:metamorph/keys [id data mode] :as ctx}] 23 | (def data data) 24 | (assoc ctx :metamorph/data 25 | (-> data 26 | (ds/rows :as-double-arrays) 27 | smile-mf/umap 28 | (#(.coordinates %)) 29 | ds/dataset)))) 30 | 31 | 32 | (def pipe 33 | (ml/pipeline 34 | (mm/drop-missing) 35 | (mm/select-columns [:culmen-length-mm :culmen-depth-mm :flipper-length-mm :body-mass-g]) 36 | (mm/std-scale :type/numerical {}) 37 | {:metamorph/id :model} 38 | (fit-smile-umap))) 39 | ;; (sklearn-mm/fit-transform :umap "UMAP") 40 | 41 | 42 | 43 | (def fit-ctx 44 | (ml/fit-pipe pinguins pipe)) 45 | 46 | (-> fit-ctx :metamorph/data)) 47 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | # Introduction to sklearn-clj 2 | 3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/) 4 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "contourpy" 5 | version = "1.3.0" 6 | description = "Python library for calculating contours of 2D quadrilateral grids" 7 | optional = false 8 | python-versions = ">=3.9" 9 | files = [ 10 | {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, 11 | {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, 12 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, 13 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, 14 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, 15 | {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, 16 | {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, 17 | {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, 18 | {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, 19 | {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, 20 | {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, 21 | {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, 22 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, 23 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, 24 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, 25 | {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, 26 | {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, 27 | {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, 28 | {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, 29 | {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, 30 | {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, 31 | {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, 32 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, 33 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, 34 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, 35 | {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, 36 | {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, 37 | {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, 38 | {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, 39 | {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, 40 | {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, 41 | {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, 42 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, 43 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, 44 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, 45 | {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, 46 | {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, 47 | {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, 48 | {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, 49 | {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, 50 | {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, 51 | {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, 52 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, 53 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, 54 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, 55 | {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, 56 | {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, 57 | {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, 58 | {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"}, 59 | {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"}, 60 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"}, 61 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"}, 62 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"}, 63 | {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"}, 64 | {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"}, 65 | {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"}, 66 | {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"}, 67 | {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"}, 68 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, 69 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, 70 | {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, 71 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"}, 72 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"}, 73 | {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"}, 74 | {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, 75 | ] 76 | 77 | [package.dependencies] 78 | numpy = ">=1.23" 79 | 80 | [package.extras] 81 | bokeh = ["bokeh", "selenium"] 82 | docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] 83 | mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] 84 | test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] 85 | test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] 86 | 87 | [[package]] 88 | name = "cycler" 89 | version = "0.12.1" 90 | description = "Composable style cycles" 91 | optional = false 92 | python-versions = ">=3.8" 93 | files = [ 94 | {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, 95 | {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, 96 | ] 97 | 98 | [package.extras] 99 | docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] 100 | tests = ["pytest", "pytest-cov", "pytest-xdist"] 101 | 102 | [[package]] 103 | name = "fonttools" 104 | version = "4.55.0" 105 | description = "Tools to manipulate font files" 106 | optional = false 107 | python-versions = ">=3.8" 108 | files = [ 109 | {file = "fonttools-4.55.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:51c029d4c0608a21a3d3d169dfc3fb776fde38f00b35ca11fdab63ba10a16f61"}, 110 | {file = "fonttools-4.55.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bca35b4e411362feab28e576ea10f11268b1aeed883b9f22ed05675b1e06ac69"}, 111 | {file = "fonttools-4.55.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ce4ba6981e10f7e0ccff6348e9775ce25ffadbee70c9fd1a3737e3e9f5fa74f"}, 112 | {file = "fonttools-4.55.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31d00f9852a6051dac23294a4cf2df80ced85d1d173a61ba90a3d8f5abc63c60"}, 113 | {file = "fonttools-4.55.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e198e494ca6e11f254bac37a680473a311a88cd40e58f9cc4dc4911dfb686ec6"}, 114 | {file = "fonttools-4.55.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7208856f61770895e79732e1dcbe49d77bd5783adf73ae35f87fcc267df9db81"}, 115 | {file = "fonttools-4.55.0-cp310-cp310-win32.whl", hash = "sha256:e7e6a352ff9e46e8ef8a3b1fe2c4478f8a553e1b5a479f2e899f9dc5f2055880"}, 116 | {file = "fonttools-4.55.0-cp310-cp310-win_amd64.whl", hash = "sha256:636caaeefe586d7c84b5ee0734c1a5ab2dae619dc21c5cf336f304ddb8f6001b"}, 117 | {file = "fonttools-4.55.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fa34aa175c91477485c44ddfbb51827d470011e558dfd5c7309eb31bef19ec51"}, 118 | {file = "fonttools-4.55.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:37dbb3fdc2ef7302d3199fb12468481cbebaee849e4b04bc55b77c24e3c49189"}, 119 | {file = "fonttools-4.55.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5263d8e7ef3c0ae87fbce7f3ec2f546dc898d44a337e95695af2cd5ea21a967"}, 120 | {file = "fonttools-4.55.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f307f6b5bf9e86891213b293e538d292cd1677e06d9faaa4bf9c086ad5f132f6"}, 121 | {file = "fonttools-4.55.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f0a4b52238e7b54f998d6a56b46a2c56b59c74d4f8a6747fb9d4042190f37cd3"}, 122 | {file = "fonttools-4.55.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3e569711464f777a5d4ef522e781dc33f8095ab5efd7548958b36079a9f2f88c"}, 123 | {file = "fonttools-4.55.0-cp311-cp311-win32.whl", hash = "sha256:2b3ab90ec0f7b76c983950ac601b58949f47aca14c3f21eed858b38d7ec42b05"}, 124 | {file = "fonttools-4.55.0-cp311-cp311-win_amd64.whl", hash = "sha256:aa046f6a63bb2ad521004b2769095d4c9480c02c1efa7d7796b37826508980b6"}, 125 | {file = "fonttools-4.55.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:838d2d8870f84fc785528a692e724f2379d5abd3fc9dad4d32f91cf99b41e4a7"}, 126 | {file = "fonttools-4.55.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f46b863d74bab7bb0d395f3b68d3f52a03444964e67ce5c43ce43a75efce9246"}, 127 | {file = "fonttools-4.55.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33b52a9cfe4e658e21b1f669f7309b4067910321757fec53802ca8f6eae96a5a"}, 128 | {file = "fonttools-4.55.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:732a9a63d6ea4a81b1b25a1f2e5e143761b40c2e1b79bb2b68e4893f45139a40"}, 129 | {file = "fonttools-4.55.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7dd91ac3fcb4c491bb4763b820bcab6c41c784111c24172616f02f4bc227c17d"}, 130 | {file = "fonttools-4.55.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1f0e115281a32ff532118aa851ef497a1b7cda617f4621c1cdf81ace3e36fb0c"}, 131 | {file = "fonttools-4.55.0-cp312-cp312-win32.whl", hash = "sha256:6c99b5205844f48a05cb58d4a8110a44d3038c67ed1d79eb733c4953c628b0f6"}, 132 | {file = "fonttools-4.55.0-cp312-cp312-win_amd64.whl", hash = "sha256:f8c8c76037d05652510ae45be1cd8fb5dd2fd9afec92a25374ac82255993d57c"}, 133 | {file = "fonttools-4.55.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8118dc571921dc9e4b288d9cb423ceaf886d195a2e5329cc427df82bba872cd9"}, 134 | {file = "fonttools-4.55.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01124f2ca6c29fad4132d930da69158d3f49b2350e4a779e1efbe0e82bd63f6c"}, 135 | {file = "fonttools-4.55.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ffd58d2691f11f7c8438796e9f21c374828805d33e83ff4b76e4635633674c"}, 136 | {file = "fonttools-4.55.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5435e5f1eb893c35c2bc2b9cd3c9596b0fcb0a59e7a14121562986dd4c47b8dd"}, 137 | {file = "fonttools-4.55.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d12081729280c39d001edd0f4f06d696014c26e6e9a0a55488fabc37c28945e4"}, 138 | {file = "fonttools-4.55.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a7ad1f1b98ab6cb927ab924a38a8649f1ffd7525c75fe5b594f5dab17af70e18"}, 139 | {file = "fonttools-4.55.0-cp313-cp313-win32.whl", hash = "sha256:abe62987c37630dca69a104266277216de1023cf570c1643bb3a19a9509e7a1b"}, 140 | {file = "fonttools-4.55.0-cp313-cp313-win_amd64.whl", hash = "sha256:2863555ba90b573e4201feaf87a7e71ca3b97c05aa4d63548a4b69ea16c9e998"}, 141 | {file = "fonttools-4.55.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:00f7cf55ad58a57ba421b6a40945b85ac7cc73094fb4949c41171d3619a3a47e"}, 142 | {file = "fonttools-4.55.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f27526042efd6f67bfb0cc2f1610fa20364396f8b1fc5edb9f45bb815fb090b2"}, 143 | {file = "fonttools-4.55.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e67974326af6a8879dc2a4ec63ab2910a1c1a9680ccd63e4a690950fceddbe"}, 144 | {file = "fonttools-4.55.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61dc0a13451143c5e987dec5254d9d428f3c2789a549a7cf4f815b63b310c1cc"}, 145 | {file = "fonttools-4.55.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:b2e526b325a903868c62155a6a7e24df53f6ce4c5c3160214d8fe1be2c41b478"}, 146 | {file = "fonttools-4.55.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b7ef9068a1297714e6fefe5932c33b058aa1d45a2b8be32a4c6dee602ae22b5c"}, 147 | {file = "fonttools-4.55.0-cp38-cp38-win32.whl", hash = "sha256:55718e8071be35dff098976bc249fc243b58efa263768c611be17fe55975d40a"}, 148 | {file = "fonttools-4.55.0-cp38-cp38-win_amd64.whl", hash = "sha256:553bd4f8cc327f310c20158e345e8174c8eed49937fb047a8bda51daf2c353c8"}, 149 | {file = "fonttools-4.55.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f901cef813f7c318b77d1c5c14cf7403bae5cb977cede023e22ba4316f0a8f6"}, 150 | {file = "fonttools-4.55.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8c9679fc0dd7e8a5351d321d8d29a498255e69387590a86b596a45659a39eb0d"}, 151 | {file = "fonttools-4.55.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd2820a8b632f3307ebb0bf57948511c2208e34a4939cf978333bc0a3f11f838"}, 152 | {file = "fonttools-4.55.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23bbbb49bec613a32ed1b43df0f2b172313cee690c2509f1af8fdedcf0a17438"}, 153 | {file = "fonttools-4.55.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a656652e1f5d55b9728937a7e7d509b73d23109cddd4e89ee4f49bde03b736c6"}, 154 | {file = "fonttools-4.55.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f50a1f455902208486fbca47ce33054208a4e437b38da49d6721ce2fef732fcf"}, 155 | {file = "fonttools-4.55.0-cp39-cp39-win32.whl", hash = "sha256:161d1ac54c73d82a3cded44202d0218ab007fde8cf194a23d3dd83f7177a2f03"}, 156 | {file = "fonttools-4.55.0-cp39-cp39-win_amd64.whl", hash = "sha256:ca7fd6987c68414fece41c96836e945e1f320cda56fc96ffdc16e54a44ec57a2"}, 157 | {file = "fonttools-4.55.0-py3-none-any.whl", hash = "sha256:12db5888cd4dd3fcc9f0ee60c6edd3c7e1fd44b7dd0f31381ea03df68f8a153f"}, 158 | {file = "fonttools-4.55.0.tar.gz", hash = "sha256:7636acc6ab733572d5e7eec922b254ead611f1cdad17be3f0be7418e8bfaca71"}, 159 | ] 160 | 161 | [package.extras] 162 | all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] 163 | graphite = ["lz4 (>=1.7.4.2)"] 164 | interpolatable = ["munkres", "pycairo", "scipy"] 165 | lxml = ["lxml (>=4.0)"] 166 | pathops = ["skia-pathops (>=0.5.0)"] 167 | plot = ["matplotlib"] 168 | repacker = ["uharfbuzz (>=0.23.0)"] 169 | symfont = ["sympy"] 170 | type1 = ["xattr"] 171 | ufo = ["fs (>=2.2.0,<3)"] 172 | unicode = ["unicodedata2 (>=15.1.0)"] 173 | woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] 174 | 175 | [[package]] 176 | name = "importlib-resources" 177 | version = "6.4.5" 178 | description = "Read resources from Python packages" 179 | optional = false 180 | python-versions = ">=3.8" 181 | files = [ 182 | {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, 183 | {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, 184 | ] 185 | 186 | [package.dependencies] 187 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} 188 | 189 | [package.extras] 190 | check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] 191 | cover = ["pytest-cov"] 192 | doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 193 | enabler = ["pytest-enabler (>=2.2)"] 194 | test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] 195 | type = ["pytest-mypy"] 196 | 197 | [[package]] 198 | name = "joblib" 199 | version = "1.4.2" 200 | description = "Lightweight pipelining with Python functions" 201 | optional = false 202 | python-versions = ">=3.8" 203 | files = [ 204 | {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, 205 | {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, 206 | ] 207 | 208 | [[package]] 209 | name = "kiwisolver" 210 | version = "1.4.7" 211 | description = "A fast implementation of the Cassowary constraint solver" 212 | optional = false 213 | python-versions = ">=3.8" 214 | files = [ 215 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, 216 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, 217 | {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, 218 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, 219 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, 220 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, 221 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, 222 | {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, 223 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, 224 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, 225 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, 226 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, 227 | {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, 228 | {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, 229 | {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, 230 | {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, 231 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, 232 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, 233 | {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, 234 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, 235 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, 236 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, 237 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, 238 | {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, 239 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, 240 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, 241 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, 242 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, 243 | {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, 244 | {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, 245 | {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, 246 | {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, 247 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, 248 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, 249 | {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, 250 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, 251 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, 252 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, 253 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, 254 | {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, 255 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, 256 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, 257 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, 258 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, 259 | {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, 260 | {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, 261 | {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, 262 | {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, 263 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, 264 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, 265 | {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, 266 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, 267 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, 268 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, 269 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, 270 | {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, 271 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, 272 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, 273 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, 274 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, 275 | {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, 276 | {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, 277 | {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, 278 | {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, 279 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, 280 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, 281 | {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, 282 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, 283 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, 284 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, 285 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, 286 | {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, 287 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, 288 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, 289 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, 290 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, 291 | {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, 292 | {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, 293 | {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, 294 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, 295 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, 296 | {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, 297 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, 298 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, 299 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, 300 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, 301 | {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, 302 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, 303 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, 304 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, 305 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, 306 | {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, 307 | {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, 308 | {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, 309 | {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, 310 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, 311 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, 312 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, 313 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, 314 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, 315 | {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, 316 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, 317 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, 318 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, 319 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, 320 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, 321 | {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, 322 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, 323 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, 324 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, 325 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, 326 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, 327 | {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, 328 | {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, 329 | ] 330 | 331 | [[package]] 332 | name = "matplotlib" 333 | version = "3.9.2" 334 | description = "Python plotting package" 335 | optional = false 336 | python-versions = ">=3.9" 337 | files = [ 338 | {file = "matplotlib-3.9.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9d78bbc0cbc891ad55b4f39a48c22182e9bdaea7fc0e5dbd364f49f729ca1bbb"}, 339 | {file = "matplotlib-3.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c375cc72229614632c87355366bdf2570c2dac01ac66b8ad048d2dabadf2d0d4"}, 340 | {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d94ff717eb2bd0b58fe66380bd8b14ac35f48a98e7c6765117fe67fb7684e64"}, 341 | {file = "matplotlib-3.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab68d50c06938ef28681073327795c5db99bb4666214d2d5f880ed11aeaded66"}, 342 | {file = "matplotlib-3.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:65aacf95b62272d568044531e41de26285d54aec8cb859031f511f84bd8b495a"}, 343 | {file = "matplotlib-3.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:3fd595f34aa8a55b7fc8bf9ebea8aa665a84c82d275190a61118d33fbc82ccae"}, 344 | {file = "matplotlib-3.9.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8dd059447824eec055e829258ab092b56bb0579fc3164fa09c64f3acd478772"}, 345 | {file = "matplotlib-3.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c797dac8bb9c7a3fd3382b16fe8f215b4cf0f22adccea36f1545a6d7be310b41"}, 346 | {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d719465db13267bcef19ea8954a971db03b9f48b4647e3860e4bc8e6ed86610f"}, 347 | {file = "matplotlib-3.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8912ef7c2362f7193b5819d17dae8629b34a95c58603d781329712ada83f9447"}, 348 | {file = "matplotlib-3.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7741f26a58a240f43bee74965c4882b6c93df3e7eb3de160126d8c8f53a6ae6e"}, 349 | {file = "matplotlib-3.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae82a14dab96fbfad7965403c643cafe6515e386de723e498cf3eeb1e0b70cc7"}, 350 | {file = "matplotlib-3.9.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac43031375a65c3196bee99f6001e7fa5bdfb00ddf43379d3c0609bdca042df9"}, 351 | {file = "matplotlib-3.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be0fc24a5e4531ae4d8e858a1a548c1fe33b176bb13eff7f9d0d38ce5112a27d"}, 352 | {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf81de2926c2db243c9b2cbc3917619a0fc85796c6ba4e58f541df814bbf83c7"}, 353 | {file = "matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ee45bc4245533111ced13f1f2cace1e7f89d1c793390392a80c139d6cf0e6c"}, 354 | {file = "matplotlib-3.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:306c8dfc73239f0e72ac50e5a9cf19cc4e8e331dd0c54f5e69ca8758550f1e1e"}, 355 | {file = "matplotlib-3.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:5413401594cfaff0052f9d8b1aafc6d305b4bd7c4331dccd18f561ff7e1d3bd3"}, 356 | {file = "matplotlib-3.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:18128cc08f0d3cfff10b76baa2f296fc28c4607368a8402de61bb3f2eb33c7d9"}, 357 | {file = "matplotlib-3.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4876d7d40219e8ae8bb70f9263bcbe5714415acfdf781086601211335e24f8aa"}, 358 | {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d9f07a80deab4bb0b82858a9e9ad53d1382fd122be8cde11080f4e7dfedb38b"}, 359 | {file = "matplotlib-3.9.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c0410f181a531ec4e93bbc27692f2c71a15c2da16766f5ba9761e7ae518413"}, 360 | {file = "matplotlib-3.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:909645cce2dc28b735674ce0931a4ac94e12f5b13f6bb0b5a5e65e7cea2c192b"}, 361 | {file = "matplotlib-3.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:f32c7410c7f246838a77d6d1eff0c0f87f3cb0e7c4247aebea71a6d5a68cab49"}, 362 | {file = "matplotlib-3.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:37e51dd1c2db16ede9cfd7b5cabdfc818b2c6397c83f8b10e0e797501c963a03"}, 363 | {file = "matplotlib-3.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b82c5045cebcecd8496a4d694d43f9cc84aeeb49fe2133e036b207abe73f4d30"}, 364 | {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f053c40f94bc51bc03832a41b4f153d83f2062d88c72b5e79997072594e97e51"}, 365 | {file = "matplotlib-3.9.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbe196377a8248972f5cede786d4c5508ed5f5ca4a1e09b44bda889958b33f8c"}, 366 | {file = "matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e"}, 367 | {file = "matplotlib-3.9.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:cef2a73d06601437be399908cf13aee74e86932a5ccc6ccdf173408ebc5f6bb2"}, 368 | {file = "matplotlib-3.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0830e188029c14e891fadd99702fd90d317df294c3298aad682739c5533721a"}, 369 | {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ba9c1299c920964e8d3857ba27173b4dbb51ca4bab47ffc2c2ba0eb5e2cbc5"}, 370 | {file = "matplotlib-3.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cd93b91ab47a3616b4d3c42b52f8363b88ca021e340804c6ab2536344fad9ca"}, 371 | {file = "matplotlib-3.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6d1ce5ed2aefcdce11904fc5bbea7d9c21fff3d5f543841edf3dea84451a09ea"}, 372 | {file = "matplotlib-3.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:b2696efdc08648536efd4e1601b5fd491fd47f4db97a5fbfd175549a7365c1b2"}, 373 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d52a3b618cb1cbb769ce2ee1dcdb333c3ab6e823944e9a2d36e37253815f9556"}, 374 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:039082812cacd6c6bec8e17a9c1e6baca230d4116d522e81e1f63a74d01d2e21"}, 375 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6758baae2ed64f2331d4fd19be38b7b4eae3ecec210049a26b6a4f3ae1c85dcc"}, 376 | {file = "matplotlib-3.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:050598c2b29e0b9832cde72bcf97627bf00262adbc4a54e2b856426bb2ef0697"}, 377 | {file = "matplotlib-3.9.2.tar.gz", hash = "sha256:96ab43906269ca64a6366934106fa01534454a69e471b7bf3d79083981aaab92"}, 378 | ] 379 | 380 | [package.dependencies] 381 | contourpy = ">=1.0.1" 382 | cycler = ">=0.10" 383 | fonttools = ">=4.22.0" 384 | importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} 385 | kiwisolver = ">=1.3.1" 386 | numpy = ">=1.23" 387 | packaging = ">=20.0" 388 | pillow = ">=8" 389 | pyparsing = ">=2.3.1" 390 | python-dateutil = ">=2.7" 391 | 392 | [package.extras] 393 | dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] 394 | 395 | [[package]] 396 | name = "numpy" 397 | version = "2.0.2" 398 | description = "Fundamental package for array computing in Python" 399 | optional = false 400 | python-versions = ">=3.9" 401 | files = [ 402 | {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, 403 | {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, 404 | {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, 405 | {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, 406 | {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, 407 | {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, 408 | {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, 409 | {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, 410 | {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, 411 | {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, 412 | {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, 413 | {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, 414 | {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, 415 | {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, 416 | {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, 417 | {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, 418 | {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, 419 | {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, 420 | {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, 421 | {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, 422 | {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, 423 | {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, 424 | {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, 425 | {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, 426 | {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, 427 | {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, 428 | {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, 429 | {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, 430 | {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, 431 | {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, 432 | {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, 433 | {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, 434 | {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, 435 | {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, 436 | {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, 437 | {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, 438 | {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, 439 | {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, 440 | {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, 441 | {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, 442 | {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, 443 | {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, 444 | {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, 445 | {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, 446 | {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, 447 | ] 448 | 449 | [[package]] 450 | name = "numpy" 451 | version = "2.1.3" 452 | description = "Fundamental package for array computing in Python" 453 | optional = false 454 | python-versions = ">=3.10" 455 | files = [ 456 | {file = "numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff"}, 457 | {file = "numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5"}, 458 | {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1"}, 459 | {file = "numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd"}, 460 | {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3"}, 461 | {file = "numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098"}, 462 | {file = "numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c"}, 463 | {file = "numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4"}, 464 | {file = "numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23"}, 465 | {file = "numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0"}, 466 | {file = "numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d"}, 467 | {file = "numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41"}, 468 | {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9"}, 469 | {file = "numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09"}, 470 | {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a"}, 471 | {file = "numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b"}, 472 | {file = "numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee"}, 473 | {file = "numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0"}, 474 | {file = "numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9"}, 475 | {file = "numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2"}, 476 | {file = "numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e"}, 477 | {file = "numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958"}, 478 | {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8"}, 479 | {file = "numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564"}, 480 | {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512"}, 481 | {file = "numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b"}, 482 | {file = "numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc"}, 483 | {file = "numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0"}, 484 | {file = "numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9"}, 485 | {file = "numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a"}, 486 | {file = "numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f"}, 487 | {file = "numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598"}, 488 | {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57"}, 489 | {file = "numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe"}, 490 | {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43"}, 491 | {file = "numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56"}, 492 | {file = "numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a"}, 493 | {file = "numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef"}, 494 | {file = "numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f"}, 495 | {file = "numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed"}, 496 | {file = "numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f"}, 497 | {file = "numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4"}, 498 | {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e"}, 499 | {file = "numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0"}, 500 | {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408"}, 501 | {file = "numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6"}, 502 | {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f"}, 503 | {file = "numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17"}, 504 | {file = "numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48"}, 505 | {file = "numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4"}, 506 | {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f"}, 507 | {file = "numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4"}, 508 | {file = "numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d"}, 509 | {file = "numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb"}, 510 | {file = "numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761"}, 511 | ] 512 | 513 | [[package]] 514 | name = "packaging" 515 | version = "24.2" 516 | description = "Core utilities for Python packages" 517 | optional = false 518 | python-versions = ">=3.8" 519 | files = [ 520 | {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, 521 | {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, 522 | ] 523 | 524 | [[package]] 525 | name = "pandas" 526 | version = "2.2.3" 527 | description = "Powerful data structures for data analysis, time series, and statistics" 528 | optional = false 529 | python-versions = ">=3.9" 530 | files = [ 531 | {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, 532 | {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, 533 | {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"}, 534 | {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"}, 535 | {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"}, 536 | {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"}, 537 | {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"}, 538 | {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, 539 | {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, 540 | {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, 541 | {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, 542 | {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, 543 | {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, 544 | {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, 545 | {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, 546 | {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, 547 | {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, 548 | {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, 549 | {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, 550 | {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, 551 | {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, 552 | {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, 553 | {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, 554 | {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, 555 | {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, 556 | {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, 557 | {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, 558 | {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, 559 | {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, 560 | {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, 561 | {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, 562 | {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, 563 | {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, 564 | {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, 565 | {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"}, 566 | {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"}, 567 | {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"}, 568 | {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"}, 569 | {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"}, 570 | {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"}, 571 | {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"}, 572 | {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, 573 | ] 574 | 575 | [package.dependencies] 576 | numpy = [ 577 | {version = ">=1.22.4", markers = "python_version < \"3.11\""}, 578 | {version = ">=1.23.2", markers = "python_version == \"3.11\""}, 579 | {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, 580 | ] 581 | python-dateutil = ">=2.8.2" 582 | pytz = ">=2020.1" 583 | tzdata = ">=2022.7" 584 | 585 | [package.extras] 586 | all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] 587 | aws = ["s3fs (>=2022.11.0)"] 588 | clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] 589 | compression = ["zstandard (>=0.19.0)"] 590 | computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] 591 | consortium-standard = ["dataframe-api-compat (>=0.1.7)"] 592 | excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] 593 | feather = ["pyarrow (>=10.0.1)"] 594 | fss = ["fsspec (>=2022.11.0)"] 595 | gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] 596 | hdf5 = ["tables (>=3.8.0)"] 597 | html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] 598 | mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] 599 | output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] 600 | parquet = ["pyarrow (>=10.0.1)"] 601 | performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] 602 | plot = ["matplotlib (>=3.6.3)"] 603 | postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] 604 | pyarrow = ["pyarrow (>=10.0.1)"] 605 | spss = ["pyreadstat (>=1.2.0)"] 606 | sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] 607 | test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] 608 | xml = ["lxml (>=4.9.2)"] 609 | 610 | [[package]] 611 | name = "pillow" 612 | version = "11.0.0" 613 | description = "Python Imaging Library (Fork)" 614 | optional = false 615 | python-versions = ">=3.9" 616 | files = [ 617 | {file = "pillow-11.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6619654954dc4936fcff82db8eb6401d3159ec6be81e33c6000dfd76ae189947"}, 618 | {file = "pillow-11.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3c5ac4bed7519088103d9450a1107f76308ecf91d6dabc8a33a2fcfb18d0fba"}, 619 | {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a65149d8ada1055029fcb665452b2814fe7d7082fcb0c5bed6db851cb69b2086"}, 620 | {file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"}, 621 | {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c26845094b1af3c91852745ae78e3ea47abf3dbcd1cf962f16b9a5fbe3ee8488"}, 622 | {file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"}, 623 | {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:674629ff60030d144b7bca2b8330225a9b11c482ed408813924619c6f302fdbb"}, 624 | {file = "pillow-11.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:598b4e238f13276e0008299bd2482003f48158e2b11826862b1eb2ad7c768b97"}, 625 | {file = "pillow-11.0.0-cp310-cp310-win32.whl", hash = "sha256:9a0f748eaa434a41fccf8e1ee7a3eed68af1b690e75328fd7a60af123c193b50"}, 626 | {file = "pillow-11.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:a5629742881bcbc1f42e840af185fd4d83a5edeb96475a575f4da50d6ede337c"}, 627 | {file = "pillow-11.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:ee217c198f2e41f184f3869f3e485557296d505b5195c513b2bfe0062dc537f1"}, 628 | {file = "pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc"}, 629 | {file = "pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a"}, 630 | {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3"}, 631 | {file = "pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5"}, 632 | {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b"}, 633 | {file = "pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa"}, 634 | {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306"}, 635 | {file = "pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9"}, 636 | {file = "pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5"}, 637 | {file = "pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291"}, 638 | {file = "pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9"}, 639 | {file = "pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923"}, 640 | {file = "pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903"}, 641 | {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4"}, 642 | {file = "pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f"}, 643 | {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9"}, 644 | {file = "pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7"}, 645 | {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6"}, 646 | {file = "pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc"}, 647 | {file = "pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6"}, 648 | {file = "pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47"}, 649 | {file = "pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25"}, 650 | {file = "pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699"}, 651 | {file = "pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38"}, 652 | {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2"}, 653 | {file = "pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2"}, 654 | {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527"}, 655 | {file = "pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa"}, 656 | {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f"}, 657 | {file = "pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb"}, 658 | {file = "pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798"}, 659 | {file = "pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de"}, 660 | {file = "pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84"}, 661 | {file = "pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b"}, 662 | {file = "pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003"}, 663 | {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2"}, 664 | {file = "pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a"}, 665 | {file = "pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8"}, 666 | {file = "pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8"}, 667 | {file = "pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904"}, 668 | {file = "pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3"}, 669 | {file = "pillow-11.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2e46773dc9f35a1dd28bd6981332fd7f27bec001a918a72a79b4133cf5291dba"}, 670 | {file = "pillow-11.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2679d2258b7f1192b378e2893a8a0a0ca472234d4c2c0e6bdd3380e8dfa21b6a"}, 671 | {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda2616eb2313cbb3eebbe51f19362eb434b18e3bb599466a1ffa76a033fb916"}, 672 | {file = "pillow-11.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ec184af98a121fb2da42642dea8a29ec80fc3efbaefb86d8fdd2606619045d"}, 673 | {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:8594f42df584e5b4bb9281799698403f7af489fba84c34d53d1c4bfb71b7c4e7"}, 674 | {file = "pillow-11.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:c12b5ae868897c7338519c03049a806af85b9b8c237b7d675b8c5e089e4a618e"}, 675 | {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:70fbbdacd1d271b77b7721fe3cdd2d537bbbd75d29e6300c672ec6bb38d9672f"}, 676 | {file = "pillow-11.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5178952973e588b3f1360868847334e9e3bf49d19e169bbbdfaf8398002419ae"}, 677 | {file = "pillow-11.0.0-cp39-cp39-win32.whl", hash = "sha256:8c676b587da5673d3c75bd67dd2a8cdfeb282ca38a30f37950511766b26858c4"}, 678 | {file = "pillow-11.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:94f3e1780abb45062287b4614a5bc0874519c86a777d4a7ad34978e86428b8dd"}, 679 | {file = "pillow-11.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:290f2cc809f9da7d6d622550bbf4c1e57518212da51b6a30fe8e0a270a5b78bd"}, 680 | {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1187739620f2b365de756ce086fdb3604573337cc28a0d3ac4a01ab6b2d2a6d2"}, 681 | {file = "pillow-11.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fbbcb7b57dc9c794843e3d1258c0fbf0f48656d46ffe9e09b63bbd6e8cd5d0a2"}, 682 | {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d203af30149ae339ad1b4f710d9844ed8796e97fda23ffbc4cc472968a47d0b"}, 683 | {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21a0d3b115009ebb8ac3d2ebec5c2982cc693da935f4ab7bb5c8ebe2f47d36f2"}, 684 | {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:73853108f56df97baf2bb8b522f3578221e56f646ba345a372c78326710d3830"}, 685 | {file = "pillow-11.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e58876c91f97b0952eb766123bfef372792ab3f4e3e1f1a2267834c2ab131734"}, 686 | {file = "pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316"}, 687 | {file = "pillow-11.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5bd2d3bdb846d757055910f0a59792d33b555800813c3b39ada1829c372ccb06"}, 688 | {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375b8dd15a1f5d2feafff536d47e22f69625c1aa92f12b339ec0b2ca40263273"}, 689 | {file = "pillow-11.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:daffdf51ee5db69a82dd127eabecce20729e21f7a3680cf7cbb23f0829189790"}, 690 | {file = "pillow-11.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7326a1787e3c7b0429659e0a944725e1b03eeaa10edd945a86dead1913383944"}, 691 | {file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"}, 692 | ] 693 | 694 | [package.extras] 695 | docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] 696 | fpx = ["olefile"] 697 | mic = ["olefile"] 698 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] 699 | typing = ["typing-extensions"] 700 | xmp = ["defusedxml"] 701 | 702 | [[package]] 703 | name = "pyparsing" 704 | version = "3.2.0" 705 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 706 | optional = false 707 | python-versions = ">=3.9" 708 | files = [ 709 | {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, 710 | {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, 711 | ] 712 | 713 | [package.extras] 714 | diagrams = ["jinja2", "railroad-diagrams"] 715 | 716 | [[package]] 717 | name = "python-dateutil" 718 | version = "2.9.0.post0" 719 | description = "Extensions to the standard Python datetime module" 720 | optional = false 721 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 722 | files = [ 723 | {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, 724 | {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, 725 | ] 726 | 727 | [package.dependencies] 728 | six = ">=1.5" 729 | 730 | [[package]] 731 | name = "pytz" 732 | version = "2024.2" 733 | description = "World timezone definitions, modern and historical" 734 | optional = false 735 | python-versions = "*" 736 | files = [ 737 | {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, 738 | {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, 739 | ] 740 | 741 | [[package]] 742 | name = "scikit-learn" 743 | version = "1.5.2" 744 | description = "A set of python modules for machine learning and data mining" 745 | optional = false 746 | python-versions = ">=3.9" 747 | files = [ 748 | {file = "scikit_learn-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:299406827fb9a4f862626d0fe6c122f5f87f8910b86fe5daa4c32dcd742139b6"}, 749 | {file = "scikit_learn-1.5.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2d4cad1119c77930b235579ad0dc25e65c917e756fe80cab96aa3b9428bd3fb0"}, 750 | {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c412ccc2ad9bf3755915e3908e677b367ebc8d010acbb3f182814524f2e5540"}, 751 | {file = "scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a686885a4b3818d9e62904d91b57fa757fc2bed3e465c8b177be652f4dd37c8"}, 752 | {file = "scikit_learn-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:c15b1ca23d7c5f33cc2cb0a0d6aaacf893792271cddff0edbd6a40e8319bc113"}, 753 | {file = "scikit_learn-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03b6158efa3faaf1feea3faa884c840ebd61b6484167c711548fce208ea09445"}, 754 | {file = "scikit_learn-1.5.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1ff45e26928d3b4eb767a8f14a9a6efbf1cbff7c05d1fb0f95f211a89fd4f5de"}, 755 | {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f763897fe92d0e903aa4847b0aec0e68cadfff77e8a0687cabd946c89d17e675"}, 756 | {file = "scikit_learn-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8b0ccd4a902836493e026c03256e8b206656f91fbcc4fde28c57a5b752561f1"}, 757 | {file = "scikit_learn-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6c16d84a0d45e4894832b3c4d0bf73050939e21b99b01b6fd59cbb0cf39163b6"}, 758 | {file = "scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f932a02c3f4956dfb981391ab24bda1dbd90fe3d628e4b42caef3e041c67707a"}, 759 | {file = "scikit_learn-1.5.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3b923d119d65b7bd555c73be5423bf06c0105678ce7e1f558cb4b40b0a5502b1"}, 760 | {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd"}, 761 | {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6"}, 762 | {file = "scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1"}, 763 | {file = "scikit_learn-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9a702e2de732bbb20d3bad29ebd77fc05a6b427dc49964300340e4c9328b3f5"}, 764 | {file = "scikit_learn-1.5.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b0768ad641981f5d3a198430a1d31c3e044ed2e8a6f22166b4d546a5116d7908"}, 765 | {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:178ddd0a5cb0044464fc1bfc4cca5b1833bfc7bb022d70b05db8530da4bb3dd3"}, 766 | {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7284ade780084d94505632241bf78c44ab3b6f1e8ccab3d2af58e0e950f9c12"}, 767 | {file = "scikit_learn-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:b7b0f9a0b1040830d38c39b91b3a44e1b643f4b36e36567b80b7c6bd2202a27f"}, 768 | {file = "scikit_learn-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:757c7d514ddb00ae249832fe87100d9c73c6ea91423802872d9e74970a0e40b9"}, 769 | {file = "scikit_learn-1.5.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:52788f48b5d8bca5c0736c175fa6bdaab2ef00a8f536cda698db61bd89c551c1"}, 770 | {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:643964678f4b5fbdc95cbf8aec638acc7aa70f5f79ee2cdad1eec3df4ba6ead8"}, 771 | {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca64b3089a6d9b9363cd3546f8978229dcbb737aceb2c12144ee3f70f95684b7"}, 772 | {file = "scikit_learn-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:3bed4909ba187aca80580fe2ef370d9180dcf18e621a27c4cf2ef10d279a7efe"}, 773 | {file = "scikit_learn-1.5.2.tar.gz", hash = "sha256:b4237ed7b3fdd0a4882792e68ef2545d5baa50aca3bb45aa7df468138ad8f94d"}, 774 | ] 775 | 776 | [package.dependencies] 777 | joblib = ">=1.2.0" 778 | numpy = ">=1.19.5" 779 | scipy = ">=1.6.0" 780 | threadpoolctl = ">=3.1.0" 781 | 782 | [package.extras] 783 | benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] 784 | build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] 785 | docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.16.0)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)"] 786 | examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] 787 | install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] 788 | maintenance = ["conda-lock (==2.5.6)"] 789 | tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.2.1)", "scikit-image (>=0.17.2)"] 790 | 791 | [[package]] 792 | name = "scipy" 793 | version = "1.13.1" 794 | description = "Fundamental algorithms for scientific computing in Python" 795 | optional = false 796 | python-versions = ">=3.9" 797 | files = [ 798 | {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, 799 | {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, 800 | {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, 801 | {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, 802 | {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, 803 | {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, 804 | {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, 805 | {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, 806 | {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, 807 | {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, 808 | {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, 809 | {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, 810 | {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, 811 | {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, 812 | {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, 813 | {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, 814 | {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, 815 | {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, 816 | {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, 817 | {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, 818 | {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, 819 | {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, 820 | {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, 821 | {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, 822 | {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, 823 | ] 824 | 825 | [package.dependencies] 826 | numpy = ">=1.22.4,<2.3" 827 | 828 | [package.extras] 829 | dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] 830 | doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] 831 | test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] 832 | 833 | [[package]] 834 | name = "six" 835 | version = "1.16.0" 836 | description = "Python 2 and 3 compatibility utilities" 837 | optional = false 838 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 839 | files = [ 840 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 841 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 842 | ] 843 | 844 | [[package]] 845 | name = "threadpoolctl" 846 | version = "3.5.0" 847 | description = "threadpoolctl" 848 | optional = false 849 | python-versions = ">=3.8" 850 | files = [ 851 | {file = "threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467"}, 852 | {file = "threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107"}, 853 | ] 854 | 855 | [[package]] 856 | name = "tzdata" 857 | version = "2024.2" 858 | description = "Provider of IANA time zone data" 859 | optional = false 860 | python-versions = ">=2" 861 | files = [ 862 | {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, 863 | {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, 864 | ] 865 | 866 | [[package]] 867 | name = "yellowbrick" 868 | version = "1.5" 869 | description = "A suite of visual analysis and diagnostic tools for machine learning." 870 | optional = false 871 | python-versions = ">=3.4, <4" 872 | files = [ 873 | {file = "yellowbrick-1.5-py3-none-any.whl", hash = "sha256:4bb2895cecf94a0e736398bbac6c5d72032ba3ff2273f49df660b14ef419305d"}, 874 | {file = "yellowbrick-1.5.tar.gz", hash = "sha256:99a6336dd2e7ce586a8cde67966b79c51b479d3759f3c083d7e19ffe949f6076"}, 875 | ] 876 | 877 | [package.dependencies] 878 | cycler = ">=0.10.0" 879 | matplotlib = ">=2.0.2,<3.0.0 || >3.0.0" 880 | numpy = ">=1.16.0" 881 | scikit-learn = ">=1.0.0" 882 | scipy = ">=1.0.0" 883 | 884 | [[package]] 885 | name = "zipp" 886 | version = "3.21.0" 887 | description = "Backport of pathlib-compatible object wrapper for zip files" 888 | optional = false 889 | python-versions = ">=3.9" 890 | files = [ 891 | {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, 892 | {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, 893 | ] 894 | 895 | [package.extras] 896 | check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] 897 | cover = ["pytest-cov"] 898 | doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 899 | enabler = ["pytest-enabler (>=2.2)"] 900 | test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] 901 | type = ["pytest-mypy"] 902 | 903 | [metadata] 904 | lock-version = "2.0" 905 | python-versions = "^3.9" 906 | content-hash = "5a51d873cf187186f5b022088b1e3c43387d792a119f9a82c53e0cfdef515db5" 907 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | jar 5 | org.scicloj 6 | sklearn-clj 7 | 0.4.1 8 | sklearn-clj 9 | 10 | 11 | org.clojure 12 | clojure 13 | 1.12.0 14 | 15 | 16 | scicloj 17 | metamorph.ml 18 | 0.8.2 19 | 20 | 21 | clj-python 22 | libpython-clj 23 | 2.025 24 | 25 | 26 | 27 | 28 | Eclipse Public License 1.0 29 | https://www.eclipse.org/org/documents/epl-v10.html 30 | 31 | 32 | 33 | src 34 | 35 | 36 | 37 | clojars 38 | https://repo.clojars.org/ 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "dummy" 3 | version = "0.0.0" 4 | description = "" 5 | authors = [] 6 | package-mode = false 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.9" 10 | scikit-learn = "1.6.1" 11 | yellowbrick = "1.5" 12 | pandas = "2.2.3" 13 | 14 | [build-system] 15 | requires = ["poetry-core"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /python.edn: -------------------------------------------------------------------------------- 1 | {:python-executable ".venv/bin/python3"} -------------------------------------------------------------------------------- /src/scicloj/sklearn_clj.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-clj 2 | (:require 3 | [camel-snake-kebab.core :as csk] 4 | [clojure.string :as str] 5 | clojure.walk 6 | [libpython-clj2.python 7 | :as py 8 | :refer [cfn path->py-obj python-type py.]] 9 | [libpython-clj2.python.np-array] 10 | [tech.v3.dataset :as ds] 11 | [tech.v3.dataset.column-filters :as cf] 12 | [tech.v3.dataset.modelling :as ds-mod] 13 | [tech.v3.dataset.tensor :as dst] 14 | tech.v3.datatype.casting 15 | [tech.v3.datatype.errors :as errors])) 16 | 17 | 18 | (defn assert-numeric-ds [ds] 19 | (errors/when-not-error 20 | (every? true? 21 | (map 22 | #(-> % meta :datatype tech.v3.datatype.casting/numeric-type?) 23 | (ds/columns ds))) 24 | "All values of target columns need to be numeric.")) 25 | 26 | 27 | 28 | 29 | 30 | 31 | (defmacro labeled-time 32 | "Evaluates expr and prints the time it took. Returns the value of 33 | expr." 34 | {:added "1.0"} 35 | [label expr] 36 | `(let [start# (. System (nanoTime)) 37 | ret# ~expr] 38 | (prn (str ~label " - " "elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs")) 39 | ret#)) 40 | 41 | (py/initialize!) 42 | (println "'sklearn' version found: " 43 | (get 44 | (py/module-dict (py/import-module "sklearn")) 45 | "__version__")) 46 | 47 | (defmacro when-error 48 | "Throw an error in the case where expr is true." 49 | [expr error-msg] 50 | {:style/indent 1} 51 | `(when ~expr 52 | (throw (Exception. ~error-msg)))) 53 | 54 | 55 | 56 | (defn mapply [f & args] (apply f (apply concat (butlast args) (last args)))) 57 | 58 | (defn snakify-keys 59 | "Recursively transforms all map keys from to snake case." 60 | {:added "1.1"} 61 | [m] 62 | (let [f (fn [[k v]] (if (and (keyword? k) 63 | (> (count (name k)) 1)) 64 | [(csk/->snake_case_keyword k :separator \-) v] 65 | [(keyword k) v] 66 | 67 | ))] 68 | ;; only apply to maps 69 | (clojure.walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) m))) 70 | 71 | 72 | (defn make-estimator [module-kw estimator-class kw-args] 73 | (let [ 74 | snakified-kw-args (snakify-keys kw-args) 75 | module (csk/->snake_case_string module-kw) 76 | class-name (if (keyword? estimator-class) 77 | (csk/->PascalCaseString estimator-class) 78 | estimator-class) 79 | estimator-class-name (str module "." class-name) 80 | constructor (path->py-obj estimator-class-name)] 81 | (mapply cfn constructor snakified-kw-args))) 82 | 83 | (defn ndarray->ds [pyobject] 84 | (-> pyobject 85 | py/->jvm 86 | dst/tensor->dataset)) 87 | 88 | (defn numeric-ds->ndarray [ds] 89 | (assert-numeric-ds ds) 90 | (-> ds 91 | dst/dataset->tensor 92 | py/->python)) 93 | 94 | 95 | 96 | (defn raw-tf-result->ds [raw-result] 97 | (let [raw-type (python-type raw-result) 98 | result (case raw-type 99 | :csr-matrix (py. raw-result toarray) 100 | :ndarray raw-result) 101 | new-ds (ndarray->ds result)] 102 | 103 | new-ds)) 104 | 105 | 106 | (defn ds->X [ds] 107 | (let [ 108 | string-ds (cf/of-datatype ds :string) 109 | numeric-ds (cf/numeric ds) 110 | _ (when-error (and (some? string-ds) (some? numeric-ds)) 111 | "Dataset contains numeric and non-numeric features, which is not supported.") 112 | 113 | X (if (nil? string-ds) 114 | (numeric-ds->ndarray numeric-ds) 115 | 116 | (do 117 | (errors/when-not-error (= 1 (ds/column-count string-ds)) 118 | "Dataset contains more then 1 string column, which is not supported.") 119 | 120 | (-> ds ds/columns first)))] 121 | X)) 122 | 123 | 124 | (defn prepare-python [ds module-kw estimator-class-kw kw-args] 125 | {:estimator (make-estimator module-kw estimator-class-kw kw-args) 126 | :inference-target (cf/target ds) 127 | :X (-> ds cf/feature ds->X py/->py-list) 128 | :y (some-> ds 129 | cf/target 130 | numeric-ds->ndarray 131 | (py. ravel))}) 132 | 133 | 134 | (defn fit 135 | "Call the fit method of a sklearn transformer, which is specified via 136 | the two keywords `module-kw` and `estimator-class-kw`. 137 | Keyword arguments can be given in a map `kw-arguments`. 138 | The data need to be given as tech.ml.dataset and will be converted to python automaticaly. 139 | The function will return the estimator as a python object. 140 | " 141 | ([ds module-kw estimator-class-kw] 142 | (fit ds module-kw estimator-class-kw {})) 143 | ([ds module-kw estimator-class-kw kw-args] 144 | (let [{:keys [estimator X y]} (prepare-python ds module-kw estimator-class-kw kw-args)] 145 | 146 | (if y 147 | (py. estimator fit X y) 148 | (py. estimator fit X))))) 149 | 150 | (defn fit-transform 151 | "Call the fit_transform method of a sklearn transformer, which is specified via 152 | the two keywords `module-kw` and `estimator-class-kw`. 153 | Keyword arguments can be given in a map `kw-arguments`. 154 | The data need to be given as tech.ml.dataset and will be converted to python automaticaly. 155 | The function will return the estimator and transformed data as a tech.ml.dataset 156 | " 157 | ([ds module-kw estimator-class-kw] 158 | (fit-transform ds module-kw estimator-class-kw {})) 159 | ([ds module-kw estimator-class-kw kw-args] 160 | 161 | (let [{:keys [estimator X y inference-target]} (prepare-python ds module-kw estimator-class-kw kw-args) 162 | raw-result (py. estimator fit_transform X) 163 | new-ds (raw-tf-result->ds raw-result) 164 | new-ds (if (nil? inference-target) 165 | new-ds 166 | (ds/append-columns new-ds (ds/columns inference-target)))] 167 | {:ds new-ds 168 | :estimator estimator}))) 169 | 170 | 171 | (defn predict 172 | "Calls `predict` on the given sklearn estimator object, and returns the result as a tech.ml.dataset" 173 | ([ds estimator inference-target-column-names] 174 | (let 175 | [first-target-column-name (first inference-target-column-names) 176 | _ (errors/when-not-error first-target-column-name "No inference target column name given") 177 | feature-ds (cf/feature ds) 178 | X (ds->X feature-ds) 179 | prediction (py. estimator predict X) 180 | y_hat-ds 181 | (-> 182 | (ds/->dataset { first-target-column-name prediction}) 183 | (ds/update-column first-target-column-name 184 | #(vary-meta % assoc :column-type :prediction)))] 185 | 186 | y_hat-ds)) 187 | ([ds estimator] 188 | (predict ds estimator (ds-mod/inference-target-column-names ds)))) 189 | 190 | (defn predict-proba 191 | "Calls `predict_proba` on the given sklearn estimator object, and returns the result as a tech.ml.dataset" 192 | ([ds estimator inference-target-column-names] 193 | (let 194 | [first-target-column-name (first inference-target-column-names) 195 | _ (errors/when-not-error first-target-column-name "No inference target column name given") 196 | feature-ds (cf/feature ds) 197 | X (ds->X feature-ds)] 198 | 199 | (-> 200 | (py. estimator predict_proba X) 201 | dst/tensor->dataset 202 | (ds-mod/probability-distributions->label-column first-target-column-name) 203 | (ds/update-column first-target-column-name 204 | #(vary-meta % assoc :column-type :prediction))))) 205 | ([ds estimator] 206 | (predict-proba ds estimator (ds-mod/inference-target-column-names ds)))) 207 | 208 | 209 | (defn transform 210 | "Calls `transform` on the given sklearn estimator object, and returns the result as a tech.ml.dataset" 211 | ([ds estimator] 212 | (transform ds estimator {})) 213 | ([ds estimator kw-args] 214 | (let [X (-> ds cf/feature ds->X) 215 | raw-result (py. estimator transform X) 216 | X-transformed (raw-tf-result->ds raw-result) 217 | target-ds (cf/target ds)] 218 | (if (nil? target-ds) 219 | X-transformed 220 | (ds/append-columns 221 | X-transformed 222 | (cf/target ds)))))) 223 | 224 | 225 | (defn model-attribute-names [sklearn-model] 226 | 227 | (->> (py/dir sklearn-model) 228 | (filter #(and (str/ends-with? % "_") 229 | (not (str/starts-with? % "_")))))) 230 | 231 | (defn save-py-get-attr [sklearn-model attr] 232 | ;; can fail in some cases 233 | (try (py/get-attr sklearn-model attr) 234 | (catch Exception e nil))) 235 | 236 | 237 | (defn is-object-ndarray? [pyob] 238 | (and (= (python-type pyob) :ndarray) 239 | (= (-> 240 | pyob 241 | (py/py.- dtype) 242 | (py/py.- name)) 243 | "object"))) 244 | 245 | (defn save->jvm [pyob] 246 | (if is-object-ndarray? 247 | (py/as-jvm pyob) 248 | (py/->jvm pyob))) 249 | 250 | 251 | 252 | (defn model-attributes [sklearn-model] 253 | (apply merge 254 | (map 255 | (fn [attr] 256 | (hash-map (keyword attr) 257 | (save->jvm (save-py-get-attr sklearn-model attr)))) 258 | (model-attribute-names sklearn-model)))) 259 | -------------------------------------------------------------------------------- /src/scicloj/sklearn_clj/metamorph.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-clj.metamorph 2 | (:require 3 | [libpython-clj2.python :refer [dir]] 4 | [scicloj.sklearn-clj :as sklearn])) 5 | 6 | (defn estimate 7 | ([module-kw estimator-class-kw] 8 | (estimate module-kw estimator-class-kw {})) 9 | ([module-kw estimator-class-kw kw-args] 10 | (fn [{:metamorph/keys [id data mode] :as ctx}] 11 | (case mode 12 | 13 | :fit (let [estimator (sklearn/fit data module-kw estimator-class-kw kw-args)] 14 | 15 | (assoc ctx 16 | id 17 | {:estimator estimator 18 | :attributes (sklearn/model-attributes estimator)})) 19 | :transform (assoc ctx 20 | :metamorph/data 21 | (let [estimator (get-in ctx [id :estimator]) 22 | attrs (set (dir estimator))] 23 | (if (contains? attrs "predict") 24 | (sklearn/predict data estimator) 25 | (sklearn/transform data estimator kw-args)))))))) 26 | 27 | 28 | (defn fit-transform 29 | ([module-kw estimator-class-kw] 30 | (fit-transform module-kw estimator-class-kw {})) 31 | ([module-kw estimator-class-kw kw-args] 32 | (fn [{:metamorph/keys [data id] :as ctx}] 33 | (let [{:keys [ds estimator]} (sklearn/fit-transform data module-kw estimator-class-kw kw-args)] 34 | (assoc ctx 35 | :metamorph/data ds 36 | id estimator))))) 37 | -------------------------------------------------------------------------------- /src/scicloj/sklearn_clj/ml.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-clj.ml 2 | (:require 3 | [camel-snake-kebab.core :as csk] 4 | [clojure.string :as str] 5 | [libpython-clj2.python :refer [->jvm as-jvm cfn path->py-obj py.- py.] :as py] 6 | [scicloj.metamorph.ml :as ml] 7 | [scicloj.sklearn-clj :as sklearn] 8 | [tech.v3.dataset :as ds] 9 | [tech.v3.dataset.modelling :as ds-mod])) 10 | 11 | (py/initialize!) 12 | (def pickle (py/import-module "pickle")) 13 | (def filter-map 14 | {"classifier" "classification" 15 | "regressor" "regression"}) 16 | 17 | (defn- make-train-fn [module-name estimator-class-name predict-proba?] 18 | (fn [feature-ds label-ds options] 19 | (let [target-column (first (ds/column-names label-ds)) 20 | dataset (-> (ds/append-columns feature-ds label-ds) 21 | (ds-mod/set-inference-target target-column)) 22 | model-options (dissoc options :model-type :predict-proba?) 23 | estimator (sklearn/fit dataset 24 | (str "sklearn." module-name) 25 | estimator-class-name 26 | model-options)] 27 | 28 | {:model estimator 29 | :predict-proba? (get options :predict-proba? predict-proba?) 30 | 31 | :pickled-model (-> (py. pickle dumps estimator) 32 | py/->jvm 33 | short-array) 34 | :attributes (sklearn/model-attributes estimator)}))) 35 | 36 | 37 | 38 | (defn- predict 39 | [feature-ds thawed-model {:keys [target-columns target-categorical-maps predict-proba?] :as model}] 40 | (let [prediction 41 | (if (-> model :model-data :predict-proba?) 42 | (sklearn/predict-proba feature-ds thawed-model target-columns) 43 | (sklearn/predict feature-ds thawed-model target-columns))] 44 | 45 | (-> prediction 46 | (ds/assoc-metadata target-columns :categorical-map (get target-categorical-maps (first target-columns)))))) 47 | 48 | 49 | 50 | 51 | (defn make-names [f] 52 | (let [class-name 53 | (py.- (second f) __name__) 54 | module-name 55 | (-> 56 | (py.- (second f) __module__) 57 | (str/replace-first "sklearn." ""))] 58 | {:module-name module-name :class-name class-name})) 59 | 60 | 61 | (def builtins (py/import-module "builtins")) 62 | 63 | (defn- thaw-fn 64 | [model-data] 65 | (py/py. pickle loads 66 | (py/py. builtins bytes (:pickled-model model-data)))) 67 | 68 | 69 | (defn define-estimators! [filter-s predict-proba] 70 | (let [ estimators 71 | (-> 72 | (cfn 73 | (path->py-obj "sklearn.utils.all_estimators") 74 | :type_filter filter-s) as-jvm) 75 | names 76 | (->> (map make-names estimators) 77 | (filter #(not (contains? 78 | #{"MultiOutputRegressor" "RegressorChain" "StackingRegressor" "VotingRegressor" 79 | "ClassifierChain" "MultiOutputClassifier" "OneVsOneClassifier" "OneVsRestClassifier" 80 | "OutputCodeClassifier" "StackingClassifier" "VotingClassifier" "FixedThresholdClassifier" 81 | "TunedThresholdClassifierCV"} 82 | (:class-name %)))))] 83 | 84 | (run! 85 | (fn [{:keys [module-name class-name]}] 86 | ;; (println module-name class-name) 87 | (let [estimator (sklearn/make-estimator (str "sklearn." module-name) class-name {}) 88 | params 89 | (->jvm (py. estimator get_params)) 90 | doc-string (py.- estimator __doc__)] 91 | (ml/define-model! 92 | (keyword (str "sklearn." (filter-map filter-s)) (csk/->kebab-case-string class-name)) 93 | (make-train-fn module-name class-name predict-proba) 94 | predict 95 | {:thaw-fn thaw-fn 96 | :documentation {:doc-string doc-string} 97 | :options 98 | (vec 99 | (concat 100 | [:map {:closed true}] 101 | (mapv (fn [[k v]] 102 | (vector 103 | (csk/->kebab-case-keyword k) 104 | {:optional true} 105 | :any)) 106 | params) 107 | [[:predict-proba? {:optional true} boolean?]]))}))) 108 | 109 | names))) 110 | 111 | (define-estimators! "regressor" false) 112 | (define-estimators! "classifier" true) 113 | 114 | -------------------------------------------------------------------------------- /src/scicloj/sklearn_clj/sklearn_wrapper.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-clj.sklearn-wrapper 2 | (:require 3 | [libpython-clj2.python :as py] 4 | [scicloj.metamorph.core :as mm] 5 | [scicloj.sklearn-clj] 6 | [tablecloth.api :as tc] 7 | [tech.v3.dataset :as ds])) 8 | 9 | 10 | (py/initialize!) 11 | 12 | (py/from-import sklearn.base BaseEstimator) 13 | (py/from-import sklearn.base ClassifierMixin) 14 | 15 | 16 | (defn set-column-names [ds column-name-list] 17 | (-> ds 18 | (tc/rename-columns (zipmap (tc/column-names ds) 19 | column-name-list)))) 20 | 21 | 22 | (defn pipe-fn->estimator [class-name pipe-fn X-column-names y-column-names X-categorical-maps y-categorical-maps] 23 | (let [fitted-state (atom {}) 24 | estimator-class (py/create-class 25 | class-name 26 | [BaseEstimator,ClassifierMixin] 27 | { 28 | 29 | "predict" 30 | (py/make-instance-fn 31 | (fn [this X] 32 | (let [X-ds (scicloj.sklearn-clj/ndarray->ds X) 33 | ds (-> X-ds 34 | (set-column-names X-column-names) 35 | (tc/add-column :species nil) 36 | 37 | (ds/assoc-metadata y-column-names :categorical-map y-categorical-maps)) 38 | prediction (-> 39 | (mm/transform-pipe ds pipe-fn @fitted-state) 40 | :metamorph/data 41 | :species 42 | vec)] 43 | prediction))) 44 | 45 | "fit" 46 | (py/make-instance-fn 47 | (fn [self X y] 48 | ;; (println :fit-X-shape (py/py.- X shape)) 49 | ;; (println :fit-y-shape (py/py.- y shape)) 50 | (let [X-ds (scicloj.sklearn-clj/ndarray->ds X) 51 | y-ds (scicloj.sklearn-clj/ndarray->ds y) 52 | labels 53 | (map long 54 | (-> y-ds (get 0) (distinct))) 55 | ds (-> 56 | (tc/add-column X-ds 57 | (tc/column-count X-ds) 58 | (get y-ds 0)) 59 | (set-column-names (concat X-column-names y-column-names)) 60 | (ds/assoc-metadata y-column-names 61 | :categorical-map 62 | (update-in y-categorical-maps [:lookup-table] #(select-keys % labels))))] 63 | 64 | 65 | 66 | (reset! fitted-state (mm/fit-pipe ds pipe-fn))) 67 | 68 | 69 | self))})] 70 | (estimator-class))) 71 | -------------------------------------------------------------------------------- /test/scicloj/cat_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.cat-test 2 | (:require 3 | [taoensso.nippy :as nippy] 4 | [libpython-clj2.python :as py] 5 | [tech.v3.dataset :as ds] 6 | [tech.v3.dataset.metamorph :as ds-mm] 7 | [scicloj.metamorph.core :as morph] 8 | [tech.v3.dataset.modelling :as ds-mod] 9 | [tech.v3.dataset.categorical :as ds-cat] 10 | 11 | [tech.v3.dataset.column-filters :as cf] 12 | [tablecloth.api.split :as split] 13 | [scicloj.metamorph.ml :as ml] 14 | [scicloj.metamorph.ml.loss :as loss] 15 | [scicloj.sklearn-clj.ml] 16 | [clojure.test :refer [deftest is]])) 17 | 18 | (py/initialize!) 19 | (def builtins (py/import-module "builtins")) 20 | 21 | 22 | (def pipe-fn (morph/pipeline 23 | (ds-mm/set-inference-target :species) 24 | (ds-mm/categorical->number cf/categorical) 25 | {:metamorph/id :model} 26 | (ml/model {:model-type 27 | :sklearn.classification/random-forest-classifier}))) 28 | (def ds (ds/->dataset "https://raw.githubusercontent.com/techascent/tech.ml/master/test/data/iris.csv" {:key-fn keyword})) 29 | 30 | 31 | (deftest test-categorical 32 | (let [ 33 | train-split-seq (split/split->seq ds :holdout) 34 | pipe-fn-seq [pipe-fn] 35 | evaluations (ml/evaluate-pipelines pipe-fn-seq train-split-seq loss/classification-loss :loss) 36 | best-fitted-context (-> evaluations first first :fit-ctx) 37 | best-pipe-fn (-> evaluations first first :pipe-fn) 38 | new-ds (ds/sample ds 10 {:seed 1234}) 39 | predictions 40 | (-> 41 | (best-pipe-fn 42 | (merge best-fitted-context 43 | {:metamorph/data new-ds 44 | :metamorph/mode :transform})) 45 | (:metamorph/data) 46 | (ds-mod/column-values->categorical :species))] 47 | 48 | 49 | (is (= {"versicolor" 5, "virginica" 4, "setosa" 1} 50 | (frequencies predictions))))) 51 | 52 | 53 | 54 | (deftest serialize-ctx 55 | (let [ctx 56 | (morph/fit-pipe ds pipe-fn) 57 | _ (nippy/freeze-to-file "/tmp/ctx.nippy" ctx) 58 | loaded-ctx (nippy/thaw-from-file "/tmp/ctx.nippy")] 59 | (is (= {"setosa" 50, "versicolor" 50, "virginica" 50} 60 | (-> 61 | (morph/transform-pipe ds 62 | pipe-fn 63 | loaded-ctx) 64 | :metamorph/data 65 | ds-cat/reverse-map-categorical-xforms 66 | :species 67 | frequencies))))) 68 | -------------------------------------------------------------------------------- /test/scicloj/iris_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.iris-test 2 | (:require 3 | [clojure.test :refer [deftest is]] 4 | [scicloj.metamorph.core :as mm] 5 | [scicloj.metamorph.ml :as ml] 6 | [scicloj.metamorph.ml.loss :as loss] 7 | [tech.v3.dataset :as ds] 8 | [tech.v3.dataset.metamorph :as ds-mm] 9 | [tablecloth.api :as tc] 10 | [scicloj.sklearn-clj.ml])) 11 | 12 | 13 | 14 | (def iris 15 | (-> 16 | (ds/->dataset 17 | "https://raw.githubusercontent.com/scicloj/metamorph.ml/main/test/data/iris.csv" {:key-fn keyword}))) 18 | 19 | 20 | (def pipe-fn 21 | (mm/pipeline 22 | (ds-mm/set-inference-target :species) 23 | (ds-mm/categorical->number [:species]) 24 | {:metamorph/id :model} 25 | (ml/model {:model-type :sklearn.classification/ridge-classifier 26 | :predict-proba? false}))) 27 | 28 | 29 | (def evals 30 | (ml/evaluate-pipelines [pipe-fn] 31 | (tc/split->seq iris) 32 | loss/classification-accuracy 33 | :loss)) 34 | 35 | (deftest emtric-is-good 36 | (is (< 0.5 37 | (-> evals first first :test-transform :mean)))) 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/scicloj/metamorph_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.metamorph-test 2 | (:require 3 | [clojure.test :refer [deftest is]] 4 | [libpython-clj2.python :refer [->jvm] 5 | :as py] 6 | [libpython-clj2.require :refer [require-python]] 7 | [scicloj.metamorph.core :as morph] 8 | [scicloj.metamorph.ml :as mm-ml] 9 | [scicloj.metamorph.ml :as ml] 10 | [scicloj.metamorph.ml.malli] 11 | [scicloj.sklearn-clj.metamorph :as sklearn-mm] 12 | [scicloj.sklearn-clj.ml] 13 | [tablecloth.api :as tc] 14 | [tech.v3.dataset :as ds] 15 | [tech.v3.dataset.column-filters :as ds-cf] 16 | [tech.v3.dataset.modelling :as ds-mod])) 17 | 18 | 19 | (py/initialize!) 20 | (deftest test-evaluate 21 | (let [XY (-> 22 | (tc/dataset [ [-1, -1], [-2, -1], [1, 1], [2, 1]] 23 | {:layout :as-rows}) 24 | (tc/add-column :target [1 1 2 2]) 25 | (ds-mod/set-inference-target :target)) 26 | 27 | 28 | 29 | pipeline 30 | (morph/pipeline 31 | (sklearn-mm/estimate :sklearn.preprocessing :standard-scaler) 32 | {:metamorph/id :model} 33 | (mm-ml/model {:model-type :sklearn.classification/svc 34 | :gamma "auto" 35 | :predict-proba? false}))] 36 | 37 | 38 | (is (= 1.0 39 | (-> 40 | (mm-ml/evaluate-pipelines [pipeline] [{:train XY :test XY}] scicloj.metamorph.ml.loss/classification-accuracy :loss) 41 | first 42 | first 43 | :test-transform 44 | :metric))))) 45 | 46 | (deftest test-estimate 47 | (let [pipeline 48 | (fn [ctx] 49 | (-> ctx 50 | ((fn [ctx] 51 | (assoc ctx :metamorph/data 52 | (ds-mod/set-inference-target (:metamorph/data ctx) :y)))) 53 | 54 | ((sklearn-mm/estimate :sklearn.linear-model :linear-regression)))) 55 | 56 | fitted 57 | (pipeline 58 | 59 | {:metamorph/id "1" 60 | :metamorph/mode :fit 61 | :metamorph/data 62 | (ds/->dataset {:x1 [1 1 2 2] 63 | :x2 [1 2 2 3] 64 | :y [6 8 9 11]})}) 65 | 66 | 67 | prediction 68 | (pipeline 69 | (merge fitted 70 | {:metamorph/mode :transform 71 | :metamorph/data 72 | (ds/->dataset {:x1 [3 7] 73 | :x2 [5 8] 74 | :y [0 0]})}))] 75 | 76 | 77 | (is (= [:y] 78 | (ds/column-names (ds-cf/prediction (:metamorph/data prediction))))) 79 | (is (= 16 80 | (Math/round 81 | (first (seq (get-in prediction [:metamorph/data :y])))))))) 82 | 83 | 84 | 85 | (deftest test-transform 86 | (let [pipeline 87 | (fn [ctx] 88 | (-> ctx 89 | ((sklearn-mm/fit-transform :sklearn.feature-extraction.text :Count-Vectorizer)))) 90 | 91 | fitted 92 | (pipeline 93 | 94 | {:metamorph/id "1" 95 | :metamorph/mode :fit 96 | :metamorph/data 97 | (ds/->dataset {:text ["hellow world"]})})] 98 | 99 | 100 | (is (= [1] 101 | (get-in fitted [:metamorph/data 1]))))) 102 | 103 | 104 | 105 | 106 | 107 | (deftest svm-pipe 108 | 109 | (let [XY 110 | (-> 111 | (tc/dataset [ [-1, -1], [-2, -1], [1, 1], [2, 1]] {:layout :as-rows}) 112 | (tc/add-column :target [1 1 2 2]) 113 | (ds-mod/set-inference-target :target)) 114 | 115 | pipeline 116 | (morph/pipeline 117 | (sklearn-mm/estimate :sklearn.preprocessing :standard-scaler) 118 | {:metamorph/id :model} 119 | (sklearn-mm/estimate :sklearn.svm "SVC" {:gamma "auto"})) 120 | 121 | fitted-pipeline 122 | (pipeline {:metamorph/data XY 123 | :metamorph/mode :fit}) 124 | 125 | 126 | new-data 127 | (-> 128 | (tc/dataset [ [-0.8 -1]] {:layout :as-rows}) 129 | (tc/add-column :target [nil]) 130 | (ds-mod/set-inference-target :target)) 131 | 132 | result 133 | (pipeline 134 | (merge fitted-pipeline 135 | {:metamorph/data new-data 136 | :metamorph/mode :transform}))] 137 | 138 | 139 | 140 | (is (= [1.0] (get-in result [:metamorph/data :target]))))) 141 | 142 | 143 | (deftest has-valid-options 144 | (is (= [:n-iter-no-change {:optional true} :any] 145 | (-> @ml/model-definitions* :sklearn.classification/sgd-classifier :options (nth 2))))) 146 | 147 | (comment 148 | (require-python '[numpy :as np] 149 | '[sklearn.pipeline :refer [make_pipeline]] 150 | '[sklearn.preprocessing :refer [StandardScaler]] 151 | '[sklearn.svm :refer [SVC]]) 152 | 153 | (def X (np/array [[-1 -1] [-2 -1 ] [1 1] [2 1]])) 154 | (def y (np/array [1 1 2 2])) 155 | (def clf (make_pipeline (StandardScaler) (SVC :gamma "auto"))) 156 | (py. clf fit X y) 157 | clf 158 | (->jvm 159 | (py. clf predict [[-0.8 -1]]))) 160 | 161 | 162 | -------------------------------------------------------------------------------- /test/scicloj/perf_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.perf-test 2 | (:require [clojure.test :as t] 3 | [tablecloth.api :as tc] 4 | [tech.v3.dataset.tensor :as dst] 5 | [libpython-clj2.python.np-array] 6 | [scicloj.sklearn-clj :refer [fit]] 7 | [libpython-clj2.python :as py])) 8 | (py/initialize!) 9 | (defmacro labeled-time 10 | "Evaluates expr and prints the time it took. Returns the value of 11 | expr." 12 | {:added "1.0"} 13 | [label expr] 14 | `(let [start# (. System (nanoTime)) 15 | ret# ~expr] 16 | (prn (str label " - " "elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs")) 17 | ret#)) 18 | 19 | (t/deftest train-flight-python [] 20 | (let [res 21 | (py/run-simple-string (slurp "train_delay.py")) 22 | 23 | python-time 24 | (-> res :globals (get "execution_time")) 25 | 26 | 27 | train 28 | (-> res :globals 29 | (get "tensor_train") 30 | py/->jvm 31 | dst/tensor->dataset) 32 | 33 | y 34 | (-> res :globals 35 | (get "y_train") 36 | py/->jvm) 37 | 38 | train 39 | (-> train 40 | (tc/add-column :y y) 41 | (tech.v3.dataset.modelling/set-inference-target :y)) 42 | start (System/currentTimeMillis) 43 | _ (fit train :sklearn.ensemble :GradientBoostingClassifier 44 | {:random-state 0 45 | :n-estimators 350 46 | :learning-rate 0.16}) 47 | end (System/currentTimeMillis) 48 | clojure-time (/ (- end start) 1000.0)] 49 | (println :clojure-time clojure-time) 50 | (println :python-time python-time) 51 | (t/is (< python-time 30)) 52 | (t/is (< clojure-time 30)))) 53 | -------------------------------------------------------------------------------- /test/scicloj/regression_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.regression-test 2 | 3 | (:require [clojure.set :as set] 4 | [clojure.string :as str] 5 | [clojure.test :refer [deftest is]] 6 | [scicloj.metamorph.ml.toydata :as toydata] 7 | [scicloj.metamorph.ml :as ml] 8 | [scicloj.metamorph.ml.loss :as loss] 9 | [scicloj.metamorph.core :as mm] 10 | [tablecloth.api :as tc] 11 | [scicloj.sklearn-clj :as sklearn] 12 | [scicloj.sklearn-clj.ml])) 13 | 14 | 15 | (deftest test-options-with-number 16 | (is (= "ElasticNet(alpha=1, l1_ratio=2)" 17 | (-> 18 | ( sklearn/make-estimator :sklearn.linear-model :elastic-net 19 | {:alpha 1 20 | :l1-ratio 2 }) 21 | str))) 22 | ) 23 | 24 | 25 | 26 | (defn validate-regressor-mean [model-type] 27 | (println model-type) 28 | (let [ diabetes (toydata/diabetes-ds) 29 | pipe-fn 30 | (mm/pipeline 31 | {:metamorph/id :model} 32 | (ml/model {:model-type model-type})) 33 | eval-result 34 | (ml/evaluate-pipelines [pipe-fn] 35 | (tc/split->seq diabetes) 36 | loss/rmse 37 | :loss) 38 | ] 39 | (is (< 50 40 | (-> eval-result first first :test-transform :mean))))) 41 | 42 | 43 | (deftest exercise-regressors 44 | (let [validation-results 45 | (->> 46 | (set/difference 47 | (into #{} (keys @ml/model-definitions*)) 48 | #{:sklearn.regression/multi-task-elastic-net 49 | :sklearn.regression/multi-task-lasso-cv 50 | :sklearn.regression/random-forest-regressor 51 | :sklearn.regression/isotonic-regression 52 | :sklearn.regression/multi-task-lasso 53 | :sklearn.regression/multi-task-elastic-net-cv 54 | :sklearn.regression/extra-trees-regressor 55 | :sklearn.regression/pls-canonical 56 | :sklearn.regression/quantile-regressor 57 | :sklearn.regression/cca}) 58 | 59 | 60 | (filter #(some? %)) 61 | (filter #(some? (namespace %))) 62 | (filter #(str/starts-with? (namespace %) "sklearn.regression")) 63 | (mapv validate-regressor-mean))] 64 | (is (every? 65 | true? 66 | validation-results)))) 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /test/scicloj/sklearn_clj_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-clj-test 2 | (:require 3 | [clojure.test :refer :all] 4 | [libpython-clj2.python :refer [python-type] :as py] 5 | [scicloj.metamorph.core :as mm] 6 | [scicloj.metamorph.ml :as ml] 7 | [scicloj.metamorph.ml.toydata :as toydata] 8 | [scicloj.sklearn-clj :refer :all] 9 | [scicloj.sklearn-clj.ml] 10 | [tablecloth.api :as tc] 11 | [tech.v3.dataset :as ds] 12 | [tech.v3.dataset.modelling :as ds-mod] 13 | [tech.v3.dataset.tensor :as dst] 14 | [tech.v3.datatype.functional :as f] 15 | [tech.v3.tensor :as tensor])) 16 | 17 | 18 | (py/initialize!) 19 | (def texts ["This is the first document." 20 | "This document is the second document." 21 | "And this is the third one." 22 | "Is this the first document?"]) 23 | 24 | 25 | (defn values->ds [values shape datatype] 26 | (-> 27 | (tensor/->tensor values :datatype datatype) 28 | (tensor/reshape shape) 29 | (dst/tensor->dataset))) 30 | 31 | 32 | 33 | 34 | (deftest count-vectorizer-fit-transform-with-target 35 | (let [ds (-> 36 | (ds/->dataset {:text texts 37 | :target (repeat (count texts) 5)}) 38 | (ds-mod/set-inference-target :target)) 39 | result 40 | (-> ds 41 | (fit-transform :sklearn.feature-extraction.text :Count-Vectorizer {}) 42 | :ds dst/dataset->tensor)] 43 | (is (f/equals result 44 | (tensor/->tensor 45 | [[0 1 1 1 0 0 1 0 1 5] 46 | [0 2 0 1 0 1 1 0 1 5] 47 | [1 0 0 1 1 0 1 1 1 5] 48 | [0 1 1 1 0 0 1 0 1 5]] 49 | :datatype :float64))))) 50 | 51 | 52 | 53 | (deftest count-vectorizer-fit 54 | 55 | (let [ds (ds/->dataset {:text texts}) 56 | estimator (fit ds :sklearn.feature-extraction.text :Count-Vectorizer {}) 57 | prediction (transform ds estimator {})] 58 | 59 | (is (= :count-vectorizer 60 | (python-type estimator))))) 61 | 62 | 63 | (deftest tfidf-vectorizer 64 | 65 | (let [ds (ds/->dataset {:text texts}) 66 | result 67 | (-> ds 68 | (fit-transform :sklearn.feature-extraction.text :TfidfVectorizer {}) 69 | :ds 70 | dst/dataset->tensor)] 71 | 72 | (is (f/equals result 73 | 74 | (tensor/->tensor 75 | [[ 0.000 0.4698 0.5803 0.3841 0.000 0.000 0.3841 0.000 0.3841] 76 | [ 0.000 0.6876 0.000 0.2811 0.000 0.5386 0.2811 0.000 0.2811] 77 | [0.5118 0.000 0.000 0.2671 0.5118 0.000 0.2671 0.5118 0.2671] 78 | [ 0.000 0.4698 0.5803 0.3841 0.000 0.000 0.3841 0.000 0.3841]] 79 | :datatype :float64))))) 80 | 81 | (deftest normalizer 82 | (is (f/equals 83 | (-> [[4 1 2 2] 84 | [1 3 9 3] 85 | [5 7 5 1]] 86 | (tensor/->tensor :datatype :float64) 87 | (dst/tensor->dataset) 88 | (fit-transform :sklearn.preprocessing :normalizer {}) 89 | :ds 90 | dst/dataset->tensor) 91 | 92 | (tensor/->tensor 93 | [[0.8 0.2 0.4 0.4] 94 | [0.1 0.3 0.9 0.3], 95 | [0.5 0.7 0.5 0.1]] 96 | :datatype :float64)))) 97 | 98 | (deftest normalizer-single-row 99 | (is (f/equals 100 | (-> [[4 1 2 2]] 101 | (tensor/->tensor :datatype :float64) 102 | (dst/tensor->dataset) 103 | (fit-transform :sklearn.preprocessing :normalizer {}) 104 | :ds 105 | dst/dataset->tensor) 106 | 107 | (tensor/->tensor 108 | [[0.8 0.2 0.4 0.4]] 109 | :datatype :float64)))) 110 | 111 | 112 | 113 | (deftest normalizer-single-col 114 | (is (f/equals 115 | (-> [[4] 116 | [1] 117 | [5]] 118 | (tensor/->tensor :datatype :float64) 119 | (dst/tensor->dataset) 120 | (fit-transform :sklearn.preprocessing :normalizer {}) 121 | :ds 122 | dst/dataset->tensor) 123 | 124 | (tensor/->tensor 125 | [[1] 126 | [1], 127 | [1]] 128 | :datatype :float64)))) 129 | 130 | 131 | (def n-arr-1 132 | (values->ds [32 nil 28 nil 32 nil nil 34 40] 133 | [3 3] 134 | :object)) 135 | 136 | 137 | (def n-arr-2 138 | (values->ds [6 9 nil 7 nil nil nil 8 12] 139 | [3 3] 140 | :object)) 141 | 142 | 143 | 144 | 145 | (deftest impute-1 146 | (let [imp (fit n-arr-1 :sklearn.impute :simple-imputer) 147 | imputed (transform n-arr-2 imp {})] 148 | (is (= 149 | (values->ds 150 | [6 9 34 151 | 7 33 34 152 | 32 8 12] 153 | [3 3] 154 | :float64) 155 | 156 | imputed)))) 157 | 158 | 159 | 160 | (deftest impute-2 161 | (let [{:keys [estimator ds]} (fit-transform n-arr-2 :sklearn.impute :simple-imputer)] 162 | ;; imputed (transform n-arr-2 imp {}) 163 | (is (= 164 | (values->ds 165 | [6 9 12 166 | 7 8.5 12 167 | 6.5 8 12] 168 | [3 3] 169 | :float64) 170 | 171 | ds)))) 172 | 173 | 174 | (deftest impute-3 175 | (let [estimator (fit n-arr-2 :sklearn.impute :simple-imputer) 176 | imputed (transform n-arr-2 estimator {})] 177 | ;; imputed (transform n-arr-2 imp {}) 178 | 179 | (is (= 180 | (values->ds 181 | [6 9 12 182 | 7 8.5 12 183 | 6.5 8 12] 184 | [3 3] 185 | :float64) 186 | 187 | imputed)))) 188 | 189 | 190 | 191 | 192 | 193 | (deftest model-svc-predict-proba 194 | 195 | (let [iris-split 196 | (-> 197 | (toydata/iris-ds) 198 | (tc/split->seq :holdout {:seed 1234}) 199 | first) 200 | 201 | pipe-fn 202 | (mm/pipeline 203 | {:metamorph/id :svc} 204 | (ml/model {:model-type :sklearn.classification/svc 205 | :predict-proba? true 206 | :probability true})) 207 | 208 | 209 | 210 | fitted-ctx 211 | (mm/fit-pipe 212 | (:train iris-split) 213 | pipe-fn) 214 | prediction 215 | (-> 216 | (mm/transform-pipe 217 | (:test iris-split) 218 | pipe-fn 219 | fitted-ctx) 220 | :metamorph/data)] 221 | 222 | 223 | (is (= [0 1 2 :species] (ds/column-names prediction))) 224 | (is (= 225 | [2.0 1.0 0.0] 226 | (-> prediction :species frequencies keys))))) 227 | 228 | 229 | (deftest model-svc-no-proba 230 | 231 | (let [iris-split 232 | (-> 233 | (toydata/iris-ds) 234 | (tc/split->seq :holdout {:seed 1234}) 235 | first) 236 | 237 | pipe-fn 238 | (mm/pipeline 239 | {:metamorph/id :svc} 240 | (ml/model {:model-type :sklearn.classification/svc 241 | :probability false 242 | :predict-proba? false})) 243 | ;; :probability false 244 | 245 | 246 | fitted-ctx 247 | (mm/fit-pipe 248 | (:train iris-split) 249 | pipe-fn) 250 | prediction 251 | (-> 252 | (mm/transform-pipe 253 | (:test iris-split) 254 | pipe-fn 255 | fitted-ctx) 256 | :metamorph/data)] 257 | 258 | 259 | (is (= [:species] (ds/column-names prediction))) 260 | (is (= 261 | [2.0 1.0 0.0] 262 | (-> prediction :species frequencies keys))))) 263 | 264 | 265 | (deftest C-param-does-work 266 | 267 | (is (= {"kernel" "rbf", 268 | "gamma" "scale", 269 | "degree" 3, 270 | "tol" 0.001, 271 | "shrinking" true, 272 | "C" 1.0, 273 | "max_iter" -1, 274 | "coef0" 0.0, 275 | "cache_size" 200, 276 | "verbose" false, 277 | "epsilon" 0.1} 278 | (-> 279 | (py/py. 280 | (make-estimator "sklearn.svm" "SVR" {:C 1.0 :cache-size 200}) 281 | get_params) 282 | py/->jvm)))) 283 | 284 | -------------------------------------------------------------------------------- /test/scicloj/sklearn_wrapper_test.clj: -------------------------------------------------------------------------------- 1 | (ns scicloj.sklearn-wrapper-test 2 | (:require 3 | [clojure.test :as t] 4 | [libpython-clj2.python :as py] 5 | [scicloj.metamorph.core :as mm] 6 | [scicloj.metamorph.ml :as ml] 7 | [scicloj.metamorph.ml.toydata :as toydata] 8 | [scicloj.sklearn-clj.sklearn-wrapper] 9 | [tablecloth.api :as tc] 10 | [scicloj.sklearn-clj] 11 | [scicloj.sklearn-clj.ml] 12 | [scicloj.ml.smile.classification] 13 | [tech.v3.dataset.categorical :as ds-cat] 14 | [tech.v3.dataset.column-filters :as cf] 15 | [tech.v3.dataset.metamorph :as ds-mm])) 16 | 17 | (py/initialize!) 18 | (py/from-import yellowbrick.model_selection LearningCurve) 19 | 20 | (defn fit-lc [estimator X y] 21 | (let [lc (LearningCurve estimator 22 | :train_sizes [60 70 80 90 100 110 120]) 23 | _ (py/py. lc fit X y)] 24 | lc)) 25 | 26 | 27 | 28 | (t/deftest wrap-via-lc 29 | 30 | (let [data 31 | (-> (toydata/iris-ds) 32 | (tc/shuffle {:seed 12345})) 33 | ;; (tc/select-columns [:sepal_length :sepal_wi:species]) 34 | 35 | 36 | pipe-fn 37 | (mm/pipeline 38 | (ds-mm/set-inference-target :species) 39 | (ml/model {:model-type :smile.classification/random-forest})) 40 | 41 | X (-> data 42 | (cf/feature) 43 | (scicloj.sklearn-clj/ds->X)) 44 | 45 | 46 | y (-> data 47 | (cf/target) 48 | (scicloj.sklearn-clj/ds->X)) 49 | 50 | X-column-names 51 | (-> data 52 | (cf/feature) 53 | (tc/column-names)) 54 | 55 | X-categorical-maps 56 | (-> data 57 | (cf/feature) 58 | (ds-cat/dataset->categorical-maps)) 59 | 60 | 61 | y-column-names 62 | (-> data 63 | (cf/target) 64 | (tc/column-names)) 65 | 66 | 67 | y-categorical-maps 68 | (-> data 69 | (cf/target) 70 | (ds-cat/dataset->categorical-maps) 71 | first) 72 | 73 | 74 | estimator 75 | (scicloj.sklearn-clj.sklearn-wrapper/pipe-fn->estimator 76 | "my" pipe-fn 77 | X-column-names y-column-names 78 | X-categorical-maps y-categorical-maps) 79 | 80 | lc 81 | (fit-lc estimator X y)] 82 | 83 | 84 | (t/is (= [60 70 80 90 100 110 120] 85 | (-> 86 | (py/py.- lc train_sizes_) 87 | (py/->jvm) 88 | vec))))) 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tests.edn: -------------------------------------------------------------------------------- 1 | #kaocha/v1 {} 2 | -------------------------------------------------------------------------------- /train_delay.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pandas as pd 4 | from sklearn.ensemble import GradientBoostingClassifier 5 | from sklearn.model_selection import train_test_split 6 | from sklearn.metrics import roc_auc_score 7 | import os 8 | data_train = pd.read_csv('https://gist.githubusercontent.com/behrica/8601bd8d6dfee59bd92d0cf5cc8db834/raw/bad7f3f8ef381cc3cb816ba16124d7aa7f83b930/flight_delays_train.csv') 9 | 10 | def removeC(data): 11 | return data[2:] 12 | 13 | data_train = data_train.drop(columns = ['UniqueCarrier', 'Origin', 'Dest']) 14 | data_train['dep_delayed_15min'].replace({"Y": 1, "N": 0}, inplace=True) 15 | 16 | data_train['Month'] = data_train.apply(lambda row : removeC(row['Month']), axis=1) 17 | data_train['DayofMonth'] = data_train.apply(lambda row : removeC(row['DayofMonth']), axis=1) 18 | data_train['DayOfWeek'] = data_train.apply(lambda row : removeC(row['DayOfWeek']), axis=1) 19 | data_train = data_train.apply(pd.to_numeric) 20 | reg = GradientBoostingClassifier(random_state=0, n_estimators=350, learning_rate=0.16) 21 | 22 | X_train, y_train = data_train.drop(columns=['dep_delayed_15min']).values, data_train.dep_delayed_15min.values 23 | import time 24 | start = time.time() 25 | reg.fit(X_train, y_train) 26 | end = time.time() 27 | execution_time = (end - start) 28 | tensor_train=data_train.to_numpy() 29 | --------------------------------------------------------------------------------