init commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..98a7cc1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,102 @@
+###OSX###
+
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must ends with two \r.
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+
+###Node###
+
+# Logs
+logs
+*.log
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# Deployed apps should consider commenting this line out:
+# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
+node_modules
+
+
+###Python###
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+bin/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# Rope
+.ropeproject
+
+# Django stuff:
+*.log
+*.pot
+
+# Sphinx documentation
+docs/_build/
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100755
index 0000000..80c9977
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Jessica Frazelle
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100755
index 0000000..4ccda13
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+## Random Forest
+
+A random forest classifier. A random forest is a meta estimator that fits a number of decision tree classifiers on various sub-samples of the dataset and use averaging to improve the predictive accuracy and control over-fitting.
+
+Modeled after [scikit-learn's RandomForestClassifier](http://scikit-learn.org/dev/modules/generated/sklearn.ensemble.RandomForestClassifier.html).
+
+```javascript
+var RandomForestClassifier = require('random-forest-classifier');
+
+RandomForestClassifier
+```
+
+
+### Parameters
+
+**`n_estimators`:** *integer, optional (default=10)* The number of trees in the forest.
+
+**`criterion`:** *string, optional (default=”gini”)* The function to measure the quality of a split. Supported criteria are “gini” for the Gini impurity and “entropy” for the information gain. Note: this parameter is tree-specific.
+
+**`max_features`:** *int, float, string or None, optional (default=”auto”)* The number of features to consider when looking for the best split:
+- If int, then consider max_features features at each split.
+- If float, then max_features is a percentage and int(max_features * n_features) features are considered at each split.
+- If “auto”, then max_features=sqrt(n_features).
+- If “sqrt”, then max_features=sqrt(n_features).
+- If “log2”, then max_features=log2(n_features).
+- If None, then max_features=n_features.
+Note: the search for a split does not stop until at least one valid partition of the node samples is found, even if it requires to effectively inspect more than max_features features. Note: this parameter is tree-specific.
+
+**`max_depth`:** *integer or None, optional (default=None) The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples. Ignored if max_samples_leaf is not None. Note: this parameter is tree-specific.
+
+**`min_samples_split`:** *integer, optional (default=2)* The minimum number of samples required to split an internal node. Note: this parameter is tree-specific.
+
+**`min_samples_leaf`:** *integer, optional (default=1)* The minimum number of samples in newly created leaves. A split is discarded if after the split, one of the leaves would contain less then min_samples_leaf samples. Note: this parameter is tree-specific.
+
+**`max_leaf_nodes`:** *int or None, optional (default=None)* Grow trees with max_leaf_nodes in best-first fashion. Best nodes are defined as relative reduction in impurity. If None then unlimited number of leaf nodes. If not None then max_depth will be ignored. Note: this parameter is tree-specific.
+
+**`verbose`:** *int, optional (default=0)* Controls the verbosity of the tree building process.
\ No newline at end of file
diff --git a/forest/index.js b/forest/index.js
new file mode 100755
index 0000000..502cf6b
--- /dev/null
+++ b/forest/index.js
@@ -0,0 +1,98 @@
+/*
+    A random forest classifier.
+
+    A random forest is a meta estimator that fits a number of decision tree
+    classifiers on various sub-samples of the dataset and use averaging to
+    improve the predictive accuracy and control over-fitting.
+
+    Parameters
+    ----------
+    n_estimators : integer, optional (default=10)
+        The number of trees in the forest.
+
+    criterion : string, optional (default="gini")
+        The function to measure the quality of a split. Supported criteria are
+        "gini" for the Gini impurity and "entropy" for the information gain.
+        Note: this parameter is tree-specific.
+
+    max_features : int, float, string or None, optional (default="auto")
+        The number of features to consider when looking for the best split:
+
+        - If int, then consider `max_features` features at each split.
+        - If float, then `max_features` is a percentage and
+          `int(max_features * n_features)` features are considered at each
+          split.
+        - If "auto", then `max_features=sqrt(n_features)`.
+        - If "sqrt", then `max_features=sqrt(n_features)`.
+        - If "log2", then `max_features=log2(n_features)`.
+        - If None, then `max_features=n_features`.
+
+        Note: the search for a split does not stop until at least one
+        valid partition of the node samples is found, even if it requires to
+        effectively inspect more than ``max_features`` features.
+        Note: this parameter is tree-specific.
+
+    max_depth : integer or None, optional (default=None)
+        The maximum depth of the tree. If None, then nodes are expanded until
+        all leaves are pure or until all leaves contain less than
+        min_samples_split samples.
+        Ignored if ``max_samples_leaf`` is not None.
+        Note: this parameter is tree-specific.
+
+    min_samples_split : integer, optional (default=2)
+        The minimum number of samples required to split an internal node.
+        Note: this parameter is tree-specific.
+
+    min_samples_leaf : integer, optional (default=1)
+        The minimum number of samples in newly created leaves.  A split is
+        discarded if after the split, one of the leaves would contain less then
+        ``min_samples_leaf`` samples.
+        Note: this parameter is tree-specific.
+
+    max_leaf_nodes : int or None, optional (default=None)
+        Grow trees with ``max_leaf_nodes`` in best-first fashion.
+        Best nodes are defined as relative reduction in impurity.
+        If None then unlimited number of leaf nodes.
+        If not None then ``max_depth`` will be ignored.
+        Note: this parameter is tree-specific.
+
+    verbose : int, optional (default=0)
+        Controls the verbosity of the tree building process.
+*/
+
+var async = require('async'),
+    DecisionTreeClassifier = require('../tree');
+
+var RandomForestClassifier = function(params) {
+    this.n_estimators = params.n_estimators || 10;
+    this.criterion = params.criterion || "gini";
+    this.max_features = params.max_features || "auto";
+    this.min_samples_split = params.min_samples_split || 2;
+    this.min_samples_leaf = params.min_samples_leaf || 1;
+    this.verbose = this.verbose || 0;
+};
+
+var _parallel_build_tree = function(data, features, y) {
+    return function (n, next) {
+        var tree = new DecisionTreeClassifier({});
+        var CLF = tree.fit(data, features, y);
+        next(null, CLF);
+    };
+};
+
+RandomForestClassifier.prototype = {
+    fit: function(data, features, y, cb) {
+        // initialize & fit trees
+        // this is done async because it can be independent
+        async.times(this.n_estimators, _parallel_build_tree(data, features, y), function(err, trees) {
+            if (err) { console.log(err); }
+            this.trees = trees;
+
+            cb(err, trees);
+        });
+    },
+    predict: function() {
+    }
+};
+
+module.exports = RandomForestClassifier;
diff --git a/index.js b/index.js
new file mode 100755
index 0000000..3507d2e
--- /dev/null
+++ b/index.js
@@ -0,0 +1,5 @@
+var RandomForestClassifier = require('./forest'),
+    DecisionTreeClassifier = require('./tree');
+
+module.exports.RandomForestClassifier = RandomForestClassifier;
+module.exports.DecisionTreeClassifier = DecisionTreeClassifier;
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100755
index 0000000..bdbbc7b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "random-forest-classifier",
+  "version": "0.0.1",
+  "description": "A random forest classifier. A random forest is a meta estimator that fits a number of decision tree classifiers on various sub-samples of the dataset and use averaging to improve the predictive accuracy and control over-fitting.",
+  "main": "index.js",
+  "scripts": {
+    "test": "tests/index.js"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jfrazelle/random-forest-classifier"
+  },
+  "keywords": [
+    "random forest",
+    "machine learning",
+    "classifier"
+  ],
+  "author": "Jessica Frazelle",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/jfrazelle/random-forest-classifier/issues"
+  },
+  "homepage": "https://github.com/jfrazelle/random-forest-classifier",
+  "dependencies": {
+    "async": "^0.9.0",
+    "underscore": "^1.6.0"
+  }
+}
diff --git a/tests/basic.py b/tests/basic.py
new file mode 100755
index 0000000..f299536
--- /dev/null
+++ b/tests/basic.py
@@ -0,0 +1,23 @@
+from sklearn.datasets import load_iris
+from sklearn.ensemble import RandomForestClassifier
+import pandas as pd
+import numpy as np
+
+iris = load_iris()
+df = pd.DataFrame(iris.data, columns=iris.feature_names)
+df['is_train'] = np.random.uniform(0, 1, len(df)) <= .75
+df['species'] = pd.Categorical(iris.target, iris.target_names)
+
+train, test = df[df['is_train'] == True], df[df['is_train'] == False]
+
+features = df.columns[:4]
+
+print test[features].head()
+
+clf = RandomForestClassifier(n_jobs=2)
+y, _ = pd.factorize(train['species'])
+clf.fit(train[features], y)
+
+preds = iris.target_names[clf.predict(test[features])]
+print pd.crosstab(test['species'],
+                  preds, rownames=['actual'], colnames=['preds'])
diff --git a/tests/index.js b/tests/index.js
new file mode 100755
index 0000000..836bb55
--- /dev/null
+++ b/tests/index.js
@@ -0,0 +1,58 @@
+var fs = require('fs'),
+    file = __dirname + '/iris.json',
+    RandomForestClassifier = require('../index.js').RandomForestClassifier;
+
+var testdata = [{
+    "length":6.9,
+    "width":3.1,
+    "petal.length":5.1,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":5.1,
+    "width":3.8,
+    "petal.length":1.5,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":2.3,
+    "petal.length":3.3,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":6.2,
+    "width":3.4,
+    "petal.length":5.4,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":4.9,
+    "width":3,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  }
+];
+
+
+fs.readFile(file, 'utf8', function (err, data) {
+  if (err) {
+    console.log('Error reading iris json file: ' + err);
+  }
+
+  data = JSON.parse(data);
+
+  var rf = new RandomForestClassifier({});
+
+  // find a way to make this sync
+  rf.fit(data, null, "species", function(err, trees){
+    console.log(JSON.stringify(trees, null, 4));
+
+
+  });
+});
\ No newline at end of file
diff --git a/tests/iris.json b/tests/iris.json
new file mode 100755
index 0000000..dbcc0aa
--- /dev/null
+++ b/tests/iris.json
@@ -0,0 +1,1017 @@
+[
+  {
+    "length":5.1,
+    "width":3.5,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.7,
+    "width":3.2,
+    "petal.length":1.3,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.6,
+    "width":3.1,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.6,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.4,
+    "width":3.9,
+    "petal.length":1.7,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":4.6,
+    "width":3.4,
+    "petal.length":1.4,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.4,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.4,
+    "width":2.9,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.9,
+    "width":3.1,
+    "petal.length":1.5,
+    "petal.width":0.1,
+    "species":"setosa"
+  },
+  {
+    "length":5.4,
+    "width":3.7,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.8,
+    "width":3.4,
+    "petal.length":1.6,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.8,
+    "width":3,
+    "petal.length":1.4,
+    "petal.width":0.1,
+    "species":"setosa"
+  },
+  {
+    "length":4.3,
+    "width":3,
+    "petal.length":1.1,
+    "petal.width":0.1,
+    "species":"setosa"
+  },
+  {
+    "length":5.8,
+    "width":4,
+    "petal.length":1.2,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.7,
+    "width":4.4,
+    "petal.length":1.5,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":5.4,
+    "width":3.9,
+    "petal.length":1.3,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.5,
+    "petal.length":1.4,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":5.7,
+    "width":3.8,
+    "petal.length":1.7,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":5.4,
+    "width":3.4,
+    "petal.length":1.7,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.7,
+    "petal.length":1.5,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":4.6,
+    "width":3.6,
+    "petal.length":1,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.3,
+    "petal.length":1.7,
+    "petal.width":0.5,
+    "species":"setosa"
+  },
+  {
+    "length":4.8,
+    "width":3.4,
+    "petal.length":1.9,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3,
+    "petal.length":1.6,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.4,
+    "petal.length":1.6,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":5.2,
+    "width":3.5,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.2,
+    "width":3.4,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.7,
+    "width":3.2,
+    "petal.length":1.6,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.8,
+    "width":3.1,
+    "petal.length":1.6,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.4,
+    "width":3.4,
+    "petal.length":1.5,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":5.2,
+    "width":4.1,
+    "petal.length":1.5,
+    "petal.width":0.1,
+    "species":"setosa"
+  },
+  {
+    "length":5.5,
+    "width":4.2,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.9,
+    "width":3.1,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.2,
+    "petal.length":1.2,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.5,
+    "width":3.5,
+    "petal.length":1.3,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.9,
+    "width":3.6,
+    "petal.length":1.4,
+    "petal.width":0.1,
+    "species":"setosa"
+  },
+  {
+    "length":4.4,
+    "width":3,
+    "petal.length":1.3,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.4,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.5,
+    "petal.length":1.3,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":4.5,
+    "width":2.3,
+    "petal.length":1.3,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":4.4,
+    "width":3.2,
+    "petal.length":1.3,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.5,
+    "petal.length":1.6,
+    "petal.width":0.6,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.8,
+    "petal.length":1.9,
+    "petal.width":0.4,
+    "species":"setosa"
+  },
+  {
+    "length":4.8,
+    "width":3,
+    "petal.length":1.4,
+    "petal.width":0.3,
+    "species":"setosa"
+  },
+  {
+    "length":5.1,
+    "width":3.8,
+    "petal.length":1.6,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":4.6,
+    "width":3.2,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5.3,
+    "width":3.7,
+    "petal.length":1.5,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":5,
+    "width":3.3,
+    "petal.length":1.4,
+    "petal.width":0.2,
+    "species":"setosa"
+  },
+  {
+    "length":7,
+    "width":3.2,
+    "petal.length":4.7,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":6.4,
+    "width":3.2,
+    "petal.length":4.5,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":6.9,
+    "width":3.1,
+    "petal.length":4.9,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":5.5,
+    "width":2.3,
+    "petal.length":4,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.5,
+    "width":2.8,
+    "petal.length":4.6,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":5.7,
+    "width":2.8,
+    "petal.length":4.5,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.3,
+    "width":3.3,
+    "petal.length":4.7,
+    "petal.width":1.6,
+    "species":"versicolor"
+  },
+  {
+    "length":4.9,
+    "width":2.4,
+    "petal.length":3.3,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":6.6,
+    "width":2.9,
+    "petal.length":4.6,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.2,
+    "width":2.7,
+    "petal.length":3.9,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":5,
+    "width":2,
+    "petal.length":3.5,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.9,
+    "width":3,
+    "petal.length":4.2,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":6,
+    "width":2.2,
+    "petal.length":4,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":6.1,
+    "width":2.9,
+    "petal.length":4.7,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":5.6,
+    "width":2.9,
+    "petal.length":3.6,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.7,
+    "width":3.1,
+    "petal.length":4.4,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":5.6,
+    "width":3,
+    "petal.length":4.5,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":5.8,
+    "width":2.7,
+    "petal.length":4.1,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":6.2,
+    "width":2.2,
+    "petal.length":4.5,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":5.6,
+    "width":2.5,
+    "petal.length":3.9,
+    "petal.width":1.1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.9,
+    "width":3.2,
+    "petal.length":4.8,
+    "petal.width":1.8,
+    "species":"versicolor"
+  },
+  {
+    "length":6.1,
+    "width":2.8,
+    "petal.length":4,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.3,
+    "width":2.5,
+    "petal.length":4.9,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":6.1,
+    "width":2.8,
+    "petal.length":4.7,
+    "petal.width":1.2,
+    "species":"versicolor"
+  },
+  {
+    "length":6.4,
+    "width":2.9,
+    "petal.length":4.3,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.6,
+    "width":3,
+    "petal.length":4.4,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":6.8,
+    "width":2.8,
+    "petal.length":4.8,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":6.7,
+    "width":3,
+    "petal.length":5,
+    "petal.width":1.7,
+    "species":"versicolor"
+  },
+  {
+    "length":6,
+    "width":2.9,
+    "petal.length":4.5,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":5.7,
+    "width":2.6,
+    "petal.length":3.5,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.5,
+    "width":2.4,
+    "petal.length":3.8,
+    "petal.width":1.1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.5,
+    "width":2.4,
+    "petal.length":3.7,
+    "petal.width":1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.8,
+    "width":2.7,
+    "petal.length":3.9,
+    "petal.width":1.2,
+    "species":"versicolor"
+  },
+  {
+    "length":6,
+    "width":2.7,
+    "petal.length":5.1,
+    "petal.width":1.6,
+    "species":"versicolor"
+  },
+  {
+    "length":5.4,
+    "width":3,
+    "petal.length":4.5,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":6,
+    "width":3.4,
+    "petal.length":4.5,
+    "petal.width":1.6,
+    "species":"versicolor"
+  },
+  {
+    "length":6.7,
+    "width":3.1,
+    "petal.length":4.7,
+    "petal.width":1.5,
+    "species":"versicolor"
+  },
+  {
+    "length":6.3,
+    "width":2.3,
+    "petal.length":4.4,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.6,
+    "width":3,
+    "petal.length":4.1,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.5,
+    "width":2.5,
+    "petal.length":4,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.5,
+    "width":2.6,
+    "petal.length":4.4,
+    "petal.width":1.2,
+    "species":"versicolor"
+  },
+  {
+    "length":6.1,
+    "width":3,
+    "petal.length":4.6,
+    "petal.width":1.4,
+    "species":"versicolor"
+  },
+  {
+    "length":5.8,
+    "width":2.6,
+    "petal.length":4,
+    "petal.width":1.2,
+    "species":"versicolor"
+  },
+  {
+    "length":5.6,
+    "width":2.7,
+    "petal.length":4.2,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.7,
+    "width":3,
+    "petal.length":4.2,
+    "petal.width":1.2,
+    "species":"versicolor"
+  },
+  {
+    "length":5.7,
+    "width":2.9,
+    "petal.length":4.2,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.2,
+    "width":2.9,
+    "petal.length":4.3,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":5.1,
+    "width":2.5,
+    "petal.length":3,
+    "petal.width":1.1,
+    "species":"versicolor"
+  },
+  {
+    "length":5.7,
+    "width":2.8,
+    "petal.length":4.1,
+    "petal.width":1.3,
+    "species":"versicolor"
+  },
+  {
+    "length":6.3,
+    "width":3.3,
+    "petal.length":6,
+    "petal.width":2.5,
+    "species":"virginica"
+  },
+  {
+    "length":5.8,
+    "width":2.7,
+    "petal.length":5.1,
+    "petal.width":1.9,
+    "species":"virginica"
+  },
+  {
+    "length":7.1,
+    "width":3,
+    "petal.length":5.9,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":6.3,
+    "width":2.9,
+    "petal.length":5.6,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.5,
+    "width":3,
+    "petal.length":5.8,
+    "petal.width":2.2,
+    "species":"virginica"
+  },
+  {
+    "length":7.6,
+    "width":3,
+    "petal.length":6.6,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":4.9,
+    "width":2.5,
+    "petal.length":4.5,
+    "petal.width":1.7,
+    "species":"virginica"
+  },
+  {
+    "length":7.3,
+    "width":2.9,
+    "petal.length":6.3,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.7,
+    "width":2.5,
+    "petal.length":5.8,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":7.2,
+    "width":3.6,
+    "petal.length":6.1,
+    "petal.width":2.5,
+    "species":"virginica"
+  },
+  {
+    "length":6.5,
+    "width":3.2,
+    "petal.length":5.1,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":6.4,
+    "width":2.7,
+    "petal.length":5.3,
+    "petal.width":1.9,
+    "species":"virginica"
+  },
+  {
+    "length":6.8,
+    "width":3,
+    "petal.length":5.5,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":5.7,
+    "width":2.5,
+    "petal.length":5,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":5.8,
+    "width":2.8,
+    "petal.length":5.1,
+    "petal.width":2.4,
+    "species":"virginica"
+  },
+  {
+    "length":6.4,
+    "width":3.2,
+    "petal.length":5.3,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":6.5,
+    "width":3,
+    "petal.length":5.5,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":7.7,
+    "width":3.8,
+    "petal.length":6.7,
+    "petal.width":2.2,
+    "species":"virginica"
+  },
+  {
+    "length":7.7,
+    "width":2.6,
+    "petal.length":6.9,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":6,
+    "width":2.2,
+    "petal.length":5,
+    "petal.width":1.5,
+    "species":"virginica"
+  },
+  {
+    "length":6.9,
+    "width":3.2,
+    "petal.length":5.7,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":5.6,
+    "width":2.8,
+    "petal.length":4.9,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":7.7,
+    "width":2.8,
+    "petal.length":6.7,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":6.3,
+    "width":2.7,
+    "petal.length":4.9,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.7,
+    "width":3.3,
+    "petal.length":5.7,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":7.2,
+    "width":3.2,
+    "petal.length":6,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.2,
+    "width":2.8,
+    "petal.length":4.8,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.1,
+    "width":3,
+    "petal.length":4.9,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.4,
+    "width":2.8,
+    "petal.length":5.6,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":7.2,
+    "width":3,
+    "petal.length":5.8,
+    "petal.width":1.6,
+    "species":"virginica"
+  },
+  {
+    "length":7.4,
+    "width":2.8,
+    "petal.length":6.1,
+    "petal.width":1.9,
+    "species":"virginica"
+  },
+  {
+    "length":7.9,
+    "width":3.8,
+    "petal.length":6.4,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":6.4,
+    "width":2.8,
+    "petal.length":5.6,
+    "petal.width":2.2,
+    "species":"virginica"
+  },
+  {
+    "length":6.3,
+    "width":2.8,
+    "petal.length":5.1,
+    "petal.width":1.5,
+    "species":"virginica"
+  },
+  {
+    "length":6.1,
+    "width":2.6,
+    "petal.length":5.6,
+    "petal.width":1.4,
+    "species":"virginica"
+  },
+  {
+    "length":7.7,
+    "width":3,
+    "petal.length":6.1,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":6.3,
+    "width":3.4,
+    "petal.length":5.6,
+    "petal.width":2.4,
+    "species":"virginica"
+  },
+  {
+    "length":6.4,
+    "width":3.1,
+    "petal.length":5.5,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6,
+    "width":3,
+    "petal.length":4.8,
+    "petal.width":1.8,
+    "species":"virginica"
+  },
+  {
+    "length":6.9,
+    "width":3.1,
+    "petal.length":5.4,
+    "petal.width":2.1,
+    "species":"virginica"
+  },
+  {
+    "length":6.7,
+    "width":3.1,
+    "petal.length":5.6,
+    "petal.width":2.4,
+    "species":"virginica"
+  },
+  {
+    "length":5.8,
+    "width":2.7,
+    "petal.length":5.1,
+    "petal.width":1.9,
+    "species":"virginica"
+  },
+  {
+    "length":6.8,
+    "width":3.2,
+    "petal.length":5.9,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":6.7,
+    "width":3.3,
+    "petal.length":5.7,
+    "petal.width":2.5,
+    "species":"virginica"
+  },
+  {
+    "length":6.7,
+    "width":3,
+    "petal.length":5.2,
+    "petal.width":2.3,
+    "species":"virginica"
+  },
+  {
+    "length":6.3,
+    "width":2.5,
+    "petal.length":5,
+    "petal.width":1.9,
+    "species":"virginica"
+  },
+  {
+    "length":6.5,
+    "width":3,
+    "petal.length":5.2,
+    "petal.width":2,
+    "species":"virginica"
+  },
+  {
+    "length":5.9,
+    "width":3,
+    "petal.length":5.1,
+    "petal.width":1.8,
+    "species":"virginica"
+  }
+]
\ No newline at end of file
diff --git a/tree/index.js b/tree/index.js
new file mode 100755
index 0000000..f3370d4
--- /dev/null
+++ b/tree/index.js
@@ -0,0 +1,127 @@
+/*A decision tree classifier.
+
+   Parameters
+   ----------
+   criterion : string, optional (default="entropy")
+       The function to measure the quality of a split. Supported criteria are
+       "gini" for the Gini impurity and "entropy" for the information gain.
+
+   splitter : string, optional (default="best")
+       The strategy used to choose the split at each node. Supported
+       strategies are "best" to choose the best split and "random" to choose
+       the best random split.
+
+   max_features : int, float, string or None, optional (default=None)
+       The number of features to consider when looking for the best split:
+         - If int, then consider `max_features` features at each split.
+         - If float, then `max_features` is a percentage and
+           `int(max_features * n_features)` features are considered at each
+           split.
+         - If "auto", then `max_features=sqrt(n_features)`.
+         - If "sqrt", then `max_features=sqrt(n_features)`.
+         - If "log2", then `max_features=log2(n_features)`.
+         - If None, then `max_features=n_features`.
+
+       Note: the search for a split does not stop until at least one
+       valid partition of the node samples is found, even if it requires to
+       effectively inspect more than ``max_features`` features.
+
+   max_depth : int or None, optional (default=None)
+       The maximum depth of the tree. If None, then nodes are expanded until
+       all leaves are pure or until all leaves contain less than
+       min_samples_split samples.
+       Ignored if ``max_samples_leaf`` is not None.
+
+   min_samples_split : int, optional (default=2)
+       The minimum number of samples required to split an internal node.
+
+   min_samples_leaf : int, optional (default=1)
+       The minimum number of samples required to be at a leaf node.
+
+   max_leaf_nodes : int or None, optional (default=None)
+       Grow a tree with ``max_leaf_nodes`` in best-first fashion.
+       Best nodes are defined as relative reduction in impurity.
+       If None then unlimited number of leaf nodes.
+       If not None then ``max_depth`` will be ignored.
+*/
+
+var _ = require("underscore"),
+    utils = require("../utilities");
+
+var DecisionTreeClassifier = function(params) {
+    this.criterion = params.criterion || 'entropy';
+    this.splitter = params.splitter || 'best';
+    this.min_samples_split = params.min_samples_split || 2;
+    this.min_samples_leaf = params.min_samples_leaf || 1;
+};
+
+DecisionTreeClassifier.prototype = {
+    fit: function(data, features, y) {
+        var unique_y_values = _.unique(_.pluck(data, y));
+
+        // last leaf
+        if (unique_y_values.length == 1){
+            return {
+                type: "result",
+                val: unique_y_values[0],
+                name: unique_y_values[0],
+                alias: unique_y_values[0] + utils.RID()
+            };
+        }
+
+        if (features === true){
+            // end of branch
+            // returning the most dominate feature
+            var dominate_y = utils.GetDominate(unique_y_values);
+            return {
+                type:"result",
+                val: dominate_y,
+                name: dominate_y,
+                alias: dominate_y + utils.RID()
+            };
+        }
+
+        if (!features || features.length == 0){
+            // get all the features that are not y
+            features = _.reject(_.keys(data), function(f){ return f == y; });
+        }
+
+        var best_feature = _.max(features, function(f){return utils.Gain(data, f, y); });
+
+        var feature_remains = _.without(features, best_feature);
+
+        var possibilities = _.unique(_.pluck(data, best_feature));
+
+        var tree = {
+            name: best_feature,
+            alias: best_feature + utils.RID(),
+            type: "feature"
+        };
+
+        // create the branch of the tree
+        tree.vals = _.map(possibilities, function(v){
+            var data_modified = data.filter(function(x) { return x[best_feature] == v; });
+
+            var branch = {
+                name: v,
+                alias: v + utils.RID(),
+                type: "feature_value"
+            };
+
+            // recursive create children
+            var child = new DecisionTreeClassifier({});
+            if (feature_remains.length == 0){
+                feature_remains = true;
+            }
+            branch.child = child.fit(data_modified, feature_remains, y);
+
+            return branch;
+        });
+
+        return tree;
+    },
+    predict: function(X, value) {
+    }
+};
+
+module.exports = DecisionTreeClassifier;
\ No newline at end of file
diff --git a/utilities/index.js b/utilities/index.js
new file mode 100755
index 0000000..8948fc3
--- /dev/null
+++ b/utilities/index.js
@@ -0,0 +1,52 @@
+var _ = require("underscore");
+
+var Gain = function(data, feature, y){
+    var attribute_values = _.unique(_.pluck(data, feature)),
+        entropy = Entropy(_.pluck(data, y)),
+        size = _.size(data);
+
+    var entropies = attribute_values.map(function(n){
+        var subset = data.filter(function(x){return x[feature] === n});
+        return ((subset.length/size) * Entropy(_.pluck(subset, y)));
+    });
+
+    var total_entropies =  entropies.reduce(function(a, b){ return a+b; }, 0);
+    return entropy - total_entropies;
+};
+
+var GetDominate = function(vals){
+    var v = _.sortBy(vals, function(a){
+        return _.filter(vals, function(b) {
+            return b === a;
+        }).length;
+    }).reverse()[0];
+    return v;
+}
+
+var Entropy = function(vals){
+    var unique = _.unique(vals),
+        probs = unique.map(function(x){ return Probability(x, vals); }),
+        logs = probs.map(function(p){ return -p*Log2(p); });
+
+    return logs.reduce(function(a, b){ return a+b; }, 0);
+};
+
+var Log2 = function(n){
+    return Math.log(n)/Math.log(2);
+};
+
+var Probability = function(val, vals){
+    var instances = _.filter(vals, function(x) { return x === val; }).length;
+    return instances/vals.length;
+};
+
+var RID = function(){
+    return "_r" + Math.round(Math.random()*1000000).toString();
+}
+
+module.exports.Gain = Gain;
+module.exports.GetDominate = GetDominate;
+module.exports.Entropy = Entropy;
+module.exports.Log2 = Log2;
+module.exports.Probability = Probability;
+module.exports.RID = RID;
\ No newline at end of file