Created
June 27, 2012 11:19
-
-
Save janmarek/3003446 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (ns trees.core) | |
| (require '[clojure.contrib.math :as math]) | |
| (use 'clojure.set) | |
| ; tools | |
| (defn | |
| ^{:doc "get column from 2 dimensional array" | |
| :test (fn [] | |
| (assert (= [0 1 2] (get-column [[2 0] [3 1] [1 2]] 1))) | |
| )} | |
| get-column [arr col] | |
| (map (fn [row] (nth row col)) arr) | |
| ) | |
| (defn | |
| ^{:doc "returns true if predicate aplied to any of columns returns true"} | |
| exist [fnc collection] | |
| (if (= (count collection) 0) | |
| false | |
| (if (fnc (first collection)) | |
| true | |
| (exist fnc (rest collection)) | |
| ) | |
| ) | |
| ) | |
| (defn in? | |
| "true if seq contains elm" | |
| [seq elm] | |
| (some #(= elm %) seq)) | |
| ; tree example: | |
| (def test-tree #{ | |
| {:pos 0 :func > :attr 1 :value 0.5} | |
| {:pos 1 :func < :attr 3 :value 0.2} | |
| {:pos 2 :func < :attr 2 :value 0.3} | |
| {:pos 5 :func < :attr 1 :value 0.4} | |
| }) | |
| (defn | |
| tree-positions [tree] | |
| (map (fn [a] (a :pos)) tree) | |
| ) | |
| (defn | |
| ^{:doc "get max node position from tree"} | |
| tree-max-pos [tree] | |
| (apply max (tree-positions tree)) | |
| ) | |
| (defn | |
| ^{:doc "depth of tree with n nodes, root only has depth 0" | |
| :test (fn [] | |
| (map (fn [nodes depth] | |
| (assert (= depth (tree-depth nodes))) | |
| ) [1 2 3 5 8 10 16 20] [0 1 1 2 3 3 4 4]) | |
| )} | |
| tree-depth [n] | |
| (dec (int (java.lang.Math/ceil (/ (java.lang.Math/log (+ n 1)) (java.lang.Math/log 2))))) | |
| ) | |
| (defn | |
| ^{:doc "current row of nodes indexed by 0"} | |
| current-row [position] | |
| (tree-depth (+ position 1)) | |
| ) | |
| (defn | |
| ^{:doc "gen count of nodes in row indexed by 0"} | |
| nodes-in-row [row] | |
| (math/expt 2 row) | |
| ) | |
| (defn | |
| tree-row-start [row] | |
| (dec (math/expt 2 row)) | |
| ) | |
| (defn | |
| ^{:doc "node position in row indexed by 0", | |
| :test (fn [] | |
| (assert (= 2 (tree-position-in-row 9))) | |
| )} | |
| tree-position-in-row [pos] | |
| (- pos (tree-row-start (current-row pos))) | |
| ) | |
| (defn | |
| ^{:doc "get parent index" | |
| :test (fn [] | |
| (assert (= | |
| '(nil 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9) | |
| (map tree-parent (range 0 20)) | |
| )) | |
| )} | |
| tree-parent [node] | |
| (if (= node 0) | |
| nil | |
| (+ (tree-row-start (dec (current-row node))) (int (/ (tree-position-in-row node) 2))) | |
| ) | |
| ) | |
| (defn | |
| ^{:doc "return parent node position indexes" | |
| :test (fn [] | |
| (map (fn [node-index res] | |
| (assert (= res (tree-parents node-index))) | |
| ) [0 6 17] [[] [2 0] [8 3 1 0]]) | |
| )} | |
| tree-parents [node-index] | |
| (loop [n node-index found-parents []] | |
| (let [parent (tree-parent n)] | |
| (if (nil? parent) | |
| found-parents | |
| (recur parent (conj found-parents parent)) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (do | |
| (assert (= | |
| (map tree-children [0 1 5 8]) | |
| [[1 2] [3 4] [11 12] [17 18]] | |
| )) | |
| (assert (= | |
| [5] (tree-children 2 test-tree) | |
| )) | |
| ) | |
| )} | |
| tree-children | |
| ([n] | |
| (let [ | |
| next-row-start (tree-row-start (inc (current-row n))) | |
| first-child (+ next-row-start (* (tree-position-in-row n) 2)) | |
| ] | |
| [first-child (inc first-child)] | |
| ) | |
| ) | |
| ([n tree] | |
| (into [] (intersection (set (tree-children n)) (set (tree-positions tree)))) | |
| ) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= #{3 4 6 11 12} (tree-appendable-positions test-tree))) | |
| )} | |
| tree-appendable-positions [tree] | |
| (if (empty? tree) | |
| #{0} | |
| (let [positions (tree-positions tree)] | |
| (difference (set (apply union (map tree-children positions))) positions) | |
| ) | |
| ) | |
| ) | |
| (defn | |
| ^{:doc "fetch subtree" | |
| :test (fn [] | |
| (assert (= [2 5] (tree-positions (subtree 2 test-tree)))) | |
| )} | |
| subtree [n tree] | |
| (set (filter (fn [item] | |
| (let [cur-pos (item :pos) node-parents (tree-parents cur-pos)] | |
| (or (= cur-pos n) (exist (fn [parent] (= parent n)) node-parents)) | |
| ) | |
| ) tree)) | |
| ) | |
| (defn | |
| remove-subtree [tree subtree] | |
| (difference tree subtree) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= 5 ((tree-find-by-pos test-tree 5) :pos))) | |
| )} | |
| tree-find-by-pos [tree pos] | |
| (first (filter (fn [row] (= (row :pos) pos)) tree)) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= | |
| #{2 5 6 13} | |
| (set (tree-positions (move-subtree 2 test-tree))) | |
| )) | |
| )} | |
| move-subtree [move-to subtree-set] | |
| (let [ | |
| subtree-root (apply min (tree-positions subtree-set)) | |
| root-children (tree-children subtree-root subtree-set) | |
| new-left-child (first (tree-children move-to)) | |
| new-right-child (inc new-left-child) | |
| new-root-row (merge (tree-find-by-pos subtree-set subtree-root) {:pos move-to}) | |
| ] | |
| (union #{new-root-row} (apply union (map (fn [child] | |
| (move-subtree (if (odd? child) new-left-child new-right-child) (subtree child subtree-set) | |
| )) root-children))) | |
| ) | |
| ) | |
| ; model | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= | |
| #{[0 1 3] [0 1 4] [0 2 5 11] [0 2 5 12] [0 2 6]} | |
| (model-branches test-tree) | |
| )) | |
| )} | |
| model-branches [tree] | |
| (set (map (fn [endpoint] | |
| (reverse (into [endpoint] (tree-parents endpoint))) | |
| ) (tree-appendable-positions tree))) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (and | |
| (= | |
| (list > '(nth item 1) 0.5) | |
| (create-condition (tree-find-by-pos test-tree 0) 1) | |
| ) | |
| (= | |
| (list 'not (list > '(nth item 1) 0.5)) | |
| (create-condition (tree-find-by-pos test-tree 0) 2) | |
| ) | |
| )) | |
| )} | |
| create-condition | |
| ([row next-index] | |
| (let [expr (list (row :func) (list 'nth 'item (row :attr)) (row :value))] | |
| (if (odd? next-index) expr (list 'not expr)) | |
| ) | |
| ) | |
| ([row] | |
| (create-condition row 1) | |
| ) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= | |
| (list 'and (list > '(nth item 1) 0.5) (list 'not (list < '(nth item 3) 0.2))) | |
| (create-branch-filter-condition [0 1 4] test-tree) | |
| )) | |
| )} | |
| create-branch-filter-condition [branch tree] | |
| (loop [b branch conditions []] | |
| (if (<= (count b) 1) | |
| (apply list (into ['and] conditions)) | |
| (recur | |
| (rest b) | |
| (into conditions | |
| [(create-condition (tree-find-by-pos tree (first b)) (second b))] | |
| ) | |
| ) | |
| ) | |
| ) | |
| ) | |
| (defn | |
| create-branch-filter-function [branch tree] | |
| (eval (list 'fn ['item] (create-branch-filter-condition branch tree))) | |
| ) | |
| (defn | |
| ^{:test (fn [] | |
| (assert (= | |
| {:a 1 :b 2} | |
| (classes [[0 :a] [1 :b] [2 :b]] 1) | |
| )) | |
| )} | |
| classes [data class-index] | |
| (apply merge (map (fn [cls] | |
| {cls (count (filter (fn [item] | |
| (= cls (nth item class-index)) | |
| ) data))} | |
| ) (distinct (get-column data class-index)))) | |
| ) | |
| (defn | |
| ^{:doc "vrátí třídu s největším poměrem počtu výskytů ve vyfiltrovaných datech vůči celému vzorku" | |
| :test (fn [] | |
| (let [ | |
| test-dataset { | |
| :meta { | |
| :data [0] | |
| :class 1 | |
| } | |
| :data [ | |
| [0 :a] | |
| [1 :b] | |
| [3 :b] | |
| [5 :b] | |
| ] | |
| } | |
| ] | |
| (map (fn [expected filter-cb] | |
| (assert (= expected (evaluate-class test-dataset filter-cb))) | |
| ) [:a :a :b] [ | |
| (fn [x] (< (first x) 1)) | |
| (fn [x] (< (first x) 3)) | |
| (fn [x] (> (first x) 1)) | |
| ]) | |
| ) | |
| )} | |
| evaluate-class [dataset filter-cb] | |
| (first (first (let [ | |
| data (dataset :data) | |
| class-index ((dataset :meta) :class) | |
| filtered-data (filter filter-cb data) | |
| data-classes (classes data class-index) | |
| filtered-data-classes (classes filtered-data class-index) | |
| ] | |
| (sort (fn [row1 row2] (> (second row1) (second row2))) (map (fn [cls] | |
| [cls (/ (get filtered-data-classes cls) (get data-classes cls))] | |
| ) (keys filtered-data-classes))) | |
| ))) | |
| ) | |
| (defn | |
| all-classes [tree test-dataset] | |
| (into {} (map (fn [branch] | |
| [(last branch) (evaluate-class test-dataset (create-branch-filter-function branch tree))] | |
| ) (model-branches tree))) | |
| ) | |
| (defn | |
| model-condition [row tree classes] | |
| (let [ | |
| children (tree-children (row :pos)) | |
| left-child (first children) | |
| left (if (contains? classes left-child) | |
| (get classes left-child) | |
| (model-condition (tree-find-by-pos tree left-child) tree classes) | |
| ) | |
| right-child (second children) | |
| right (if (contains? classes right-child) | |
| (get classes right-child) | |
| (model-condition (tree-find-by-pos tree right-child) tree classes) | |
| ) | |
| ] | |
| (list 'if (create-condition row) left right) | |
| ) | |
| ) | |
| (defn | |
| model-from-tree [tree test-dataset] | |
| (let [ | |
| classes (all-classes tree test-dataset) | |
| condition (model-condition (tree-find-by-pos tree 0) tree classes) | |
| ] | |
| (list 'fn ['item] condition) | |
| ) | |
| ) | |
| ; data preparation | |
| (defn | |
| ^{:doc "shuffle dataset and take 1/3 as train data and rest as test data"} | |
| divide-train-and-test-data [dataset] | |
| (let [ | |
| divide-at (/ (count dataset) 3) | |
| shuffled (shuffle dataset) | |
| ] | |
| {:train (take divide-at shuffled), :test (nthnext shuffled divide-at)} | |
| ) | |
| ) | |
| (defn | |
| ^{:doc "normalize numbers in dataset to 0.0 to 1.0 interval" | |
| :test (fn [] | |
| (assert (= | |
| '((0 1 1 1 :A) (1/2 0 0.5 1/4 :B) (1 1 0 0 :C)) | |
| (normalize-dataset [[1 2 3 8 :A] [2 0 2.5 2 :B] [3 2 2 0 :C]]) | |
| )) | |
| )} | |
| normalize-dataset [dataset] | |
| (let [ | |
| create-reduce-func (fn [comparator] | |
| (fn [item1 item2] | |
| (map (fn [a b] | |
| (if (and (number? a) (number? b)) (comparator a b) false) ; compare for numbers or return nil | |
| ) item1 item2) | |
| ) | |
| ) | |
| min-vec (reduce (create-reduce-func min) dataset) | |
| max-vec (reduce (create-reduce-func max) dataset) | |
| ] | |
| (map (fn [instance] | |
| (map (fn [cur-val min-val max-val] | |
| (if (number? cur-val) (/ (- cur-val min-val) (- max-val min-val)) cur-val) | |
| ) instance min-vec max-vec) | |
| ) dataset) | |
| ) | |
| ) | |
| ; model testing | |
| (defn | |
| ^{:doc "knows where item instance is written and looks at it" | |
| :test (fn [] | |
| (assert (= :Iris-setosa (god-classifier [5.1 3.5 1.4 0.2 :Iris-setosa]) )) | |
| )} | |
| god-classifier [instance] | |
| (last instance) | |
| ) | |
| (defn | |
| ^{:doc "returns function which returns true if classifier is correct"} | |
| classifier-comparator-factory [classifier] | |
| (fn [item] (= (classifier item) (god-classifier item))) | |
| ) | |
| (defn | |
| ^{:doc "returns numbers how many classifications were correct and how many were wrong" | |
| :test (fn [] | |
| (let [ | |
| const-classifier (fn [item] :A) | |
| dataset [[:A] [:A] [:B] [:A] [:C]] | |
| ] | |
| (assert (= [3 2] (test-model const-classifier dataset))) | |
| ) | |
| )} | |
| test-model [classifier dataset] | |
| (reduce | |
| (fn [results cur] (if (= cur true) | |
| [(+ 1 (first results)) (second results)] | |
| [(first results) (+ 1 (second results))])) | |
| [0 0] | |
| (map (classifier-comparator-factory classifier) dataset) | |
| ) | |
| ) | |
| ; genetics | |
| (defn | |
| ^{:test (fn [] | |
| (do | |
| (assert (= | |
| #{} | |
| (set (useless-nodes | |
| {1 :Iris-setosa, 2 :Iris-versicolor} | |
| [[0 1] [0 2]] | |
| )) | |
| )) | |
| (assert (= | |
| #{2 5 6 14} | |
| (set (useless-nodes | |
| {3 :Iris-setosa, 4 :Iris-virginica, 11 nil, 12 nil, 13 nil, 29 nil, 30 nil} | |
| [[0 1 3] [0 1 4] [0 2 5 11] [0 2 5 12] [0 2 6 13] [0 2 6 14 29] [0 2 6 14 30]] | |
| )) | |
| )) | |
| ) | |
| )} | |
| useless-nodes [all-classes model-branches] | |
| (let [ | |
| useless-endpoints (keys (filter (fn [[k v]] | |
| (nil? v) | |
| ) all-classes)) | |
| parents-of-useless-endpoints (distinct (into [] (apply union (map tree-parents useless-endpoints)))) | |
| ] | |
| (filter (fn [parent] ; has all endpoints useless | |
| (let [ | |
| parent-branches (filter (fn [branch] | |
| (in? branch parent) | |
| ) model-branches) | |
| parent-endpoints (map last parent-branches) | |
| ] | |
| (empty? (difference (set parent-endpoints) (set useless-endpoints))) | |
| )) parents-of-useless-endpoints) | |
| ) | |
| ) | |
| (defn | |
| ; todo should remove also nodes where all test-data goes to same branch | |
| remove-useless-nodes [tree test-dataset] | |
| (let [ | |
| useless-nodes (useless-nodes (all-classes tree test-dataset) (model-branches tree)) | |
| ] | |
| (set (filter (fn [node] | |
| (not (in? useless-nodes (node :pos))) | |
| ) tree)) | |
| ) | |
| ) | |
| (defn | |
| create-random-node [at dataset-meta] | |
| (let [ | |
| data-indexes (dataset-meta :data) | |
| func (nth [< >] (* 2 (rand))) | |
| attr (nth data-indexes (* (count data-indexes) (rand))) | |
| ] | |
| {:pos at :func func :attr attr :value (rand)} | |
| ) | |
| ) | |
| (defn | |
| create-initial-trees [n dataset-meta] | |
| (map (fn [n] | |
| (let [ | |
| node-count (+ 2 (int (* 5 (rand)))) | |
| ] | |
| (set (map (fn [node-index] | |
| (create-random-node node-index dataset-meta) | |
| ) (range 0 node-count))) | |
| ) | |
| ) (range 0 n)) | |
| ) | |
| (defn | |
| fitness [tree test-dataset] | |
| (let [ | |
| data (test-dataset :data) | |
| class-index ((test-dataset :meta) :class) | |
| model (model-from-tree tree test-dataset) | |
| correctness (test-model (eval model) data) | |
| correctness-num (/ (first correctness) (+ (first correctness) (second correctness))) | |
| classes-ct (count (distinct (get-column data class-index))) | |
| node-count (count tree) | |
| depth (inc (inc (tree-depth (apply max (tree-positions tree))))) | |
| magic-number (* correctness-num correctness-num classes-ct (/ 1 depth)) | |
| ] | |
| { | |
| :magic-number magic-number | |
| :correctness correctness-num | |
| :classes classes-ct | |
| :depth depth | |
| } | |
| ) | |
| ) | |
| (defn | |
| mutate-add [tree pos dataset-meta] | |
| (union | |
| tree | |
| #{(create-random-node pos dataset-meta)} | |
| ) | |
| ) | |
| (defn | |
| mutate-rm [tree pos] | |
| (if (not= pos 0) | |
| (remove-subtree tree (subtree pos tree)) | |
| tree | |
| ) | |
| ) | |
| (defn | |
| mutate-change-node [tree dataset-meta pos] | |
| (union | |
| (difference tree #{(tree-find-by-pos tree pos)}) | |
| #{(create-random-node pos dataset-meta)} | |
| ) | |
| ) | |
| (defn | |
| mutate-change-val [tree pos] | |
| (let [random-node (tree-find-by-pos tree pos)] | |
| (union | |
| (difference tree #{random-node}) | |
| #{(merge | |
| random-node {:value | |
| (max 0.05 (min 0.95 | |
| (* (random-node :value) (inc (rand))) | |
| )) | |
| } | |
| )} | |
| ) | |
| ) | |
| ) | |
| (defn | |
| mutate [tree dataset-meta] | |
| (let [ | |
| positions (tree-positions tree) | |
| appendable (into [] (tree-appendable-positions tree)) | |
| random-appendable (nth appendable (* (rand) (count appendable))) | |
| random-node-pos (nth positions (* (rand) (count positions))) | |
| rnd (rand) | |
| ] | |
| (cond | |
| (< rnd 0.1) (mutate-rm tree random-node-pos) | |
| (< rnd 0.25) (mutate-add tree random-appendable dataset-meta) | |
| (< rnd 0.40) (mutate-change-node tree dataset-meta random-node-pos) | |
| (< rnd 0.70) (mutate-change-val tree random-node-pos) | |
| :else tree | |
| ) | |
| ) | |
| ) | |
| (defn | |
| merge-tree [t1 t2] | |
| (let [ | |
| positions-t1 (tree-positions t1) | |
| positions-t2 (tree-positions t2) | |
| rnd-pos-1 (nth positions-t1 (* (rand) (count positions-t1))) | |
| rnd-pos-2 (nth positions-t2 (* (rand) (count positions-t2))) | |
| new-tree (if (= (count positions-t1) 1) t1 (remove-subtree t1 (subtree rnd-pos-1 t1))) | |
| appendable (into [] (tree-appendable-positions new-tree)) | |
| random-appendable (nth appendable (* (rand) (count appendable))) | |
| appended-subtree (move-subtree random-appendable (subtree rnd-pos-2 t2)) | |
| ] | |
| (union new-tree appended-subtree) | |
| ) | |
| ) | |
| (defn | |
| create-train-dataset [dataset] | |
| { | |
| :meta (dataset :meta) | |
| :data ((divide-train-and-test-data (normalize-dataset (dataset :data))) :train) | |
| } | |
| ) | |
| (defn | |
| run-genetics [treeset train-dataset] | |
| (let [ | |
| dataset-meta (train-dataset :meta) | |
| mapped (map (fn [tree] | |
| (let [optimized (remove-useless-nodes tree train-dataset)] | |
| [tree (fitness tree train-dataset)] | |
| ) | |
| ) treeset) | |
| sorted (sort (fn [[tree1 fitness1] [tree2 fitness2]] | |
| (> (fitness1 :magic-number) (fitness2 :magic-number)) | |
| ) mapped) | |
| sorted-trees (map first sorted) | |
| ct (count sorted) | |
| divide-at (/ ct 3) | |
| to-merge (take divide-at sorted-trees) | |
| to-mutate (take divide-at (nthnext sorted-trees divide-at)) | |
| to-delete (nthnext (nthnext sorted-trees divide-at) divide-at) | |
| to-merge-ct (count to-merge) | |
| to-delete-ct (count to-delete) | |
| merged (set (map (fn [i] | |
| (merge-tree | |
| (nth to-merge (* (rand) to-merge-ct)) | |
| (nth to-merge (* (rand) to-merge-ct)) | |
| ) | |
| ) (range 0 to-delete-ct))) | |
| mutated (set (map (fn [tree] | |
| (mutate tree dataset-meta) | |
| ) to-merge)) | |
| best-solution (first sorted) | |
| ret (set (union (set to-merge) mutated merged)) | |
| ] | |
| (do | |
| (println "Best solution:") | |
| (println (model-from-tree (first best-solution) train-dataset)) | |
| (println "fitness: " (second best-solution)) | |
| (println) | |
| (println "Average solution:") | |
| (println "correctness: " (/ (apply + (map (fn [[tree fit]] | |
| (fit :correctness) | |
| ) sorted)) ct)) | |
| (println "depth: " (/ (apply + (map (fn [[tree fit]] | |
| (fit :depth) | |
| ) sorted)) ct)) | |
| ret | |
| ) | |
| ) | |
| ) | |
| ; test runner | |
| (defn | |
| ^{:doc "run tests all functions"} | |
| test-all [] | |
| (map | |
| (fn [func] (println func (((meta func) :test)))) ; run tests | |
| [ | |
| #'get-column #'god-classifier #'test-model #'normalize-dataset #'tree-depth | |
| #'tree-position-in-row #'tree-parent #'tree-parents #'tree-children | |
| #'tree-appendable-positions #'subtree #'tree-find-by-pos #'move-subtree | |
| #'model-branches #'create-condition #'create-branch-filter-condition | |
| #'evaluate-class #'classes #'useless-nodes | |
| ] | |
| ) | |
| ) | |
| (test-all) | |
| ; dataset | |
| (def iris-dataset { | |
| :meta { | |
| :data [0 1 2 3] | |
| :class 4 | |
| } | |
| :data [ | |
| [5.1 3.5 1.4 0.2 :Iris-setosa] | |
| [4.9 3.0 1.4 0.2 :Iris-setosa] | |
| [4.7 3.2 1.3 0.2 :Iris-setosa] | |
| [4.6 3.1 1.5 0.2 :Iris-setosa] | |
| [5.0 3.6 1.4 0.2 :Iris-setosa] | |
| [5.4 3.9 1.7 0.4 :Iris-setosa] | |
| [4.6 3.4 1.4 0.3 :Iris-setosa] | |
| [5.0 3.4 1.5 0.2 :Iris-setosa] | |
| [4.4 2.9 1.4 0.2 :Iris-setosa] | |
| [4.9 3.1 1.5 0.1 :Iris-setosa] | |
| [5.4 3.7 1.5 0.2 :Iris-setosa] | |
| [4.8 3.4 1.6 0.2 :Iris-setosa] | |
| [4.8 3.0 1.4 0.1 :Iris-setosa] | |
| [4.3 3.0 1.1 0.1 :Iris-setosa] | |
| [5.8 4.0 1.2 0.2 :Iris-setosa] | |
| [5.7 4.4 1.5 0.4 :Iris-setosa] | |
| [5.4 3.9 1.3 0.4 :Iris-setosa] | |
| [5.1 3.5 1.4 0.3 :Iris-setosa] | |
| [5.7 3.8 1.7 0.3 :Iris-setosa] | |
| [5.1 3.8 1.5 0.3 :Iris-setosa] | |
| [5.4 3.4 1.7 0.2 :Iris-setosa] | |
| [5.1 3.7 1.5 0.4 :Iris-setosa] | |
| [4.6 3.6 1.0 0.2 :Iris-setosa] | |
| [5.1 3.3 1.7 0.5 :Iris-setosa] | |
| [4.8 3.4 1.9 0.2 :Iris-setosa] | |
| [5.0 3.0 1.6 0.2 :Iris-setosa] | |
| [5.0 3.4 1.6 0.4 :Iris-setosa] | |
| [5.2 3.5 1.5 0.2 :Iris-setosa] | |
| [5.2 3.4 1.4 0.2 :Iris-setosa] | |
| [4.7 3.2 1.6 0.2 :Iris-setosa] | |
| [4.8 3.1 1.6 0.2 :Iris-setosa] | |
| [5.4 3.4 1.5 0.4 :Iris-setosa] | |
| [5.2 4.1 1.5 0.1 :Iris-setosa] | |
| [5.5 4.2 1.4 0.2 :Iris-setosa] | |
| [4.9 3.1 1.5 0.1 :Iris-setosa] | |
| [5.0 3.2 1.2 0.2 :Iris-setosa] | |
| [5.5 3.5 1.3 0.2 :Iris-setosa] | |
| [4.9 3.1 1.5 0.1 :Iris-setosa] | |
| [4.4 3.0 1.3 0.2 :Iris-setosa] | |
| [5.1 3.4 1.5 0.2 :Iris-setosa] | |
| [5.0 3.5 1.3 0.3 :Iris-setosa] | |
| [4.5 2.3 1.3 0.3 :Iris-setosa] | |
| [4.4 3.2 1.3 0.2 :Iris-setosa] | |
| [5.0 3.5 1.6 0.6 :Iris-setosa] | |
| [5.1 3.8 1.9 0.4 :Iris-setosa] | |
| [4.8 3.0 1.4 0.3 :Iris-setosa] | |
| [5.1 3.8 1.6 0.2 :Iris-setosa] | |
| [4.6 3.2 1.4 0.2 :Iris-setosa] | |
| [5.3 3.7 1.5 0.2 :Iris-setosa] | |
| [5.0 3.3 1.4 0.2 :Iris-setosa] | |
| [7.0 3.2 4.7 1.4 :Iris-versicolor] | |
| [6.4 3.2 4.5 1.5 :Iris-versicolor] | |
| [6.9 3.1 4.9 1.5 :Iris-versicolor] | |
| [5.5 2.3 4.0 1.3 :Iris-versicolor] | |
| [6.5 2.8 4.6 1.5 :Iris-versicolor] | |
| [5.7 2.8 4.5 1.3 :Iris-versicolor] | |
| [6.3 3.3 4.7 1.6 :Iris-versicolor] | |
| [4.9 2.4 3.3 1.0 :Iris-versicolor] | |
| [6.6 2.9 4.6 1.3 :Iris-versicolor] | |
| [5.2 2.7 3.9 1.4 :Iris-versicolor] | |
| [5.0 2.0 3.5 1.0 :Iris-versicolor] | |
| [5.9 3.0 4.2 1.5 :Iris-versicolor] | |
| [6.0 2.2 4.0 1.0 :Iris-versicolor] | |
| [6.1 2.9 4.7 1.4 :Iris-versicolor] | |
| [5.6 2.9 3.6 1.3 :Iris-versicolor] | |
| [6.7 3.1 4.4 1.4 :Iris-versicolor] | |
| [5.6 3.0 4.5 1.5 :Iris-versicolor] | |
| [5.8 2.7 4.1 1.0 :Iris-versicolor] | |
| [6.2 2.2 4.5 1.5 :Iris-versicolor] | |
| [5.6 2.5 3.9 1.1 :Iris-versicolor] | |
| [5.9 3.2 4.8 1.8 :Iris-versicolor] | |
| [6.1 2.8 4.0 1.3 :Iris-versicolor] | |
| [6.3 2.5 4.9 1.5 :Iris-versicolor] | |
| [6.1 2.8 4.7 1.2 :Iris-versicolor] | |
| [6.4 2.9 4.3 1.3 :Iris-versicolor] | |
| [6.6 3.0 4.4 1.4 :Iris-versicolor] | |
| [6.8 2.8 4.8 1.4 :Iris-versicolor] | |
| [6.7 3.0 5.0 1.7 :Iris-versicolor] | |
| [6.0 2.9 4.5 1.5 :Iris-versicolor] | |
| [5.7 2.6 3.5 1.0 :Iris-versicolor] | |
| [5.5 2.4 3.8 1.1 :Iris-versicolor] | |
| [5.5 2.4 3.7 1.0 :Iris-versicolor] | |
| [5.8 2.7 3.9 1.2 :Iris-versicolor] | |
| [6.0 2.7 5.1 1.6 :Iris-versicolor] | |
| [5.4 3.0 4.5 1.5 :Iris-versicolor] | |
| [6.0 3.4 4.5 1.6 :Iris-versicolor] | |
| [6.7 3.1 4.7 1.5 :Iris-versicolor] | |
| [6.3 2.3 4.4 1.3 :Iris-versicolor] | |
| [5.6 3.0 4.1 1.3 :Iris-versicolor] | |
| [5.5 2.5 4.0 1.3 :Iris-versicolor] | |
| [5.5 2.6 4.4 1.2 :Iris-versicolor] | |
| [6.1 3.0 4.6 1.4 :Iris-versicolor] | |
| [5.8 2.6 4.0 1.2 :Iris-versicolor] | |
| [5.0 2.3 3.3 1.0 :Iris-versicolor] | |
| [5.6 2.7 4.2 1.3 :Iris-versicolor] | |
| [5.7 3.0 4.2 1.2 :Iris-versicolor] | |
| [5.7 2.9 4.2 1.3 :Iris-versicolor] | |
| [6.2 2.9 4.3 1.3 :Iris-versicolor] | |
| [5.1 2.5 3.0 1.1 :Iris-versicolor] | |
| [5.7 2.8 4.1 1.3 :Iris-versicolor] | |
| [6.3 3.3 6.0 2.5 :Iris-virginica] | |
| [5.8 2.7 5.1 1.9 :Iris-virginica] | |
| [7.1 3.0 5.9 2.1 :Iris-virginica] | |
| [6.3 2.9 5.6 1.8 :Iris-virginica] | |
| [6.5 3.0 5.8 2.2 :Iris-virginica] | |
| [7.6 3.0 6.6 2.1 :Iris-virginica] | |
| [4.9 2.5 4.5 1.7 :Iris-virginica] | |
| [7.3 2.9 6.3 1.8 :Iris-virginica] | |
| [6.7 2.5 5.8 1.8 :Iris-virginica] | |
| [7.2 3.6 6.1 2.5 :Iris-virginica] | |
| [6.5 3.2 5.1 2.0 :Iris-virginica] | |
| [6.4 2.7 5.3 1.9 :Iris-virginica] | |
| [6.8 3.0 5.5 2.1 :Iris-virginica] | |
| [5.7 2.5 5.0 2.0 :Iris-virginica] | |
| [5.8 2.8 5.1 2.4 :Iris-virginica] | |
| [6.4 3.2 5.3 2.3 :Iris-virginica] | |
| [6.5 3.0 5.5 1.8 :Iris-virginica] | |
| [7.7 3.8 6.7 2.2 :Iris-virginica] | |
| [7.7 2.6 6.9 2.3 :Iris-virginica] | |
| [6.0 2.2 5.0 1.5 :Iris-virginica] | |
| [6.9 3.2 5.7 2.3 :Iris-virginica] | |
| [5.6 2.8 4.9 2.0 :Iris-virginica] | |
| [7.7 2.8 6.7 2.0 :Iris-virginica] | |
| [6.3 2.7 4.9 1.8 :Iris-virginica] | |
| [6.7 3.3 5.7 2.1 :Iris-virginica] | |
| [7.2 3.2 6.0 1.8 :Iris-virginica] | |
| [6.2 2.8 4.8 1.8 :Iris-virginica] | |
| [6.1 3.0 4.9 1.8 :Iris-virginica] | |
| [6.4 2.8 5.6 2.1 :Iris-virginica] | |
| [7.2 3.0 5.8 1.6 :Iris-virginica] | |
| [7.4 2.8 6.1 1.9 :Iris-virginica] | |
| [7.9 3.8 6.4 2.0 :Iris-virginica] | |
| [6.4 2.8 5.6 2.2 :Iris-virginica] | |
| [6.3 2.8 5.1 1.5 :Iris-virginica] | |
| [6.1 2.6 5.6 1.4 :Iris-virginica] | |
| [7.7 3.0 6.1 2.3 :Iris-virginica] | |
| [6.3 3.4 5.6 2.4 :Iris-virginica] | |
| [6.4 3.1 5.5 1.8 :Iris-virginica] | |
| [6.0 3.0 4.8 1.8 :Iris-virginica] | |
| [6.9 3.1 5.4 2.1 :Iris-virginica] | |
| [6.7 3.1 5.6 2.4 :Iris-virginica] | |
| [6.9 3.1 5.1 2.3 :Iris-virginica] | |
| [5.8 2.7 5.1 1.9 :Iris-virginica] | |
| [6.8 3.2 5.9 2.3 :Iris-virginica] | |
| [6.7 3.3 5.7 2.5 :Iris-virginica] | |
| [6.7 3.0 5.2 2.3 :Iris-virginica] | |
| [6.3 2.5 5.0 1.9 :Iris-virginica] | |
| [6.5 3.0 5.2 2.0 :Iris-virginica] | |
| [6.2 3.4 5.4 2.3 :Iris-virginica] | |
| [5.9 3.0 5.1 1.8 :Iris-virginica] | |
| ] | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment