You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@madlib.apache.org by ri...@apache.org on 2016/02/12 19:54:20 UTC
[1/5] incubator-madlib git commit: Release: Add Apache license
headers and disclaimer
Repository: incubator-madlib
Updated Branches:
refs/heads/master b9054a48b -> 8fa2f539f
Release: Add Apache license headers and disclaimer
JIRA: MADLIB-962
- ASL for files created after the grant date are added.
- RAT checks are modified to accommodate for the new files.
- DISCLAIMER is added as the release guide requires.
Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/acb05976
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/acb05976
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/acb05976
Branch: refs/heads/master
Commit: acb059769a5d4f32aa3ec933c0a3972b034d5678
Parents: b9054a4
Author: Orhan Kislal <ok...@pivotal.io>
Authored: Wed Feb 10 14:43:48 2016 -0800
Committer: Rahul Iyer <ri...@pivotal.io>
Committed: Fri Feb 12 10:52:29 2016 -0800
----------------------------------------------------------------------
.gitignore | 1 +
DISCLAIMER | 11 ++++++++
pom.xml | 6 +----
src/ports/postgres/modules/utilities/path.py_in | 17 ++++++++++++
.../postgres/modules/utilities/path.sql_in | 18 ++++++++++++-
.../postgres/modules/utilities/test/path.sql_in | 27 ++++++++++++++++++++
.../validation/internal/cross_validation.py_in | 17 ++++++++++++
7 files changed, 91 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index c4af9f9..abfccfa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ auto
# Ignore specific generated files
/doc/design/design.pdf
+/target/rat.txt
# ctags, cscope files
/cscope.files
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/DISCLAIMER
----------------------------------------------------------------------
diff --git a/DISCLAIMER b/DISCLAIMER
new file mode 100644
index 0000000..96c0821
--- /dev/null
+++ b/DISCLAIMER
@@ -0,0 +1,11 @@
+Apache MADlib is an effort undergoing incubation at the Apache Software
+Foundation (ASF), sponsored by the Apache Incubator PMC.
+
+Incubation is required of all newly accepted projects until a further
+review indicates that the infrastructure, communications, and decision
+making process have stabilized in a manner consistent with other
+successful ASF projects.
+
+While incubation status is not necessarily a reflection of the
+completeness or stability of the code, it does indicate that the
+project has yet to be fully endorsed by the ASF.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 44ae0e5..8cc3adb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -674,10 +674,7 @@
<exclude>src/ports/postgres/modules/utilities/group_control.py_in</exclude>
<exclude>src/ports/postgres/modules/utilities/in_mem_group_control.py_in</exclude>
<exclude>src/ports/postgres/modules/utilities/math_utils.py_in</exclude>
- <exclude>src/ports/postgres/modules/utilities/path.py_in</exclude>
- <exclude>src/ports/postgres/modules/utilities/path.sql_in</exclude>
<exclude>src/ports/postgres/modules/utilities/test/drop_madlib_temp.sql_in</exclude>
- <exclude>src/ports/postgres/modules/utilities/test/path.sql_in</exclude>
<exclude>src/ports/postgres/modules/utilities/test/text_utilities.sql_in</exclude>
<exclude>src/ports/postgres/modules/utilities/text_utilities.py_in</exclude>
<exclude>src/ports/postgres/modules/utilities/text_utilities.sql_in</exclude>
@@ -689,7 +686,6 @@
<exclude>src/ports/postgres/modules/validation/cross_validation.sql_in</exclude>
<exclude>src/ports/postgres/modules/validation/cv_utils.py_in</exclude>
<exclude>src/ports/postgres/modules/validation/internal/__init__.py_in</exclude>
- <exclude>src/ports/postgres/modules/validation/internal/cross_validation.py_in</exclude>
<exclude>src/ports/postgres/modules/validation/test/cross_validation.sql_in</exclude>
<exclude>src/unexported_symbols_list.txt</exclude>
<exclude>src/utils/libstdcxx-compatibility.cpp</exclude>
@@ -710,7 +706,6 @@
<exclude>**/*.md5</exclude>
<exclude>**/*.json</exclude>
<exclude>**/*.ans</exclude>
- <exclude>**/*.sql</exclude>
<exclude>**/*.out</exclude>
<exclude>**/*.po</exclude>
<exclude>**/*.map</exclude>
@@ -727,6 +722,7 @@
<exclude>**/*.stx</exclude>
<exclude>**/*.gdb</exclude>
<exclude>**/__init__.py</exclude>
+ <exclude>**/__init__.py_in</exclude>
<exclude>**/*README*</exclude>
</excludes>
</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/src/ports/postgres/modules/utilities/path.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/utilities/path.py_in b/src/ports/postgres/modules/utilities/path.py_in
index c44055e..44b4d81 100644
--- a/src/ports/postgres/modules/utilities/path.py_in
+++ b/src/ports/postgres/modules/utilities/path.py_in
@@ -1,3 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
"""
@file pathing.py_in
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/src/ports/postgres/modules/utilities/path.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/utilities/path.sql_in b/src/ports/postgres/modules/utilities/path.sql_in
index 9ec1dd8..db06fb6 100644
--- a/src/ports/postgres/modules/utilities/path.sql_in
+++ b/src/ports/postgres/modules/utilities/path.sql_in
@@ -1,7 +1,23 @@
/* ----------------------------------------------------------------------- */
/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
*
- * @file pathing.sql_in
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * @file path.sql_in
*
* @brief SQL functions for pathing functions
* @date Sep 2015
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/src/ports/postgres/modules/utilities/test/path.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/utilities/test/path.sql_in b/src/ports/postgres/modules/utilities/test/path.sql_in
index 09d76a4..44d89c8 100644
--- a/src/ports/postgres/modules/utilities/test/path.sql_in
+++ b/src/ports/postgres/modules/utilities/test/path.sql_in
@@ -1,3 +1,30 @@
+/* ----------------------------------------------------------------------- */
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * @file path.sql_in
+ *
+ * @brief SQL functions for pathing functions
+ * @date Sep 2015
+ *
+ */
+/* ----------------------------------------------------------------------- */
+
DROP TABLE IF EXISTS weblog, path_output, path_output_rows CASCADE;
CREATE TABLE weblog (event_timestamp TIMESTAMP,
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/acb05976/src/ports/postgres/modules/validation/internal/cross_validation.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/validation/internal/cross_validation.py_in b/src/ports/postgres/modules/validation/internal/cross_validation.py_in
index 2dc6c5f..8b361f2 100644
--- a/src/ports/postgres/modules/validation/internal/cross_validation.py_in
+++ b/src/ports/postgres/modules/validation/internal/cross_validation.py_in
@@ -1,3 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
import plpy
from validation.cv_utils import __cv_produce_col_name_string as _cv_col_string
from validation.cv_utils import __cv_validation_rows as _cv_validation_rows
[3/5] incubator-madlib git commit: SVM: Add Gaussian Kernel
Posted by ri...@apache.org.
SVM: Add Gaussian Kernel
JIRA: MADLIB-937, MADLIB-958
This implements explicit random feature mapping described by Rahimi and
Recht. A few distributed random matrix generation utilities used by
the transformation process are added to the MADlib Matrix module.
The commit provides two forms of kernel transformation:
- in-memory transformation, applied to problems where the
resultant model fits in the Postgres 1GB limit
- out-of-memory transformation, where the random transformation matrix
is stored in a distributed table.
Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/9b012604
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/9b012604
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/9b012604
Branch: refs/heads/master
Commit: 9b01260439e45ee931bf9c88a59b2a5f3686e6ba
Parents: a62eb6f
Author: Xiaocheng Tang <xi...@gmail.com>
Authored: Tue Dec 8 23:30:37 2015 -0800
Committer: Rahul Iyer <ri...@pivotal.io>
Committed: Fri Feb 12 10:53:35 2016 -0800
----------------------------------------------------------------------
methods/array_ops/src/pg_gp/array_ops.c | 43 ++
methods/array_ops/src/pg_gp/array_ops.sql_in | 16 +-
src/modules/linalg/matrix_ops.cpp | 88 +++-
src/modules/linalg/matrix_ops.hpp | 4 +
.../postgres/modules/linalg/matrix_ops.py_in | 73 ++++
.../postgres/modules/linalg/matrix_ops.sql_in | 120 ++++++
.../modules/svm/kernel_approximation.py_in | 404 +++++++++++++++++++
src/ports/postgres/modules/svm/svm.py_in | 335 +++++++++++++--
src/ports/postgres/modules/svm/svm.sql_in | 353 +++++++++++++---
.../postgres/modules/svm/test/linear_svm.sql_in | 129 +++++-
10 files changed, 1456 insertions(+), 109 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/methods/array_ops/src/pg_gp/array_ops.c
----------------------------------------------------------------------
diff --git a/methods/array_ops/src/pg_gp/array_ops.c b/methods/array_ops/src/pg_gp/array_ops.c
index cd2bfd2..57fd694 100644
--- a/methods/array_ops/src/pg_gp/array_ops.c
+++ b/methods/array_ops/src/pg_gp/array_ops.c
@@ -62,6 +62,8 @@ static inline Datum average_finalize(Datum elt,int size,Oid element_type);
static inline Datum average_root_finalize(Datum elt,int size,Oid element_type);
static inline Datum value_index_finalize(void *mid_result,int size,Oid element_type);
+static inline Datum element_cos(Datum element, Oid elt_type, Datum result,
+ Oid result_type, Datum opt_elt, Oid opt_type);
static inline Datum element_add(Datum element, Oid elt_type, Datum result,
Oid result_type, Datum opt_elt, Oid opt_type);
static inline Datum element_sub(Datum element, Oid elt_type, Datum result,
@@ -110,6 +112,7 @@ static inline Datum element_op(Datum element, Oid elt_type, Datum result,
Oid result_type, Datum opt_elt, Oid opt_type,
float8 (*op)(float8, float8, float8));
+static inline float8 float8_cos(float8 op1, float8 op2, float8 opt_op);
static inline float8 float8_add(float8 op1, float8 op2, float8 opt_op);
static inline float8 float8_sub(float8 op1, float8 op2, float8 opt_op);
static inline float8 float8_mult(float8 op1, float8 op2, float8 opt_op);
@@ -134,6 +137,15 @@ static inline float8 float8_sum_sqr(float8 op1, float8 op2, float8 opt_op);
static
inline
float8
+float8_cos(float8 op1, float8 op2, float8 opt_op){
+ (void) op2;
+ (void) opt_op;
+ return cos(op1);
+}
+
+static
+inline
+float8
float8_add(float8 op1, float8 op2, float8 opt_op){
(void) op2;
return op1 + opt_op;
@@ -824,6 +836,25 @@ array_fill(PG_FUNCTION_ARGS){
}
/*
+ * This function apply cos function to each element.
+ */
+PG_FUNCTION_INFO_V1(array_cos);
+Datum
+array_cos(PG_FUNCTION_ARGS){
+ if (PG_ARGISNULL(0)) { PG_RETURN_NULL(); }
+
+ ArrayType *v1 = PG_GETARG_ARRAYTYPE_P(0);
+ Oid element_type = ARR_ELEMTYPE(v1);
+ Datum v2 = float8_datum_cast(0, element_type);
+
+ ArrayType *res = General_Array_to_Array(v1, v2, element_cos);
+
+ PG_FREE_IF_COPY(v1, 0);
+
+ PG_RETURN_ARRAYTYPE_P(res);
+}
+
+/*
* This function multiplies the specified value to each element.
*/
PG_FUNCTION_INFO_V1(array_scalar_mult);
@@ -1339,6 +1370,17 @@ element_set(Datum element, Oid elt_type, Datum result,
}
/*
+ * Assign result to be cos(elt1).
+ */
+static
+inline
+Datum
+element_cos(Datum element, Oid elt_type, Datum result,
+ Oid result_type, Datum opt_elt, Oid opt_type){
+ return element_op(element, elt_type, result, result_type, opt_elt, opt_type, float8_cos);
+}
+
+/*
* Assign result to be (elt1 + elt2).
*/
static
@@ -1929,3 +1971,4 @@ General_Array_to_Array(
return pgarray;
}
+/******* internal functions ********/
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/methods/array_ops/src/pg_gp/array_ops.sql_in
----------------------------------------------------------------------
diff --git a/methods/array_ops/src/pg_gp/array_ops.sql_in b/methods/array_ops/src/pg_gp/array_ops.sql_in
index 1af49b1..70de776 100644
--- a/methods/array_ops/src/pg_gp/array_ops.sql_in
+++ b/methods/array_ops/src/pg_gp/array_ops.sql_in
@@ -478,6 +478,17 @@ LANGUAGE C IMMUTABLE
m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
/**
+ * @brief This function takes an array as the input and apply cos function element-wise, returning the resulting array. It requires that all the values are NON-NULL. Return type is the same as the input type.
+ * @param x Array x
+ * @returns Array with each element of cos(x).
+ *
+ */
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.array_cos(x anyarray) RETURNS anyarray
+AS 'MODULE_PATHNAME', 'array_cos'
+LANGUAGE C IMMUTABLE
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+/**
* @brief This function takes an array as the input and executes element-wise multiplication by the scalar provided as the second argument, returning the resulting array. It requires that all the values are NON-NULL. Return type is the same as the input type.
* @param x Array x
* @param k Scalar
@@ -549,12 +560,12 @@ m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
* @brief This function takes an array and a float8 as the input and finds power of each element in the array, returning the resulting array. It requires that all the values are NON-NULL.
*
* @param x Array x
- * @param y Desired power
+ * @param y Desired power
* @returns Power of y for all elements of x.
*
*/
DROP FUNCTION IF EXISTS MADLIB_SCHEMA.array_pow(x anyarray, y anyelement) CASCADE;
-CREATE FUNCTION MADLIB_SCHEMA.array_pow(x anyarray, y anyelement) RETURNS anyarray
+CREATE FUNCTION MADLIB_SCHEMA.array_pow(x anyarray, y anyelement) RETURNS anyarray
AS 'MODULE_PATHNAME', 'array_pow'
LANGUAGE C IMMUTABLE
m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
@@ -610,3 +621,4 @@ CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.array_contains_null(x anyarray) RETURNS
AS 'MODULE_PATHNAME', 'array_contains_null' LANGUAGE C IMMUTABLE STRICT
m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+/* Internal functions */
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/modules/linalg/matrix_ops.cpp
----------------------------------------------------------------------
diff --git a/src/modules/linalg/matrix_ops.cpp b/src/modules/linalg/matrix_ops.cpp
index 66e90c4..c6f9286 100644
--- a/src/modules/linalg/matrix_ops.cpp
+++ b/src/modules/linalg/matrix_ops.cpp
@@ -1,5 +1,4 @@
/* ----------------------------------------------------------------------- *//**
- *
* @file matrix_ops.cpp
*
* @date May 8, 2013
@@ -13,6 +12,11 @@
#include <algorithm>
#include <functional>
#include <numeric>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/normal_distribution.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/generator_iterator.hpp>
+#include <boost/random/linear_congruential.hpp>
#include "matrix_ops.hpp"
namespace madlib {
@@ -26,7 +30,6 @@ using madlib::dbconnector::postgres::madlib_construct_md_array;
// Use Eigen
using namespace dbal::eigen_integration;
-
typedef struct __type_info{
Oid oid;
int16_t len;
@@ -225,6 +228,87 @@ AnyType rand_vector::run(AnyType & args)
return r;
}
+AnyType normal_vector::run(AnyType & args)
+{
+ int dim = args[0].getAs<int>();
+ double mu = args[1].getAs<double>();
+ double sigma = args[2].getAs<double>();
+ int seed = args[3].getAs<int>();
+
+ if (dim < 1) {
+ throw std::invalid_argument("invalid argument - dim should be positive");
+ }
+ MutableArrayHandle<double> r = madlib_construct_array(
+ NULL, dim, FLOAT8TI.oid, FLOAT8TI.len, FLOAT8TI.byval, FLOAT8TI.align);
+
+ boost::minstd_rand generator(seed);
+ boost::normal_distribution<> nd_dist(mu,sigma);
+ boost::variate_generator<boost::minstd_rand&, boost::normal_distribution<> > nd(generator, nd_dist);
+
+ for (int i = 0; i < dim; i++){
+ *(r.ptr() + i) = (double)nd();
+ }
+ return r;
+}
+
+AnyType uniform_vector::run(AnyType & args)
+{
+ int dim = args[0].getAs<int>();
+ double min_ = args[1].getAs<double>();
+ double max_ = args[2].getAs<double>();
+ int seed = args[3].getAs<int>();
+
+ if (dim < 1) {
+ throw std::invalid_argument("invalid argument - dim should be positive");
+ }
+ MutableArrayHandle<double> r = madlib_construct_array(
+ NULL, dim, FLOAT8TI.oid, FLOAT8TI.len, FLOAT8TI.byval, FLOAT8TI.align);
+
+ boost::minstd_rand generator(seed);
+ boost::uniform_real<> uni_dist(min_,max_);
+ boost::variate_generator<boost::minstd_rand&, boost::uniform_real<> > uni(generator, uni_dist);
+
+ for (int i = 0; i < dim; i++){
+ *(r.ptr() + i) = (double)uni();
+ }
+ return r;
+}
+
+AnyType matrix_vec_mult_in_mem_2d::run(AnyType & args){
+ MappedColumnVector vec = args[0].getAs<MappedColumnVector>();
+ MappedMatrix mat = args[1].getAs<MappedMatrix>();
+
+ // Note mat is constructed in the column-first order
+ // which means that mat is actually transposed
+ if(vec.size() != mat.cols()){
+ throw std::invalid_argument(
+ "dimensions mismatch: vec.size() != matrix.rows()");
+ };
+
+ // trans(vec) * trans(mat) = mat * vec
+ Matrix r = mat * vec;
+ ColumnVector v = r.col(0);
+ return v;
+}
+
+AnyType matrix_vec_mult_in_mem_1d::run(AnyType & args){
+ MappedColumnVector vec1 = args[0].getAs<MappedColumnVector>();
+ // matrix stored as a 1-d array
+ MappedColumnVector vec2 = args[1].getAs<MappedColumnVector>();
+
+ if(vec2.size() % vec1.size() != 0){
+ throw std::invalid_argument(
+ "dimensions mismatch: matrix.size() is not multiples of vec.size()");
+ };
+
+ MappedMatrix mat;
+ // the rebinding happens in column-major
+ mat.rebind(vec2.memoryHandle(), vec1.size(), vec2.size()/vec1.size());
+ Matrix r = trans(mat) * vec1;
+ ColumnVector v = r.col(0);
+ return v;
+}
+
AnyType rand_block::run(AnyType & args)
{
int row_dim = args[0].getAs<int>();
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/modules/linalg/matrix_ops.hpp
----------------------------------------------------------------------
diff --git a/src/modules/linalg/matrix_ops.hpp b/src/modules/linalg/matrix_ops.hpp
index dc94fb9..2fe8452 100644
--- a/src/modules/linalg/matrix_ops.hpp
+++ b/src/modules/linalg/matrix_ops.hpp
@@ -15,5 +15,9 @@ DECLARE_UDF(linalg, matrix_mem_sum_sfunc)
DECLARE_UDF(linalg, rand_block)
DECLARE_UDF(linalg, rand_vector)
+DECLARE_UDF(linalg, uniform_vector)
+DECLARE_UDF(linalg, normal_vector)
+DECLARE_UDF(linalg, matrix_vec_mult_in_mem_2d)
+DECLARE_UDF(linalg, matrix_vec_mult_in_mem_1d)
DECLARE_SR_UDF(linalg, row_split)
DECLARE_SR_UDF(linalg, unnest_block)
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/linalg/matrix_ops.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/linalg/matrix_ops.py_in b/src/ports/postgres/modules/linalg/matrix_ops.py_in
index daba059..12d8cd8 100644
--- a/src/ports/postgres/modules/linalg/matrix_ops.py_in
+++ b/src/ports/postgres/modules/linalg/matrix_ops.py_in
@@ -5,6 +5,7 @@
import plpy
import sys
+from random import randint
from utilities.utilities import __mad_version
from utilities.utilities import extract_keyvalue_params
@@ -3085,3 +3086,75 @@ def matrix_ones(schema_madlib, row_dim, col_dim, matrix_out, out_args):
""" Create a row_dim by col_dim matrix with each element set to 1.
"""
_matrix_create_scalar(schema_madlib, row_dim, col_dim, matrix_out, out_args, 1)
+
+
+def matrix_random(schema_madlib, distribution, row_dim, col_dim,
+ in_args, matrix_out, out_args):
+ """ Create a row_dim by col_dim random matrix from distribution.
+ """
+ _validate_output_table(matrix_out)
+ _assert(row_dim > 0 and col_dim > 0,
+ "Matrix error: Invalid dimensions for input matrices: {0} x {1}".
+ format(row_dim, col_dim))
+
+ out_args = parse_matrix_args(
+ out_args, in_default_args={'row': 'row', 'col': 'col', 'val': 'val'})
+
+ distribution = 'uniform' if not distribution else distribution.lower()
+ supported_dist = ['uniform', 'normal']
+ try:
+ distribution = next(x for x in supported_dist
+ if x.startswith(distribution))
+ except StopIteration:
+ # next() returns a StopIteration if no element found
+ plpy.error("Matrix Error: Invalid distribution: "
+ "{0}. Supported distribution are ({1})"
+ .format(distribution, ','.join(sorted(supported_dist))))
+
+ in_args_default = {
+ 'seed': randint(1, 1000),
+ 'mu': 0,
+ 'sigma': 1,
+ 'min_a': 0,
+ 'max_b': 1}
+
+ in_args_types = {
+ 'seed': int,
+ 'mu': float,
+ 'sigma': float,
+ 'min_a': float,
+ 'max_b': float}
+
+ in_args_vals = extract_keyvalue_params(in_args,
+ in_args_types,
+ in_args_default)
+
+ if distribution == 'normal':
+ random_row = ('{schema_madlib}.__normal_vector({size},'
+ '{mu},{sigma},{seed}+row)'
+ .format(size=col_dim,
+ mu=in_args_vals['mu'],
+ sigma=in_args_vals['sigma'],
+ seed=in_args_vals['seed'],
+ schema_madlib=schema_madlib))
+ elif distribution == 'uniform':
+ random_row = ('{schema_madlib}.__uniform_vector({size},'
+ '{a},{b},{seed}+row)'
+ .format(size=col_dim,
+ a=in_args_vals['min_a'],
+ b=in_args_vals['max_b'],
+ seed=in_args_vals['seed'],
+ schema_madlib=schema_madlib))
+
+ plpy.execute("""
+ CREATE TABLE {matrix_out}
+ m4_ifdef(`__POSTGRESQL__', `',
+ `WITH (APPENDONLY=TRUE,COMPRESSTYPE=QUICKLZ)') AS
+ SELECT
+ row as {out_args[row]},
+ {random_row} as {out_args[val]}
+ FROM
+ generate_series(1, {row_dim}) as row
+ m4_ifdef(`__POSTGRESQL__', `',
+ `DISTRIBUTED BY ({out_args[row]})')
+ """.format(**locals()))
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/linalg/matrix_ops.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/linalg/matrix_ops.sql_in b/src/ports/postgres/modules/linalg/matrix_ops.sql_in
index bddecc1..f74dd8e 100644
--- a/src/ports/postgres/modules/linalg/matrix_ops.sql_in
+++ b/src/ports/postgres/modules/linalg/matrix_ops.sql_in
@@ -2361,6 +2361,45 @@ m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `CONTAINS SQL', `');
-------------------------------------------------------------------------
/**
+ * @brief Initializes matrix with random distribution. It requires that all the values are NON-NULL.
+ * @param distribution Name of the distribution to use (normal or uniform)
+ * @param row_dim Name of the column containing the row index for the one matrix
+ * @param col_dim Name of the column containing the column index for the one matrix
+ * @param matrix_out Name of the table where to output the result matrix
+ * @returns Name of the table containing the result matrix
+ *
+ */
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.matrix_random
+(
+ distribution TEXT,
+ row_dim INTEGER,
+ col_dim INTEGER,
+ in_args TEXT,
+ matrix_out TEXT,
+ out_args TEXT
+)
+RETURNS MADLIB_SCHEMA.matrix_result AS $$
+ PythonFunctionBodyOnly(`linalg', `matrix_ops')
+ matrix_ops.matrix_random(schema_madlib, distribution,
+ row_dim, col_dim, in_args, matrix_out, out_args)
+ return [matrix_out]
+$$ LANGUAGE plpythonu
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA', `');
+
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.matrix_random
+(
+ row_id INTEGER,
+ col_id INTEGER,
+ matrix_out TEXT
+)
+RETURNS MADLIB_SCHEMA.matrix_result AS $$
+ SELECT MADLIB_SCHEMA.matrix_random('uniform', $1, $2, ''::TEXT, $3, ''::TEXT)
+$$ LANGUAGE SQL
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA', `');
+
+/**
* @brief Initializes matrix with ones. It requires that all the values are NON-NULL.
* @param row_dim Name of the column containing the row index for the one matrix
* @param col_dim Name of the column containing the column index for the one matrix
@@ -2897,6 +2936,87 @@ m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `CONTAINS SQL', `');
/* Internal functions */
+/*
+ * @brief In-memory multiplication of a vector with a matrix
+ * @param vec a 1 x r vector
+ * @param mat a r x n matrix
+ * @return vec * mat
+ */
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.__matrix_vec_mult_in_mem(
+ vector FLOAT8[],
+ matrix FLOAT8[][]
+)
+RETURNS FLOAT8[]
+AS 'MODULE_PATHNAME', 'matrix_vec_mult_in_mem_2d'
+LANGUAGE C STRICT
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+/*
+ * @brief In-memory broadcast multiplication of a vector with a vector
+ * @param vec1 a vector with r elements
+ * @param vec2 a vector with multiples (n) of r elements
+ * @note first cast vec2 to r x n matrix mat in column-major, then return trans(mat) * vec1
+ */
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.__matrix_vec_mult_in_mem(
+ vector FLOAT8[],
+ matrix FLOAT8[]
+)
+RETURNS FLOAT8[]
+AS 'MODULE_PATHNAME', 'matrix_vec_mult_in_mem_1d'
+LANGUAGE C STRICT
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.__uniform_vector
+(
+ dim INTEGER,
+ a FLOAT8,
+ b FLOAT8,
+ seed INTEGER
+)
+RETURNS FLOAT8[]
+AS 'MODULE_PATHNAME', 'uniform_vector'
+LANGUAGE C STRICT
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.__uniform_vector
+(
+ dim INTEGER,
+ a FLOAT8,
+ b FLOAT8
+)
+RETURNS FLOAT8[] AS $$
+ SELECT MADLIB_SCHEMA.__uniform_vector($1, $2, $3, 42::INTEGER)
+$$ LANGUAGE SQL
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA', `');
+
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.__normal_vector
+(
+ dim INTEGER,
+ mu FLOAT8,
+ sigma FLOAT8,
+ seed INTEGER
+)
+RETURNS FLOAT8[]
+AS 'MODULE_PATHNAME', 'normal_vector'
+LANGUAGE C STRICT
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+CREATE OR REPLACE FUNCTION
+MADLIB_SCHEMA.__normal_vector
+(
+ dim INTEGER,
+ mu FLOAT8,
+ sigma FLOAT8
+)
+RETURNS FLOAT8[] AS $$
+ SELECT MADLIB_SCHEMA.__normal_vector($1, $2, $3, 42::INTEGER)
+$$ LANGUAGE SQL
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA', `');
+
+
CREATE OR REPLACE FUNCTION
MADLIB_SCHEMA.__rand_vector
(
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/svm/kernel_approximation.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/kernel_approximation.py_in b/src/ports/postgres/modules/svm/kernel_approximation.py_in
new file mode 100644
index 0000000..2fe2318
--- /dev/null
+++ b/src/ports/postgres/modules/svm/kernel_approximation.py_in
@@ -0,0 +1,404 @@
+from __future__ import division
+
+import plpy
+
+from utilities.utilities import unique_string
+from utilities.utilities import extract_keyvalue_params
+from utilities.utilities import num_features
+
+from math import sqrt
+from math import pi
+
+
+class GaussianKernelBase(object):
+ """docstring for gaussianKernel"""
+ def __init__(self, schema_madlib, gamma, n_components, random_state,
+ random_weights, random_offset, id_col, val_col,
+ orig_data, **kwargs):
+ self.kernel_func = 'gaussian'
+ self.gamma = gamma
+ self.n_components = n_components
+ # int32 seed used by boost::minstd_rand
+ self.random_state = random_state
+ # random operators
+ self.rd_weights = random_weights
+ self.rd_offset = random_offset
+ # val column in random operators
+ self.rd_val = val_col
+ # id column in random operators
+ self.rd_id = id_col
+ self.transformed_table = dict()
+ self.original_table = dict()
+ # indicate whether rd_weights and rd_offset is view or table
+ # store the original data table name if they are view
+ # None if they are table
+ self.orig_data = orig_data
+ self.schema_madlib = schema_madlib
+ if self.rd_offset is not None:
+ self.n_components = num_features(self.rd_offset, self.rd_val)
+
+ def _random_weights(self, row_dim, col_dim, rd_id, rd_val):
+ rd_weights = unique_string(desp='random_weights')
+ sigma = sqrt(2*self.gamma)
+ plpy.execute("""
+ drop table if exists {rd_weights};
+ select {self.schema_madlib}.matrix_random(
+ 'normal',{row_dim},{col_dim},
+ 'mu=0, sigma={sigma}, seed={self.random_state}',
+ '{rd_weights}','row={rd_id}, val={rd_val}');
+ """.format(**locals()))
+ return rd_weights
+
+ def _random_offsets(self, row_dim, col_dim, rd_id, rd_val):
+ rd_offset = unique_string(desp='random_offsets')
+ max_b = 2*pi
+ plpy.execute("""
+ drop table if exists {rd_offset};
+ select {self.schema_madlib}.matrix_random(
+ 'uniform',{row_dim},{col_dim},
+ 'min_a=0, max_b={max_b}, seed={self.random_state}',
+ '{rd_offset}','row={rd_id}, val={rd_val}');
+ """.format(**locals()))
+ return rd_offset
+
+ def clear(self):
+ data_type = 'view' if self.orig_data else 'table'
+ if self.rd_weights:
+ plpy.execute("drop {data_type} if exists {data};".format(
+ data=self.rd_weights,
+ data_type=data_type))
+ if self.rd_offset:
+ plpy.execute("drop {data_type} if exists {data};".format(
+ data=self.rd_offset,
+ data_type=data_type))
+
+ def __del__(self):
+ self.clear()
+
+ def saveAs(self, name):
+ if self.orig_data:
+ plpy.warning("Gaussian Kernel Warning: no need to save."
+ "Original data table exists: {0}"
+ .format(self.orig_data))
+ return
+
+ run_sql = """
+ create table {name} as
+ select
+ {id} as id, {val} as val,
+ 'offsets' as desp
+ from {rd_offset}
+ union
+ select
+ {id} as id, {val} as val,
+ 'weights' as desp
+ from {rd_weights}
+ """.format(name=name,
+ id=self.rd_id,
+ val=self.rd_val,
+ rd_offset=self.rd_offset,
+ rd_weights=self.rd_weights)
+ plpy.execute(run_sql)
+
+ @classmethod
+ def parse_params(cls, kernel_params='', n_features=10):
+ params_default = {
+ 'in_memory': 1,
+ 'gamma': 1/n_features,
+ 'random_state': 1,
+ 'n_components': 2*n_features}
+ params_types = {
+ 'in_memory': int,
+ 'gamma': float,
+ 'random_state': int,
+ 'n_components': int}
+ return extract_keyvalue_params(kernel_params,
+ params_types,
+ params_default)
+
+ @classmethod
+ def create(cls, schema_madlib, n_features, kernel_params):
+ params = cls.parse_params(kernel_params, n_features)
+ in_memory = params.pop('in_memory', True)
+ # according to the 1gb limit on each entry of the table
+ nelems = params['n_components']*n_features
+ if in_memory and nelems <= 1e8:
+ return GaussianKernelInMemory(schema_madlib, **params)
+ else:
+ return GaussianKernel(schema_madlib, **params)
+
+ @classmethod
+ def loadFrom(cls, schema_madlib, data, kernel_params=''):
+ rd_weights = unique_string(desp='random_weights')
+ rd_offset = unique_string(desp='random_offsets')
+ rd_val = unique_string(desp='val')
+ rd_id = unique_string(desp='id')
+ plpy.execute("""
+ drop view if exists {rd_weights};
+ create temp view {rd_weights} as
+ select id as {rd_id}, val as {rd_val} from {data}
+ where desp = 'weights';
+
+ drop view if exists {rd_offset};
+ create temp view {rd_offset} as
+ select id as {rd_id}, val as {rd_val} from {data}
+ where desp = 'offsets';
+ """.format(**locals()))
+ params = cls.parse_params(kernel_params)
+ in_memory = params.pop('in_memory', True)
+ if in_memory:
+ return GaussianKernelInMemory(schema_madlib,
+ random_weights=rd_weights,
+ random_offset=rd_offset,
+ id_col=rd_id, val_col=rd_val,
+ orig_data=data, **params)
+ else:
+ return GaussianKernel(schema_madlib,
+ random_weights=rd_weights,
+ random_offset=rd_offset,
+ id_col=rd_id, val_col=rd_val,
+ orig_data=data, **params)
+
+
+class GaussianKernel(GaussianKernelBase):
+ """docstring for gaussianKernel"""
+ def __init__(self, schema_madlib, gamma=1, n_components=100,
+ random_state=1, random_weights=None,
+ random_offset=None, id_col=None, val_col=None,
+ orig_data=None):
+ params = locals(); params.pop('self')
+ super(GaussianKernel, self).__init__(**params)
+
+ @property
+ def kernel_params(self):
+ return ('gamma={gamma}, n_components={n_components},'
+ 'random_state={random_state}, in_memory=0'
+ .format(gamma=self.gamma,
+ n_components=self.n_components,
+ random_state=self.random_state))
+
+ def fit(self, n_features):
+ self.clear()
+ self.orig_data = None
+ self.rd_val = unique_string(desp='val')
+ self.rd_id = unique_string(desp='id')
+ self.rd_weights = self._random_weights(n_features, self.n_components,
+ self.rd_id, self.rd_val)
+ self.rd_offset = self._random_offsets(1, self.n_components,
+ self.rd_id, self.rd_val)
+ return self
+
+ def transform(self, source_table, independent_varname,
+ dependent_varname=None, grouping_col=None, id_col=None,
+ transformed_name='gaussian_transformed'):
+ if not self.rd_offset or not self.rd_weights:
+ return self
+
+ self.original_table = dict(source_table=source_table,
+ independent_varname=independent_varname,
+ dependent_varname=dependent_varname)
+
+ schema_madlib = self.schema_madlib
+
+ _null_str = "NULL::integer"
+ _null_str_as = lambda s: _null_str + " as " + s if s else _null_str
+ _verify = lambda x, s: str(x) if x else _null_str_as(s)
+
+ grouping_col = _verify(grouping_col, unique_string('grp_col'))
+ dependent_varname = _verify(dependent_varname, '')
+ id_col = _verify(id_col, unique_string('id_col'))
+
+ # copy data to the temporary table with id column
+ # id_col is different from index_col
+ # id_col is unique and, if any, is from the original table
+ # index_col is generated randomly
+ # needs to be sequential for madlib.matrix_mult to work
+ source_with_id = unique_string(desp='source_copied')
+ features_col = unique_string(desp='features_col')
+ target_col = unique_string(desp='target_col')
+ index_col = unique_string(desp='index_col')
+ run_sql = """
+ select setseed(0.5);
+ drop table if exists {source_with_id};
+ create temp table {source_with_id} as
+ select
+ row_number() over (order by random()) as {index_col},
+ {dependent_varname} as {target_col},
+ {independent_varname} as {features_col},
+ {id_col},
+ {grouping_col}
+ from {source_table}
+ """.format(**locals())
+ plpy.execute(run_sql)
+ source_table = source_with_id
+ dependent_varname = target_col
+ independent_varname = features_col
+
+ temp_transformed = unique_string(desp='temp_transformed')
+ # X = X * weights
+ run_sql = """
+ drop table if exists {temp_transformed};
+ select {schema_madlib}.matrix_mult(
+ '{source_table}',
+ 'row={index_col}, val={independent_varname}',
+ '{self.rd_weights}',
+ 'row={self.rd_id}, val={self.rd_val}',
+ '{temp_transformed}',
+ 'row={index_col}, val={independent_varname}');
+ """.format(**locals())
+ plpy.execute(run_sql)
+
+ transformed = unique_string(desp=transformed_name)
+
+ # rd_offset is a vector of n_components elements
+ # which will fit in memory most of the time. Plus,
+ # putting rd_offset in memory makes broadcasting it to
+ # segments more efficiently
+ rd_offset_vals = plpy.execute("""
+ select {rd_val} as val from {rd_offset}
+ """.format(rd_val=self.rd_val,
+ rd_offset=self.rd_offset))[0]['val']
+
+ # X = a * cos (X + b)
+ multiplier = sqrt(2. / self.n_components)
+ run_sql = """
+ drop table if exists {transformed};
+ create temp table {transformed} as
+ select
+ {index_col},
+ {schema_madlib}.array_scalar_mult(
+ {schema_madlib}.array_cos(
+ q.{independent_varname}::float[])::float[],
+ {multiplier}::float) as {independent_varname},
+ {dependent_varname},
+ {id_col},
+ {grouping_col}
+ from (
+ select
+ x.{index_col},
+ {schema_madlib}.array_add(
+ x.{independent_varname}::float[],
+ $1) as {independent_varname}
+ from {temp_transformed} as x
+ ) q join {source_table} s using ({index_col})
+ """.format(**locals())
+ plpy.execute(plpy.prepare(run_sql, ['float[]']), [rd_offset_vals])
+ # clear table generated from matrix mult
+ plpy.execute("drop table {0};".format(temp_transformed))
+ self.transformed_table = dict(index_col=index_col,
+ source_table=transformed,
+ dependent_varname=dependent_varname,
+ independent_varname=independent_varname)
+ return self
+
+
+class GaussianKernelInMemory(GaussianKernelBase):
+ """docstring for gaussianKernel"""
+ def __init__(self, schema_madlib, gamma=1, n_components=100,
+ random_state=1, random_weights=None,
+ random_offset=None, id_col=None,
+ val_col=None, orig_data=None):
+ params = locals(); params.pop('self')
+ super(GaussianKernelInMemory, self).__init__(**params)
+
+ @property
+ def kernel_params(self):
+ return ('gamma={gamma}, n_components={n_components},'
+ 'random_state={random_state}, in_memory=1'
+ .format(gamma=self.gamma,
+ n_components=self.n_components,
+ random_state=self.random_state))
+
+ def fit(self, n_features):
+ self.clear()
+ self.orig_data = None
+ self.rd_val = unique_string(desp='val')
+ self.rd_id = unique_string(desp='id')
+ self.rd_weights = self._random_weights(1, n_features*self.n_components,
+ self.rd_id, self.rd_val)
+ self.rd_offset = self._random_offsets(1, self.n_components,
+ self.rd_id, self.rd_val)
+ return self
+
+ def transform(self, source_table, independent_varname,
+ dependent_varname=None, grouping_col=None, id_col=None,
+ transformed_name='gaussian_transformed'):
+ if not self.rd_offset or not self.rd_weights:
+ return self
+
+ self.original_table = dict(source_table=source_table,
+ independent_varname=independent_varname,
+ dependent_varname=dependent_varname)
+
+ schema_madlib = self.schema_madlib
+
+ _null_str = "NULL::integer"
+ _null_str_as = lambda s: _null_str + " as " + s if s else _null_str
+ _verify = lambda x, s: str(x) if x else _null_str_as(s)
+
+ grouping_col = _verify(grouping_col, unique_string('grp_col'))
+ dependent_varname = _verify(dependent_varname, '')
+ id_col = _verify(id_col, unique_string('id_col'))
+
+ features_col = unique_string(desp='features_col')
+ target_col = unique_string(desp='target_col')
+ transformed = unique_string(desp=transformed_name)
+
+ # X <- a * cos (X*C + b)
+ multiplier = sqrt(2. / self.n_components)
+ run_sql = """
+ drop table if exists {transformed};
+ create temp table {transformed} as
+ select
+ {schema_madlib}.array_scalar_mult(
+ {schema_madlib}.array_cos(
+ {schema_madlib}.array_add(
+ {schema_madlib}.__matrix_vec_mult_in_mem(
+ q.{features_col}::float[],
+ rw.{self.rd_val}::float[]
+ )::float[],
+ ro.{self.rd_val}::float[]
+ )::float[]
+ )::float[],
+ {multiplier}::float
+ ) as {features_col},
+ q.{target_col} as {target_col},
+ {id_col},
+ {grouping_col}
+ from (
+ select
+ {dependent_varname} as {target_col},
+ {independent_varname} as {features_col},
+ {id_col},
+ {grouping_col}
+ from {source_table}
+ ) q
+ cross join (select {self.rd_val} from {self.rd_weights}) as rw
+ cross join (select {self.rd_val} from {self.rd_offset}) as ro
+ """.format(**locals())
+ plpy.execute(run_sql)
+ self.transformed_table = dict(source_table=transformed,
+ dependent_varname=target_col,
+ independent_varname=features_col)
+ return self
+
+
+def createKernel(schema_madlib, n_features, kernel_func, kernel_params):
+ if kernel_func == 'linear':
+ return None
+ elif kernel_func == 'gaussian':
+ return GaussianKernelBase.create(schema_madlib,
+ n_features,
+ kernel_params)
+
+
+def loadKernel(schema_madlib, data, kernel_func, kernel_params):
+ if kernel_func == 'linear':
+ return None
+ elif kernel_func == 'gaussian':
+ return GaussianKernelBase.loadFrom(schema_madlib, data, kernel_params)
+
+
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/svm/svm.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/svm.py_in b/src/ports/postgres/modules/svm/svm.py_in
index 25a1d92..49e3ec0 100644
--- a/src/ports/postgres/modules/svm/svm.py_in
+++ b/src/ports/postgres/modules/svm/svm.py_in
@@ -20,6 +20,7 @@ from utilities.validate_args import is_var_valid
from utilities.validate_args import get_expr_type
from validation.internal.cross_validation import CrossValidator
+from .kernel_approximation import createKernel, loadKernel
def _compute_svm(args):
@@ -99,8 +100,8 @@ def _verify_grouping(schema_madlib, source_table, grouping_col):
intersect = frozenset(
_string_to_array(grouping_col)).intersection(
frozenset(
- ('coef', '__random_feature_data',
- '__random_feature_data', 'loss'
+ ('coef', 'random_feature_data',
+ 'random_feature_data', 'loss'
'num_rows_processed', 'num_rows_skipped',
'norm_of_gradient', 'num_iterations')))
_assert(len(intersect) == 0,
@@ -121,24 +122,6 @@ def _verify_grouping(schema_madlib, source_table, grouping_col):
return grouping_str, grouping_col
-def _verify_kernel(kernel_func):
- kernel_func = 'linear' if not kernel_func else kernel_func.lower()
- # Add non-linear kernels below after implementing them.
- supported_kernels = ['linear']
- try:
- # allow user to specify a prefix substring of
- # supported kernel function names. This works because the supported
- # kernel functions have unique prefixes.
- kernel_func = next(x for x in supported_kernels
- if x.startswith(kernel_func))
- except StopIteration:
- # next() returns a StopIteration if no element found
- plpy.error("SVM Error: Invalid kernel function: "
- "{0}. Supported kernel functions are ({1})"
- .format(kernel_func, ','.join(sorted(supported_kernels))))
- return kernel_func
-
-
def _verify_params_dict(params_dict):
_assert(not hasattr(params_dict['lambda'], '__len__'),
"SVM Error: lambda should not be a list after cross validation!")
@@ -155,11 +138,24 @@ def _verify_params_dict(params_dict):
return params_dict
-def _build_output_tables(n_iters_run, model_table, args):
+def _build_output_tables(n_iters_run, model_table, args, transformer,**kwargs):
+ if transformer is None:
+ dependent_varname = args['col_dep_var']
+ independent_varname = args['col_ind_var']
+ source_table = args['rel_source']
+ kernel_func = "linear"
+ kernel_params = "NULL"
+ else:
+ original_table = transformer.original_table
+ dependent_varname = original_table['dependent_varname']
+ independent_varname = original_table['independent_varname']
+ source_table = original_table['source_table']
+ random_table = add_postfix(model_table, "_random")
+ transformer.saveAs(random_table)
+ kernel_func = transformer.kernel_func
+ kernel_params = transformer.kernel_params
+
grouping_col = args['grouping_col']
- dependent_varname = args['col_dep_var']
- independent_varname = args['col_ind_var']
- source_table = args['rel_source']
col_grp_key = args['col_grp_key']
groupby_str, grouping_str1, using_str = "", "", "ON TRUE"
if grouping_col:
@@ -180,7 +176,6 @@ def _build_output_tables(n_iters_run, model_table, args):
(result).num_rows_processed AS num_rows_processed,
n_tuples_including_nulls - (result).num_rows_processed
AS num_rows_skipped,
- NULL AS __random_feature_data,
ARRAY[{mapping}]::{dep_type}[] AS dep_var_mapping
FROM
(
@@ -225,8 +220,8 @@ def _build_output_tables(n_iters_run, model_table, args):
'{model_table}'::text AS model_table,
'{dependent_varname}'::text AS dependent_varname,
'{independent_varname}'::text AS independent_varname,
- 'linear'::text AS kernel_func,
- NULL::text AS kernel_params,
+ '{kernel_func}'::text AS kernel_func,
+ '{kernel_params}'::text AS kernel_params,
'{grouping_text}'::text AS grouping_col,
'init_stepsize={init_stepsize}, ' ||
'decay_factor={decay_factor}, ' ||
@@ -246,11 +241,215 @@ def _build_output_tables(n_iters_run, model_table, args):
summary_table=summary_table,
source_table=source_table,
model_table=model_table,
+ kernel_func=kernel_func,
+ kernel_params=kernel_params,
dependent_varname=dependent_varname,
independent_varname=independent_varname,
**args))
+def svm_help(schema_madlib, message, is_svc, **kwargs):
+ method = 'svm_classification' if is_svc else 'svm_regression'
+
+ args = dict(schema_madlib=schema_madlib, method=method)
+
+ summary = """
+ ----------------------------------------------------------------
+ SUMMARY
+ ----------------------------------------------------------------
+ Support Vector Machines (SVMs) are models for regression
+ and classification tasks.
+
+ SVM models have two particularly desirable features:
+ robustness in the presence of noisy data and applicability
+ to a variety of data configurations.
+
+ For more details on function usage:
+ SELECT {schema_madlib}.{method}('usage')
+ """.format(**args)
+
+ usage = """
+ ---------------------------------------------------------------------------
+ USAGE
+ ---------------------------------------------------------------------------
+ SELECT {schema_madlib}.{method}(
+ source_table, -- name of input table
+ model_table, -- name of output model table
+ dependent_varname, -- name of dependent variable
+ independent_varname, -- names of independent variables
+ kernel_func, -- optional, default: 'linear'.
+ supported type of kernel: 'linear', 'gaussian',
+ and 'polynomial'
+ kernel_params, -- optional, default: NULL
+ parameters for non-linear kernel in a
+ comma-separated string of key-value pairs. The
+ parameters differ depending on the value of
+ kernel_func.
+ to find out more:
+
+ SELECT {schema_madlib}.{method}('kernel_func')
+
+ where replace 'kernel_func' with whatever kernel
+ you are interested in, i.e.,
+
+ SELECT {schema_madlib}.{method}('gaussian')
+
+ grouping_cols, -- optional, default NULL
+ names of columns to group-by
+ params, -- optional, default NULL
+ parameters for optimization and regularization in
+ a comma-separated string of key-value pairs. If a
+ list of values are provided, then cross-
+ validation will be performed to select the best
+ value from the list.
+ to find out more:
+
+ SELECT {schema_madlib}.{method}('params')
+
+ verbose -- optional, default FALSE
+ whether to print useful info
+ );
+
+
+ ---------------------------------------------------------------------------
+ OUTPUT
+ ---------------------------------------------------------------------------
+ The model table produced by svm contains the following columns:
+
+ coef FLOAT8, -- vector of the coefficients.
+ grouping_key TEXT, -- identifies the group to which
+ the datum belongs.
+ num_rows_processed BIGINT, -- numbers of rows processed.
+ num_rows_skipped BIGINT, -- numbers of rows skipped due
+ to missing values or failures.
+ num_iterations INTEGER, -- number of iterations completed by
+ the optimization algorithm.
+ The algorithm either converged in this
+ number of iterations or hit the maximum
+ number specified in the
+ optimization parameters.
+ __dep_var_mapping TEXT[], -- vector of dependendent variable labels.
+ The first entry will correspond to -1
+ and the second to +1, for internal use.
+
+ An auxiliary table named <model_table>_random is created if the kernel is not
+ linear. It contains data needed to embed test data into random feature space
+ (see reference [2,3]). This data is used internally by svm_predict and not
+ meaningful on its own.
+
+ A summary table named <model_table>_summary is also created at the same time,
+ which has the following columns:
+ method varchar, -- 'svm'
+ version_number varchar, -- version of madlib which was used to
+ generate the model.
+ source_table varchar, -- the data source table name.
+ model_table varchar, -- the model table name.
+ dependent_varname varchar, -- the dependent variable.
+ independent_varname varchar, -- the independent variables.
+ kernel_func varchar, -- the kernel function.
+ kernel_parameters varchar, -- the kernel parameters.
+ grouping_col varchar, -- columns on which to group.
+ optim_params varchar, -- a string containing the
+ optimization parameters.
+ reg_params varchar, -- a string containing the
+ regularization parameters.
+ num_all_groups integer, -- number of groups in glm training.
+ num_failed_groups integer, -- number of failed groups in glm training.
+ total_rows_processed integer, -- total numbers of rows processed
+ in all groups.
+ total_rows_skipped integer, -- numbers of rows skipped in all groups
+ due to missing values or failures.
+ """.format(**args)
+
+ params_usage = """
+ ---------------------------------------------------------------------------
+ OTHER PARAMETERS
+ ---------------------------------------------------------------------------
+ Parameters are supplied in params argument as a string
+ containing a comma-delimited list of name-value pairs.
+
+ Hyperparameter optimization can be carried out through
+ the built-in cross validation mechanism
+
+ init_stepsize -- Default: [0.01]. Also known as the inital learning rate.
+ decay_factor -- Default: [0.9].
+ Control the learning rate schedule:
+ 0 means constant rate; -1 means inverse scaling, i.e.,
+ stepsize = init_stepsize / iteration;
+ > 0 means exponential decay, i.e.,
+ stepsize = init_stepsize * decay_factor^iteration.
+ max_iter -- Default: [100].
+ The maximum number of iterations allowed.
+ tolerance -- Default: 1e-10. The criteria to end iterations.
+ lambda -- Default: [0.01]. Regularization parameter, positive.
+ norm -- Default: 'L2'.
+ Name of the regularization, either 'L2' or 'L1'.
+ epsilon -- Default: [0.01].
+ Determines the $\epsilon$ for $\epsilon$-regression.
+ Ignored during classification.
+ eps_tabl -- Default: NULL.
+ Name of the table that contains values of epsilon for
+ different groups. Ignored when grouping_col is NULL.
+ validation_result -- Default: NULL.
+ Name of the table to store the cross validation results
+ including the values of parameters and
+ their averaged error values.
+ n_folds -- Default: 0. Number of folds.
+ Must be at least 2 to activate cross validation.
+ """
+
+ gaussian_usage = """
+ ---------------------------------------------------------------------------
+ GAUSSIAN PARAMETERS
+ ---------------------------------------------------------------------------
+ Parameters are supplied in kernel_params argument as a string
+ containing a comma-delimited list of name-value pairs.
+
+ gamma -- Default: 1/num_features.
+ The parameter $\gamma$ in the Radius Basis
+ Function kernel,
+ n_components -- Default: 2*num_features.
+ The dimensionality of the transformed feature space.
+ random_state -- Default: 1. Seed used by the random number generator.
+ """
+
+ poly_usage = """
+ ---------------------------------------------------------------------------
+ POLYNOMIAL PARAMETERS
+ ---------------------------------------------------------------------------
+ Parameters are supplied in kernel_params argument as a string
+ containing a comma-delimited list of name-value pairs.
+
+ coef0 -- Default: 1.0.
+ The independent term q in (xTy + q)^r.
+ Must be larger or equal to 0. When it is 0,
+ the polynomial kernel is in homogeneous form.
+ degree -- Default: 3.
+ The parameter r in (xTy + q)^r.
+ n_components -- Default: 2*num_features.
+ The dimensionality of the transformed feature space.
+ A larger value lowers the variance of the estimate of
+ kernel but requires more memory and
+ takes longer to train.
+ random_state -- Default: 1. Seed used by the random number generator.
+ """
+
+ if not message:
+ return summary
+ elif message.lower() in ('usage', 'help', '?'):
+ return usage
+ elif message.lower() == 'params':
+ return params_usage
+ elif message.lower() == 'gaussian':
+ return gaussian_usage
+ elif message.lower() == 'polynomial':
+ return poly_usage
+ else:
+ return """
+ No such option. Use "SELECT {schema_madlib}.{method}()" for help.
+ """.format(**args)
+
+
def svm(schema_madlib, source_table, model_table,
dependent_varname, independent_varname, kernel_func,
kernel_params, grouping_col, params, is_svc,
@@ -265,8 +464,16 @@ def svm(schema_madlib, source_table, model_table,
model_table,
dependent_varname,
independent_varname)
+ grouping_str, grouping_col = _verify_grouping(schema_madlib,
+ source_table, grouping_col)
+ kernel_func = _verify_kernel(kernel_func)
+ transformer = _random_feature_map(schema_madlib, source_table,
+ dependent_varname, independent_varname,
+ kernel_func, kernel_params, grouping_col)
+ params_dict = _extract_params(schema_madlib, params)
args = locals()
- args['params_dict'] = _extract_params(schema_madlib, params)
+ if transformer is not None:
+ args.update(transformer.transformed_table)
_cross_validate_svm(args)
_svm_parsed_params(**args)
@@ -316,27 +523,58 @@ def _cross_validate_svm(args):
scorer = 'classification' if args['is_svc'] else 'regression'
sub_args = {'params_dict': cv_params}
+ transformer = args.get('transformer', None)
+ # we want svm in cross validation to behave as if transformer is None
+ # if it is not, then svm_predict will transform the test data again,
+ # which will not be correct since test data in cross validation
+ # comes from training data which has already been transformed
+ args.update(dict(transformer=None))
cv = CrossValidator(_svm_parsed_params, svm_predict, scorer, args)
val_res = cv.validate(sub_args, params_dict['n_folds']).sorted()
val_res.output_tbl(params_dict['validation_result'])
params_dict.update(val_res.first('sub_args')['params_dict'])
-# ------------------------------------------------------------------------------
+ args.update(dict(transformer=transformer))
+
+
+def _verify_kernel(kernel_func):
+ kernel_func = 'linear' if not kernel_func else kernel_func.lower()
+ # Add non-linear kernels below after implementing them.
+ supported_kernels = ['linear', 'gaussian']
+ try:
+ # allow user to specify a prefix substring of
+ # supported kernel function names. This works because the supported
+ # kernel functions have unique prefixes.
+ kernel_func = next(x for x in supported_kernels
+ if x.startswith(kernel_func))
+ except StopIteration:
+ # next() returns a StopIteration if no element found
+ plpy.error("SVM Error: Invalid kernel function: "
+ "{0}. Supported kernel functions are ({1})"
+ .format(kernel_func, ','.join(sorted(supported_kernels))))
+ return kernel_func
+
+
+def _random_feature_map(schema_madlib, source_table, dependent_varname,
+ independent_varname, kernel_func,
+ kernel_params, grouping_col):
+ if kernel_func == 'linear':
+ return None
+
+ n_features = num_features(source_table, independent_varname)
+ transformer = createKernel(schema_madlib, n_features,
+ kernel_func, kernel_params)
+ return (transformer.fit(n_features)
+ .transform(source_table, independent_varname,
+ dependent_varname, grouping_col))
def _svm_parsed_params(schema_madlib, source_table, model_table,
- dependent_varname, independent_varname, kernel_func,
- kernel_params, grouping_col, params_dict, is_svc,
+ dependent_varname, independent_varname, transformer,
+ grouping_str, grouping_col, params_dict, is_svc,
verbose, **kwargs):
"""
Executes the linear support vector algorithm.
"""
- grouping_str, grouping_col = _verify_grouping(schema_madlib,
- source_table,
- grouping_col)
-
- kernel_func = _verify_kernel(kernel_func)
-
- # arguments for iterating
n_features = num_features(source_table, independent_varname)
args = {
@@ -366,7 +604,8 @@ def _svm_parsed_params(schema_madlib, source_table, model_table,
.format(args['rel_args']))
# actual iterative algorithm computation
n_iters_run = _compute_svm(args)
- _build_output_tables(n_iters_run, model_table, args)
+ _build_output_tables(n_iters_run, model_table,
+ args, transformer, **kwargs)
def svm_predict(schema_madlib, model_table, new_data_table, id_col_name,
@@ -411,6 +650,7 @@ def svm_predict(schema_madlib, model_table, new_data_table, id_col_name,
kernel_func = summary['kernel_func']
kernel_params = summary['kernel_params']
grouping_col = summary['grouping_col']
+ grouping_col = None if grouping_col == 'NULL' else grouping_col
input_tbl_valid(new_data_table, 'SVM')
grouping_str, grouping_col = _verify_grouping(schema_madlib,
@@ -424,6 +664,23 @@ def svm_predict(schema_madlib, model_table, new_data_table, id_col_name,
"SVM Error: id_col_name ('" + id_col_name +
"') is invalid for new_data_table (" + new_data_table + ")!")
output_tbl_valid(output_table, 'SVM')
+
+ if kernel_func.lower() != 'linear':
+ random_table = add_postfix(model_table, '_random')
+ input_tbl_valid(random_table, 'SVM')
+ transformer = loadKernel(schema_madlib,
+ random_table,
+ kernel_func,
+ kernel_params)
+ transformer.transform(new_data_table,
+ independent_varname,
+ grouping_col=grouping_col,
+ id_col=id_col_name)
+ transformed_table = transformer.transformed_table
+ new_data_table = transformed_table['source_table']
+ independent_varname = transformed_table['independent_varname']
+ dependent_varname = transformed_table['dependent_varname']
+
if method.upper() == 'SVC':
pred_query = """
CASE WHEN {schema_madlib}.array_dot(
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/svm/svm.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/svm.sql_in b/src/ports/postgres/modules/svm/svm.sql_in
index 047b364..74df817 100644
--- a/src/ports/postgres/modules/svm/svm.sql_in
+++ b/src/ports/postgres/modules/svm/svm.sql_in
@@ -16,6 +16,29 @@ m4_include(`SQLCommon.m4')
/**
@addtogroup grp_svm
+<div class="toc"><b>Contents</b><ul>
+<li class="level1"><a href="#svm_classification">Classification Function</a></li>
+<li class="level1"><a href="#svm_regression">Regression Function</a></li>
+<li class="level1"><a href="#kernel_params">Kernel Parameters</a></li>
+<li class="level1"><a href="#parameters">Other Parameters</a></li>
+<li class="level1"><a href="#predict">Prediction Functions</a></li>
+<li class="level1"><a href="#example">Examples</a></li>
+<li class="level1"><a href="#background">Technical Background</a></li>
+<li class="level1"><a href="#literature">Literature</a></li>
+<li class="level1"><a href="#related">Related Topics</a></li>
+</ul></div>
+
+Support Vector Machines (SVMs) are models for regression and classification
+tasks. SVM models have two particularly desirable features: robustness in the
+presence of noisy data and applicability to a variety of data configurations. At
+its core, a <em>linear</em> SVM model is a hyperplane separating the two
+distinct classes of data (in the case of classification problems), in such a way
+that the distance between the hyperplane and the nearest training data point
+(called the <em>margin</em>) is maximized. Vectors that lie on this margin are
+called support vectors. With the support vectors fixed, perturbations of vectors
+beyond the margin will not affect the model; this contributes to the models
+robutstness. Subsituting a kernel function for the usual inner product, one can
+approximate a large variety of decision boundaries beyond linear hyperplanes.
@brief Solves classification and regression problems by separating the data with
a hyperplane or other nonlinear decision boundaries.
@@ -31,8 +54,7 @@ svm_classification(
kernel_func,
kernel_params,
grouping_col,
- optim_params,
- reg_params,
+ params,
verbose
)
</pre>
@@ -68,14 +90,10 @@ svm_classification(
</DD>
<DT>kernel_params (optional)</DT>
- <DD>TEXT, defaults: NULL for kernel='linear';
- 'gamma=\f$\frac{1}{num\_features}\f$' for kernel='gaussian',
- 'q=0,d=3' for kernel='polynomial'.
+ <DD>TEXT, defaults: NULL
<br>Parameters for non-linear kernel in a comma-separated string of key-value pairs.
- <br>For kernel='gaussian', one parameter, 'gamma', is expected.
- <br>For kernel='polynomial', two parameters are expected:
- a coefficient \f$q\f$ and degree \f$d\f$, as in \f$ (\langle x,y\rangle + q)^d \f$.
- </DD>
+ The parameters differ depending on the value of \e kernel_func. See the description below for details.
+ </DD>
<DT>grouping_col (optional)</DT>
<DD>TEXT, default: NULL. An expression list used to group
@@ -83,24 +101,10 @@ svm_classification(
Similar to the SQL "GROUP BY" clause. When this value is NULL, no
grouping is used and a single model is generated.</DD>
- <DT>optim_params (optional)</DT>
- <DD>TEXT, default: 'init_stepsize=0.01, decay_factor=0.9, max_iter=100, tolerance=0.001'. <br>
- Optimization paramters including stepsize, decay factor of stepsize, max
- number of iterations, and error tolerance. If the number of iterations of
- IGD reaches the maximum, the algorithm will halt. Alternatively, if the
- current value of the objective function has a relative difference from the
- previous iteration of less than the tolerance, the algorithm will halt.</DD>
-
- <DT>reg_params (optional)</DT>
- <DD>TEXT, default: 'lambda=0.01, norm=L2, n_folds=0'. <br>
- Regularization parameters. Parameter 'norm' corresponds
- which norm will be used for regularization; user can select either 'L1' or 'L2'.
- If the user specifies n_folds > 1, then cross-validation will be performed to
- select lambda from a list.
-
- For example, if one wanted to regularize with the L1 norm and use a lambda
- value from the set {0.3, 0.4, 0.5}, one would input
- 'lambda={0.3, 0.4, 0.5}, norm=L1, n_folds=10' as reg_params.</DD>
+ <DT>params (optional)</DT>
+ <DD>TEXT, default: NULL.
+ <br> Parameters for optimization and regularization in a comma-separated string of key-value pairs. If a list of values are provided, then cross-validation will be performed to select the \e best value from the list.
+ See the description below for details. </DD>
<DT>verbose (optional)</DT>
<DD>BOOLEAN default: FALSE.
@@ -135,19 +139,12 @@ svm_classification(
</tr>
<tr>
<th>__dep_var_mapping</th>
- <td>TEXT[]. Vector of dependendent variable labels. The first entry will
+ <td>TEXT[]. Vector of dependent variable labels. The first entry will
correspond to -1 and the second to +1, for internal use.</td>
</tr>
- <tr>
- <th>__random_feature_data</th>
- <td>BYTEA8. Data needed to embed test data into random feature space
- (see references [2,3]). This data is used internally by svm_predict and
- not meaningful on its own. NULL if the kernel is linear.</td>
- </tr>
</table>
- A summary table named \<model_table\>_summary is also created at the same time,
- which has the following columns:
+ An auxiliary table named \<model_table\>_random is created if the kernel is not linear. It contains data needed to embed test data into random feature space (see reference [2,3]). This data is used internally by svm_predict and not meaningful on its own. And a summary table named \<model_table\>_summary is also created at the same time, which has the following columns:
<table class="output">
<tr>
<th>method</th>
@@ -195,11 +192,11 @@ svm_classification(
</tr>
<tr>
<th>num_all_groups</th>
- <td>Number of groups in glm training.</td>
+ <td>Number of groups in svm training.</td>
</tr>
<tr>
<th>num_failed_groups</th>
- <td>Number of failed groups in glm training.</td>
+ <td>Number of failed groups in svm training.</td>
</tr>
<tr>
<th>total_rows_processed</th>
@@ -224,9 +221,7 @@ svm_regression(source_table,
kernel_func,
kernel_params,
grouping_col,
- optim_params,
- reg_params,
- epsilon,
+ params,
verbose
)
</pre>
@@ -244,16 +239,138 @@ arguments have specifications which differ from svm_classification:
Otherwise, an error will be thrown.
</DD>
-<DT>epsilon (optional)</DT>
-<DD>DOUBLE PRECISION, default: 'epsilon=0.1'.
- Determines the \f$\epsilon\f$ for \f$\epsilon\f$-regression. When training
- the model, differences of less than \f$\epsilon\f$ between estimated labels
- and actual labels are ignored. A larger \f$\epsilon\f$ will yield a model
- with fewer support vectors, but will not generalize as well to future data.
- Generally, it has been suggested that epsilon should increase with noisier
- data, and decrease with the number of samples. See [5]. </DD>
+<DT>params (optional)</DT>
+<DD>TEXT, default: NULL.
+The parameters \e epsilon and \e eps_table are only meaningful for regression. See descriptions below for more details.
+</DD>
+</DL>
+
+@anchor kernel_params
+@par Kernel Parameters
+Kernel parameters are supplied in a string containing a comma-delimited
+list of name-value pairs. All of these named parameters are optional, and
+their order does not matter. You must use the format "<param_name> = <value>"
+to specify the value of a parameter, otherwise the parameter is ignored.
+When the \ref svm_classification() \e kernel_func argument value is \b 'gaussian', the \e kernel_params argument is a string containing name-value pairs with the following format. (Line breaks are inserted for readability.)
+<pre class="syntax">
+ 'gamma = <value>,
+ n_components = <value>,
+ random_state = <value>'
+</pre>
+\b Parameters
+<DL class="arglist">
+<DT>gamma</dt>
+<DD>Default: 1/num_features. The parameter \f$\gamma\f$ in the Radius Basis Function kernel, i.e., \f$\exp(-\gamma||x-y||^2)\f$. Choosing a proper value for \e gamma is critical to the performance of kernel machine, e.g., while a large \e gamma tends to cause overfitting, a small \e gamma will make the model too constrained to capture the complexity of the data.
+.</DD>
+
+<DT>n_components</DT>
+<DD>Default: 2*num_features. The dimensionality of the transformed feature space. A larger value lowers the variance of the estimate of kernel but requires more memory and takes longer to train.</DD>
+
+<DT>random_state</DT>
+<DD>Default: 1. Seed used by the random number generator. </DD>
+</DL>
+
+When the \ref svm_classification() \e kernel_func argument value is \b 'poly', the \e kernel_params argument is a string containing name-value pairs with the following format. (Line breaks are inserted for readability.)
+<pre class="syntax">
+ 'coef0 = <value>,
+ degree = <value>,
+ n_components = <value>,
+ random_state = <value>'
+</pre>
+\b Parameters
+<DL class="arglist">
+<DT>coef0</dt>
+<DD>Default: 1.0. The independent term \f$q\f$ in \f$ (\langle x,y\rangle + q)^r \f$. Must be larger or equal to 0. When it is 0, the polynomial kernel is in homogeneous form.
+</DD>
+
+<DT>degree</dt>
+<DD>Default: 3. The parameter \f$r\f$ in \f$ (\langle x,y\rangle + q)^r \f$.
+</DD>
+
+<DT>n_components</DT>
+<DD>Default: 2*num_features. The dimensionality of the transformed feature space. A larger value lowers the variance of the estimate of kernel but requires more memory and takes longer to train.</DD>
+
+<DT>random_state</DT>
+<DD>Default: 1. Seed used by the random number generator. </DD>
+</DL>
+
+
+@anchor parameters
+@par Other Parameters
+Parameters in this sections are supplied in \e params argument as a string containing a comma-delimited
+list of name-value pairs. Hyperparameter optimization can be carried out through the built-in cross validation mechanism, which is activated by assigning a value greater than 1 to the parameter \e n_folds in \e params.
+All of these named parameters are optional, and their order does not matter.
+You must use the format "<param_name> = <value>" to specify the value of a parameter, otherwise the parameter is ignored.
+The validating values of the parameter are provided in a list, i.e., "lambda = [0.01, 0.1, 1]".
+For example, if one wanted to regularize with the L1 norm and use a lambda value from the set {0.3, 0.4, 0.5}, one would input 'lambda={0.3, 0.4, 0.5}, norm=L1, n_folds=10' in \e params. Note that the use of '{}' and '[]' are both valid here.
+
+Not all parameters below can be cross-validated. And for those who do, their default values, as described below, are specified in a list, i.e., [0.01].
+<pre class="syntax">
+ 'init_stepsize = <value>,
+ decay_factor = <value>,
+ max_iter = <value>,
+ tolerance = <value>,
+ lambda = <value>,
+ norm = <value>,
+ epsilon = <value>,
+ eps_table = <value>,
+ validation_result = <value>,
+ n_folds = <value>'
+</pre>
+\b Parameters
+<DL class="arglist">
+
+<DT>init_stepsize</dt>
+<DD>Default: [0.01]. Also known as the inital learning rate. A small value is usually desirable to ensure convergence, while a large value provides more room for progress during training. Since the best value depends on the condition number of the data, in practice one can search in a exponential grid using the built-in cross validation, i.e., "init_stepsize = [1, 0.1, 0.001]". This can be done on a subsampled dataset which usually provides a good estimate of the condition number of the whole dataset.
+</DD>
+
+<DT>decay_factor</DT>
+<DD>Default: [0.9]. Control the learning rate schedule: 0 means constant rate; -1 means inverse scaling, i.e., stepsize = init_stepsize / iteration; > 0 means exponential decay, i.e., stepsize = init_stepsize * decay_factor^iteration.
+</DD>
+
+<DT>max_iter</dt>
+<DD>Default: [100]. The maximum number of iterations allowed.
+</DD>
+
+<DT>tolerance</dt>
+<DD>Default: 1e-10. The criteria to end iterations. The training stops whenever the difference between the training models of two consecutive iterations is smaller than \e tolerance or the iteration number is larger than \e max_iter.
+</DD>
+
+<DT>lambda</dt>
+<DD>Default: [0.01]. Regularization parameter, positive.
+</DD>
+
+<DT>norm</dt>
+<DD>Default: 'L2'. Name of the regularization, either 'L2' or 'L1'.
+</DD>
+
+<DT>epsilon</dt>
+<DD>Default: [0.01].
+Determines the \f$\epsilon\f$ for \f$\epsilon\f$-regression. Ignored during classification.
+When training the model, differences of less than \f$\epsilon\f$ between estimated labels
+and actual labels are ignored. A larger \f$\epsilon\f$ will yield a model
+with fewer support vectors, but will not generalize as well to future data.
+Generally, it has been suggested that epsilon should increase with noisier
+data, and decrease with the number of samples. See [5].
+</DD>
+
+<DT>eps_tabl</dt>
+<DD>Default: NULL.
+Name of the table that contains values of epsilon for different groups. Ignored when \e grouping_col is NULL.
+The table consists of the column named epsilon which specifies the epsilon values, as well as those columns used in \e grouping_col. Extra groups are ignored, and groups not present in this table will use the epsilon value specified in parameter \e epsilon.
+</DD>
+
+<DT>validation_result</dt>
+<DD>Default: NULL.
+Name of the table to store the cross validation results including the values of parameters and their averaged error values. For now simple metric like 0-1 loss is used for classification and mean square error is used for regression. The table is only created if the name is not NULL.
+</DD>
+
+<DT>n_folds</dt>
+<DD>Default: 0.
+Number of folds. Must be at least 2 to activate cross validation. If a value of k > 2 is specified, each fold is then used as a validation set once while the k - 1 remaining fold form the training set.
+</DD>
</DL>
@@ -289,21 +406,102 @@ id_col_name column giving the 'id' for each prediction and the prediction
columns for the dependent variable.</DD>
</DL>
+@anchor example
+@par Examples
+-# Create an input data set.
+<pre class="example">
+CREATE TABLE houses (id INT, tax INT, bedroom INT, bath FLOAT, price INT,
+ size INT, lot INT);
+COPY houses FROM STDIN WITH DELIMITER '|';
+ 1 | 590 | 2 | 1 | 50000 | 770 | 22100
+ 2 | 1050 | 3 | 2 | 85000 | 1410 | 12000
+ 3 | 20 | 3 | 1 | 22500 | 1060 | 3500
+ 4 | 870 | 2 | 2 | 90000 | 1300 | 17500
+ 5 | 1320 | 3 | 2 | 133000 | 1500 | 30000
+ 6 | 1350 | 2 | 1 | 90500 | 820 | 25700
+ 7 | 2790 | 3 | 2.5 | 260000 | 2130 | 25000
+ 8 | 680 | 2 | 1 | 142500 | 1170 | 22000
+ 9 | 1840 | 3 | 2 | 160000 | 1500 | 19000
+ 10 | 3680 | 4 | 2 | 240000 | 2790 | 20000
+ 11 | 1660 | 3 | 1 | 87000 | 1030 | 17500
+ 12 | 1620 | 3 | 2 | 118600 | 1250 | 20000
+ 13 | 3100 | 3 | 2 | 140000 | 1760 | 38000
+ 14 | 2070 | 2 | 3 | 148000 | 1550 | 14000
+ 15 | 650 | 3 | 1.5 | 65000 | 1450 | 12000
+\\.
+</pre>
+-# Train a classification model. First, a linear model.
+<pre class="example">
+SELECT madlib.svm_classification('houses',
+ 'houses_svm',
+ 'price < 100000',
+ 'ARRAY[1, tax, bath, size]'
+ );
+</pre>
+-# Generate a nonlinear model using gaussian kernel. This time we specify the intital step size and maximum number of iteration to run. As part of the kernel parameter, we choose 10 as the dimension of the space where we train svm. A larger number will lead to a more powerful model but run the risk of overfitting. As a result, the model will be a 10 dimensional vector, instead of 4 as in the case of linear model, which we will verify when we examine the models.
+<pre class="example">
+SELECT madlib.linregr_train( 'houses',
+ 'houses_svm_gaussian',
+ 'price < 100000',
+ 'ARRAY[1, tax, bath, size]',
+ 'gaussian',
+ 'n_components=10',
+ '',
+ 'init_stepsize=1, max_iter=200'
+ );
+</pre>
+-# Examine the resulting models.
+<pre class="example">
+-- Set extended display on for easier reading of output
+\\x ON
+SELECT * FROM houses_svm;
+</pre>
+Result:
+<pre class="result">
+-[ RECORD 1 ]+---------------------------------------------------------------------------
+coef | [0.113989576847, -0.00226133300602, -0.0676303607996, 0.00179440841072]
+loss | 9.21745071385
+norm_of_gradient | 108.171180769
+num_iterations | 100
+num_rows_processed | 15
+num_rows_skipped | 0
+dep_var_mapping | [False, True]
+</pre>
+
+-# View the results from kernel svm.
+<pre class="example">
+-- Set extended display on for easier reading of output
+\\x ON
+SELECT * FROM houses_svm_gaussian;
+</pre>
+Result:
+<pre class="result">
+-[ RECORD 1 ]+---------------------------------------------------------------------------
+coef | [-2.00789985255, 2.02625531256, -1.09903715824, 2.04431020735, 3.14208435644, 0.14838741816, 2.07527256499, 3.0816372960, 0.853428649407, 3.63747384926]
+loss | 0.255909866744
+norm_of_gradient | 0.0715415776655
+num_iterations | 184
+num_rows_processed | 15
+num_rows_skipped | 0
+dep_var_mapping | [False, True]
+</pre>
+
+-# Use the prediction function to evaluate the models. The predicted results are in the \e prediction column and the actual data is in the \e target column.
+For the linear model:
+<pre class="example">
+SELECT madlib.svm_predict('houses_svm', 'houses', 'id', 'houses_pred');
+SELECT *, price < 100000 AS target FROM houses JOIN houses_pred USING (id)
+</pre>
+and for the gaussian model:
+<pre class="example">
+SELECT madlib.svm_predict('houses_svm_gaussian', 'houses', 'id', 'houses_pred_gaussian');
+SELECT *, price < 100000 AS target FROM houses JOIN houses_pred_gaussian USING (id)
+</pre>
+
+
@anchor background
@par Technical Background
-Support Vector Machines (SVMs) are models for regression and classification
-tasks. SVM models have two particularly desirable features: robustness in the
-presence of noisy data and applicability to a variety of data configurations. At
-its core, a <em>linear</em> SVM model is a hyperplane separating the two
-distinct classes of data (in the case of classification problems), in such a way
-that the distance between the hyperplane and the nearest training data point
-(called the <em>margin</em>) is maximized. Vectors that lie on this margin are
-called support vectors. With the support vectors fixed, perturbations of vectors
-beyond the margin will not affect the model; this contributes to the models
-robutstness. Subsituting a kernel function for the usual inner product, one can
-approximate a large variety of decision boundaries beyond linear hyperplanes.
-
To solve linear SVM, the following objective function is minimized:
\f[
\underset{w,b}{\text{Minimize }} \lambda||w||^2 + \frac{1}{n}\sum_{i=1}^n \ell(y_i,f_{w,b}(x_i))
@@ -649,4 +847,35 @@ m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA');
-- Online Help -----------------------------------------------------------
-
+/**
+ * @brief Help function
+ */
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.svm_classification (
+ message TEXT
+) RETURNS TEXT AS $$
+ global is_svc
+ is_svc = True
+ PythonFunction(svm, svm, svm_help)
+$$ LANGUAGE plpythonu
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.svm_classification ()
+RETURNS TEXT AS $$
+ SELECT MADLIB_SCHEMA.svm_classification(NULL::TEXT)
+$$ LANGUAGE SQL IMMUTABLE
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `CONTAINS SQL', `');
+
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.svm_regression (
+ message TEXT
+) RETURNS TEXT AS $$
+ global is_svc
+ is_svc = False
+ PythonFunction(svm, svm, svm_help)
+$$ LANGUAGE plpythonu
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
+
+CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.svm_regression ()
+RETURNS TEXT AS $$
+ SELECT MADLIB_SCHEMA.svm_regression(NULL::TEXT)
+$$ LANGUAGE SQL IMMUTABLE
+m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `CONTAINS SQL', `');
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/9b012604/src/ports/postgres/modules/svm/test/linear_svm.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/test/linear_svm.sql_in b/src/ports/postgres/modules/svm/test/linear_svm.sql_in
index e94a90a..8458190 100644
--- a/src/ports/postgres/modules/svm/test/linear_svm.sql_in
+++ b/src/ports/postgres/modules/svm/test/linear_svm.sql_in
@@ -555,7 +555,7 @@ INSERT INTO abalone_eps(sex, epsilon) VALUES
-- solve it with grouping and table of epsilon as inputs
DROP TABLE IF EXISTS svr_mdl, svr_mdl_summary;
-SELECT madlib.svm_regression(
+SELECT svm_regression(
'abalone_train_small',
'svr_mdl',
'rings',
@@ -567,7 +567,7 @@ SELECT * FROM svr_mdl;
DROP TABLE IF EXISTS svr_mdl_i, svr_mdl_i_summary;
-SELECT madlib.svm_regression(
+SELECT svm_regression(
'abalone_train_small',
'svr_mdl_i',
'rings',
@@ -578,7 +578,7 @@ SELECT madlib.svm_regression(
SELECT * FROM svr_mdl_i where sex = 'I';
DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary;
-SELECT madlib.svm_regression(
+SELECT svm_regression(
'abalone_train_small',
'svr_mdl_m',
'rings',
@@ -589,7 +589,7 @@ SELECT madlib.svm_regression(
SELECT * FROM svr_mdl_m where sex = 'M';
DROP TABLE IF EXISTS svr_mdl_f, svr_mdl_f_summary;
-SELECT madlib.svm_regression(
+SELECT svm_regression(
'abalone_train_small',
'svr_mdl_f',
'rings',
@@ -704,7 +704,128 @@ SELECT
FROM svm_test_predict NATURAL JOIN svm_test_data
WHERE prediction <> label;
+-- verify guassian kernel mapping dimensions
+DROP TABLE IF EXISTS m1, m1_summary, m1_random;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3',
+ NULL,
+ 'max_iter=2');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+-- verify gaussian kernel with grouping
+-- verify partial string support in kernel specification
+DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary, svr_mdl_m_random;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl_m',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ 'gau',
+ 'n_components=10',
+ 'sex',
+ 'max_iter=2, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.05',
+ false);
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('svr_mdl_m','abalone_train_small', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 10,
+ 'The dimension of the coefficients must be equal to n_components (10)!')
+FROM svr_mdl_m;
+-- verify guassian kernel with cross validation
+DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3',
+ NULL,
+ 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+-- verify guassian kernel with out-of-memory support
+DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3, in_memory=0',
+ NULL,
+ 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+
+DROP TABLE IF EXISTS kernel_data;
+CREATE TABLE kernel_data (
+ index bigint,
+ x1 double precision,
+ x2 double precision,
+ y double precision
+);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (0, 0.400000000000000022, -0.699999999999999956, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (1, -1.5, -1, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (2, -1.39999999999999991, -0.900000000000000022, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (3, -1.30000000000000004, -1.19999999999999996, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (4, -1.10000000000000009, -0.200000000000000011, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (5, -1.19999999999999996, -0.400000000000000022, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (6, -0.5, 1.19999999999999996, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (7, -1.5, 2.10000000000000009, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (8, 1, 1, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (9, 1.30000000000000004, 0.800000000000000044, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (10, 1.19999999999999996, 0.5, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (11, 0.200000000000000011, -2, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (12, 0.5, -2.39999999999999991, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (13, 0.200000000000000011, -2.29999999999999982, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (14, 0, -2.70000000000000018, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (15, 1.30000000000000004, 2.10000000000000009, 1);
+
+
+DROP TABLE IF EXISTS m1, m1_summary, m1_random;
+SELECT svm_classification(
+ 'kernel_data',
+ 'm1',
+ 'y',
+ 'array[x1, x2]',
+ 'gaussian',
+ 'gamma=1, n_components=20, random_state=2',
+ NULL,
+ 'init_stepsize=1, max_iter=10');
+SELECT * FROM m1;
+DROP TABLE IF EXISTS kernel_predict CASCADE;
+SELECT svm_predict('m1','kernel_data', 'index', 'kernel_predict');
+SELECT
+ count(*) as misclassification
+FROM kernel_predict NATURAL JOIN kernel_data
+WHERE prediction <> y;
+SELECT
+ assert(count(*) = 0, 'Using kernel should perfectly fit the data!')
+FROM kernel_predict NATURAL JOIN kernel_data
+WHERE prediction <> y;
[2/5] incubator-madlib git commit: Build: Remove doxypy to be
compatible with Apache
Posted by ri...@apache.org.
Build: Remove doxypy to be compatible with Apache
JIRA: MADLIB-962
doxypy build's doxygen compatible documentation from Python
docstrings and comment blocks. It is licensed as GPL which breaks the
MADlib Apache license. We need to find/write an alternative Python
script to create the documentation.
Closes #16
Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/a62eb6f0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/a62eb6f0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/a62eb6f0
Branch: refs/heads/master
Commit: a62eb6f07b9a28706f8931cff934c1ed3ea28cf9
Parents: acb0597
Author: Rahul Iyer <ri...@pivotal.io>
Authored: Fri Feb 12 10:46:03 2016 -0800
Committer: Rahul Iyer <ri...@pivotal.io>
Committed: Fri Feb 12 10:52:53 2016 -0800
----------------------------------------------------------------------
doc/CMakeLists.txt | 4 +-
doc/bin/CMakeLists.txt | 14 +-
doc/bin/doxypy.py | 414 -------------------------------------------
doc/bin/py_filter.sh.in | 4 -
4 files changed, 9 insertions(+), 427 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/a62eb6f0/doc/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 3a5960c..fca039b 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -152,7 +152,7 @@ if(FLEX_FOUND AND BISON_FOUND AND DOXYGEN_FOUND)
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} user.doxyfile | ${_DOXYGEN_UNNEEDED_WARNINGS_FILTER}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/etc"
- DEPENDS doxysql doxyBinFiles ${_MATHJAX_DEPENDENCY_USER}
+ DEPENDS doxysql ${_MATHJAX_DEPENDENCY_USER}
"${CMAKE_CURRENT_BINARY_DIR}/etc/literature.bib"
COMMENT "Generating user-level documentation..."
VERBATIM
@@ -168,7 +168,7 @@ if(FLEX_FOUND AND BISON_FOUND AND DOXYGEN_FOUND)
add_custom_target(devdoc
COMMAND ${DOXYGEN_EXECUTABLE} developer.doxyfile | ${_DOXYGEN_UNNEEDED_WARNINGS_FILTER}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/etc"
- DEPENDS doxysql doxyBinFiles update_mathjax
+ DEPENDS doxysql update_mathjax
"${CMAKE_CURRENT_BINARY_DIR}/etc/literature.bib"
COMMENT "Generating developer documentation..."
VERBATIM
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/a62eb6f0/doc/bin/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/doc/bin/CMakeLists.txt b/doc/bin/CMakeLists.txt
index cc7faad..bf504c7 100644
--- a/doc/bin/CMakeLists.txt
+++ b/doc/bin/CMakeLists.txt
@@ -2,19 +2,19 @@
# MADlib Documentation Executable Files
# ------------------------------------------------------------------------------
-set(BIN_FILES
- doxypy.py
-)
-add_files(BIN_TARGET_FILES . "${CMAKE_CURRENT_BINARY_DIR}" ${BIN_FILES})
-add_custom_target(doxyBinFiles ALL DEPENDS ${BIN_TARGET_FILES})
+# set(BIN_FILES
+# doxypy.py
+# )
+# add_files(BIN_TARGET_FILES . "${CMAKE_CURRENT_BINARY_DIR}" ${BIN_FILES})
+# add_custom_target(doxyBinFiles ALL DEPENDS ${BIN_TARGET_FILES})
list(APPEND M4_ARGUMENTS
- "\"-DMADLIB_SCHEMA=MADlib\""
+ "\"-DMADLIB_SCHEMA=madlib\""
"\"-I${CMAKE_BINARY_DIR}/doc/etc\""
)
join_strings(_M4_ARGUMENTS " " "${M4_ARGUMENTS}")
set(_M4_ARGUMENTS "${_M4_ARGUMENTS}")
-configure_file(py_filter.sh.in py_filter.sh @ONLY)
+# configure_file(py_filter.sh.in py_filter.sh @ONLY)
configure_file(sql_filter.sh.in sql_filter.sh @ONLY)
configure_file(update_mathjax.sh.in update_mathjax.sh @ONLY)
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/a62eb6f0/doc/bin/doxypy.py
----------------------------------------------------------------------
diff --git a/doc/bin/doxypy.py b/doc/bin/doxypy.py
deleted file mode 100755
index 649281b..0000000
--- a/doc/bin/doxypy.py
+++ /dev/null
@@ -1,414 +0,0 @@
-#!/usr/bin/env python
-
-__applicationName__ = "doxypy"
-__blurb__ = """
-doxypy is an input filter for Doxygen. It preprocesses python
-files so that docstrings of classes and functions are reformatted
-into Doxygen-conform documentation blocks.
-"""
-
-__doc__ = __blurb__ + \
-"""
-In order to make Doxygen preprocess files through doxypy, simply
-add the following lines to your Doxyfile:
- FILTER_SOURCE_FILES = YES
- INPUT_FILTER = "python /path/to/doxypy.py"
-"""
-
-__version__ = "0.4.2"
-__date__ = "14th October 2009"
-__website__ = "http://code.foosel.org/doxypy"
-
-__author__ = (
- "Philippe 'demod' Neumann (doxypy at demod dot org)",
- "Gina 'foosel' Haeussge (gina at foosel dot net)"
-)
-
-__licenseName__ = "GPL v2"
-__license__ = """This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-import sys
-import re
-
-from optparse import OptionParser, OptionGroup
-
-class FSM(object):
- """Implements a finite state machine.
-
- Transitions are given as 4-tuples, consisting of an origin state, a target
- state, a condition for the transition (given as a reference to a function
- which gets called with a given piece of input) and a pointer to a function
- to be called upon the execution of the given transition.
- """
-
- """
- @var transitions holds the transitions
- @var current_state holds the current state
- @var current_input holds the current input
- @var current_transition hold the currently active transition
- """
-
- def __init__(self, start_state=None, transitions=[]):
- self.transitions = transitions
- self.current_state = start_state
- self.current_input = None
- self.current_transition = None
-
- def setStartState(self, state):
- self.current_state = state
-
- def addTransition(self, from_state, to_state, condition, callback):
- self.transitions.append([from_state, to_state, condition, callback])
-
- def makeTransition(self, input):
- """Makes a transition based on the given input.
-
- @param input input to parse by the FSM
- """
- for transition in self.transitions:
- [from_state, to_state, condition, callback] = transition
- if from_state == self.current_state:
- match = condition(input)
- if match:
- self.current_state = to_state
- self.current_input = input
- self.current_transition = transition
- if options.debug:
- print >>sys.stderr, "# FSM: executing (%s -> %s) for line '%s'" % (from_state, to_state, input)
- callback(match)
- return
-
-class Doxypy(object):
- def __init__(self):
- string_prefixes = "[uU]?[rR]?"
-
- self.start_single_comment_re = re.compile("^\s*%s(''')" % string_prefixes)
- self.end_single_comment_re = re.compile("(''')\s*$")
-
- self.start_double_comment_re = re.compile("^\s*%s(\"\"\")" % string_prefixes)
- self.end_double_comment_re = re.compile("(\"\"\")\s*$")
-
- self.single_comment_re = re.compile("^\s*%s(''').*(''')\s*$" % string_prefixes)
- self.double_comment_re = re.compile("^\s*%s(\"\"\").*(\"\"\")\s*$" % string_prefixes)
-
- self.defclass_re = re.compile("^(\s*)(def .+:|class .+:)")
- self.empty_re = re.compile("^\s*$")
- self.hashline_re = re.compile("^\s*#.*$")
- self.importline_re = re.compile("^\s*(import |from .+ import)")
-
- self.multiline_defclass_start_re = re.compile("^(\s*)(def|class)(\s.*)?$")
- self.multiline_defclass_end_re = re.compile(":\s*$")
-
- ## Transition list format
- # ["FROM", "TO", condition, action]
- transitions = [
- ### FILEHEAD
-
- # single line comments
- ["FILEHEAD", "FILEHEAD", self.single_comment_re.search, self.appendCommentLine],
- ["FILEHEAD", "FILEHEAD", self.double_comment_re.search, self.appendCommentLine],
-
- # multiline comments
- ["FILEHEAD", "FILEHEAD_COMMENT_SINGLE", self.start_single_comment_re.search, self.appendCommentLine],
- ["FILEHEAD_COMMENT_SINGLE", "FILEHEAD", self.end_single_comment_re.search, self.appendCommentLine],
- ["FILEHEAD_COMMENT_SINGLE", "FILEHEAD_COMMENT_SINGLE", self.catchall, self.appendCommentLine],
- ["FILEHEAD", "FILEHEAD_COMMENT_DOUBLE", self.start_double_comment_re.search, self.appendCommentLine],
- ["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD", self.end_double_comment_re.search, self.appendCommentLine],
- ["FILEHEAD_COMMENT_DOUBLE", "FILEHEAD_COMMENT_DOUBLE", self.catchall, self.appendCommentLine],
-
- # other lines
- ["FILEHEAD", "FILEHEAD", self.empty_re.search, self.appendFileheadLine],
- ["FILEHEAD", "FILEHEAD", self.hashline_re.search, self.appendFileheadLine],
- ["FILEHEAD", "FILEHEAD", self.importline_re.search, self.appendFileheadLine],
- ["FILEHEAD", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
- ["FILEHEAD", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.resetCommentSearch],
- ["FILEHEAD", "DEFCLASS_BODY", self.catchall, self.appendFileheadLine],
-
- ### DEFCLASS
-
- # single line comments
- ["DEFCLASS", "DEFCLASS_BODY", self.single_comment_re.search, self.appendCommentLine],
- ["DEFCLASS", "DEFCLASS_BODY", self.double_comment_re.search, self.appendCommentLine],
-
- # multiline comments
- ["DEFCLASS", "COMMENT_SINGLE", self.start_single_comment_re.search, self.appendCommentLine],
- ["COMMENT_SINGLE", "DEFCLASS_BODY", self.end_single_comment_re.search, self.appendCommentLine],
- ["COMMENT_SINGLE", "COMMENT_SINGLE", self.catchall, self.appendCommentLine],
- ["DEFCLASS", "COMMENT_DOUBLE", self.start_double_comment_re.search, self.appendCommentLine],
- ["COMMENT_DOUBLE", "DEFCLASS_BODY", self.end_double_comment_re.search, self.appendCommentLine],
- ["COMMENT_DOUBLE", "COMMENT_DOUBLE", self.catchall, self.appendCommentLine],
-
- # other lines
- ["DEFCLASS", "DEFCLASS", self.empty_re.search, self.appendDefclassLine],
- ["DEFCLASS", "DEFCLASS", self.defclass_re.search, self.resetCommentSearch],
- ["DEFCLASS", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.resetCommentSearch],
- ["DEFCLASS", "DEFCLASS_BODY", self.catchall, self.stopCommentSearch],
-
- ### DEFCLASS_BODY
-
- ["DEFCLASS_BODY", "DEFCLASS", self.defclass_re.search, self.startCommentSearch],
- ["DEFCLASS_BODY", "DEFCLASS_MULTI", self.multiline_defclass_start_re.search, self.startCommentSearch],
- ["DEFCLASS_BODY", "DEFCLASS_BODY", self.catchall, self.appendNormalLine],
-
- ### DEFCLASS_MULTI
- ["DEFCLASS_MULTI", "DEFCLASS", self.multiline_defclass_end_re.search, self.appendDefclassLine],
- ["DEFCLASS_MULTI", "DEFCLASS_MULTI", self.catchall, self.appendDefclassLine],
- ]
-
- self.fsm = FSM("FILEHEAD", transitions)
- self.outstream = sys.stdout
-
- self.output = []
- self.comment = []
- self.filehead = []
- self.defclass = []
- self.indent = ""
-
- def __closeComment(self):
- """Appends any open comment block and triggering block to the output."""
-
- if options.autobrief:
- if len(self.comment) == 1 \
- or (len(self.comment) > 2 and self.comment[1].strip() == ''):
- self.comment[0] = self.__docstringSummaryToBrief(self.comment[0])
-
- if self.comment:
- block = self.makeCommentBlock()
- self.output.extend(block)
-
- if self.defclass:
- self.output.extend(self.defclass)
-
- def __docstringSummaryToBrief(self, line):
- """Adds \\brief to the docstrings summary line.
-
- A \\brief is prepended, provided no other doxygen command is at the
- start of the line.
- """
- stripped = line.strip()
- if stripped and not stripped[0] in ('@', '\\'):
- return "\\brief " + line
- else:
- return line
-
- def __flushBuffer(self):
- """Flushes the current outputbuffer to the outstream."""
- if self.output:
- try:
- if options.debug:
- print >>sys.stderr, "# OUTPUT: ", self.output
- print >>self.outstream, "\n".join(self.output)
- self.outstream.flush()
- except IOError:
- # Fix for FS#33. Catches "broken pipe" when doxygen closes
- # stdout prematurely upon usage of INPUT_FILTER, INLINE_SOURCES
- # and FILTER_SOURCE_FILES.
- pass
- self.output = []
-
- def catchall(self, input):
- """The catchall-condition, always returns true."""
- return True
-
- def resetCommentSearch(self, match):
- """Restarts a new comment search for a different triggering line.
-
- Closes the current commentblock and starts a new comment search.
- """
- if options.debug:
- print >>sys.stderr, "# CALLBACK: resetCommentSearch"
- self.__closeComment()
- self.startCommentSearch(match)
-
- def startCommentSearch(self, match):
- """Starts a new comment search.
-
- Saves the triggering line, resets the current comment and saves
- the current indentation.
- """
- if options.debug:
- print >>sys.stderr, "# CALLBACK: startCommentSearch"
- self.defclass = [self.fsm.current_input]
- self.comment = []
- self.indent = match.group(1)
-
- def stopCommentSearch(self, match):
- """Stops a comment search.
-
- Closes the current commentblock, resets the triggering line and
- appends the current line to the output.
- """
- if options.debug:
- print >>sys.stderr, "# CALLBACK: stopCommentSearch"
- self.__closeComment()
-
- self.defclass = []
- self.output.append(self.fsm.current_input)
-
- def appendFileheadLine(self, match):
- """Appends a line in the FILEHEAD state.
-
- Closes the open comment block, resets it and appends the current line.
- """
- if options.debug:
- print >>sys.stderr, "# CALLBACK: appendFileheadLine"
- self.__closeComment()
- self.comment = []
- self.output.append(self.fsm.current_input)
-
- def appendCommentLine(self, match):
- """Appends a comment line.
-
- The comment delimiter is removed from multiline start and ends as
- well as singleline comments.
- """
- if options.debug:
- print >>sys.stderr, "# CALLBACK: appendCommentLine"
- (from_state, to_state, condition, callback) = self.fsm.current_transition
-
- # single line comment
- if (from_state == "DEFCLASS" and to_state == "DEFCLASS_BODY") \
- or (from_state == "FILEHEAD" and to_state == "FILEHEAD"):
- # remove comment delimiter from begin and end of the line
- activeCommentDelim = match.group(1)
- line = self.fsm.current_input
- self.comment.append(line[line.find(activeCommentDelim)+len(activeCommentDelim):line.rfind(activeCommentDelim)])
-
- if (to_state == "DEFCLASS_BODY"):
- self.__closeComment()
- self.defclass = []
- # multiline start
- elif from_state == "DEFCLASS" or from_state == "FILEHEAD":
- # remove comment delimiter from begin of the line
- activeCommentDelim = match.group(1)
- line = self.fsm.current_input
- self.comment.append(line[line.find(activeCommentDelim)+len(activeCommentDelim):])
- # multiline end
- elif to_state == "DEFCLASS_BODY" or to_state == "FILEHEAD":
- # remove comment delimiter from end of the line
- activeCommentDelim = match.group(1)
- line = self.fsm.current_input
- self.comment.append(line[0:line.rfind(activeCommentDelim)])
- if (to_state == "DEFCLASS_BODY"):
- self.__closeComment()
- self.defclass = []
- # in multiline comment
- else:
- # just append the comment line
- self.comment.append(self.fsm.current_input)
-
- def appendNormalLine(self, match):
- """Appends a line to the output."""
- if options.debug:
- print >>sys.stderr, "# CALLBACK: appendNormalLine"
- self.output.append(self.fsm.current_input)
-
- def appendDefclassLine(self, match):
- """Appends a line to the triggering block."""
- if options.debug:
- print >>sys.stderr, "# CALLBACK: appendDefclassLine"
- self.defclass.append(self.fsm.current_input)
-
- def makeCommentBlock(self):
- """Indents the current comment block with respect to the current
- indentation level.
-
- @returns a list of indented comment lines
- """
- doxyStart = "##"
- commentLines = self.comment
-
- commentLines = map(lambda x: "%s# %s" % (self.indent, x), commentLines)
- l = [self.indent + doxyStart]
- l.extend(commentLines)
-
- return l
-
- def parse(self, input):
- """Parses a python file given as input string and returns the doxygen-
- compatible representation.
-
- @param input the python code to parse
- @returns the modified python code
- """
- lines = input.split("\n")
-
- for line in lines:
- self.fsm.makeTransition(line)
-
- if self.fsm.current_state == "DEFCLASS":
- self.__closeComment()
-
- return "\n".join(self.output)
-
- def parseFile(self, filename):
- """Parses a python file given as input string and returns the doxygen-
- compatible representation.
-
- @param input the python code to parse
- @returns the modified python code
- """
- f = open(filename, 'r')
-
- for line in f:
- self.parseLine(line.rstrip('\r\n'))
- if self.fsm.current_state == "DEFCLASS":
- self.__closeComment()
- self.__flushBuffer()
- f.close()
-
- def parseLine(self, line):
- """Parse one line of python and flush the resulting output to the
- outstream.
-
- @param line the python code line to parse
- """
- self.fsm.makeTransition(line)
- self.__flushBuffer()
-
-def optParse():
- """Parses commandline options."""
- parser = OptionParser(prog=__applicationName__, version="%prog " + __version__)
-
- parser.set_usage("%prog [options] filename")
- parser.add_option("--autobrief",
- action="store_true", dest="autobrief",
- help="use the docstring summary line as \\brief description"
- )
- parser.add_option("--debug",
- action="store_true", dest="debug",
- help="enable debug output on stderr"
- )
-
- ## parse options
- global options
- (options, filename) = parser.parse_args()
-
- if not filename:
- print >>sys.stderr, "No filename given."
- sys.exit(-1)
-
- return filename[0]
-
-def main():
- """Starts the parser on the file given by the filename as the first
- argument on the commandline.
- """
- filename = optParse()
- fsm = Doxypy()
- fsm.parseFile(filename)
-
-if __name__ == "__main__":
- main()
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/a62eb6f0/doc/bin/py_filter.sh.in
----------------------------------------------------------------------
diff --git a/doc/bin/py_filter.sh.in b/doc/bin/py_filter.sh.in
deleted file mode 100755
index 887ec05..0000000
--- a/doc/bin/py_filter.sh.in
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-FILTER="../bin/doxypy.py /dev/stdin"
-
-@M4_BINARY@ @_M4_ARGUMENTS@ $1 | ${FILTER}
[4/5] incubator-madlib git commit: SVM: Ensure clean code and
consistency
Posted by ri...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/svm/test/svm.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/test/svm.sql_in b/src/ports/postgres/modules/svm/test/svm.sql_in
new file mode 100644
index 0000000..7fdc26c
--- /dev/null
+++ b/src/ports/postgres/modules/svm/test/svm.sql_in
@@ -0,0 +1,838 @@
+/* -----------------------------------------------------------------------------
+ * Test Linear Support Vector Machine
+ * -------------------------------------------------------------------------- */
+
+CREATE OR REPLACE FUNCTION __svm_target_cl_func(ind float8[])
+RETURNS float8 AS $$
+BEGIN
+ IF (ind[1] > 0 AND ind[2] < 0) THEN RETURN 1; END IF;
+ RETURN -1;
+END
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION __svr_target_cl_func(ind float8[])
+RETURNS float8 AS $$
+BEGIN
+ RETURN 1*ind[1] + 2*ind[2];
+END
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION __svm_random_ind(d INT)
+RETURNS float8[] AS $$
+DECLARE
+ ret float8[];
+BEGIN
+ FOR i IN 1..(d-1) LOOP
+ ret[i] = RANDOM() * 40 - 20;
+ END LOOP;
+ IF (RANDOM() > 0.5) THEN
+ ret[d] = 10;
+ ELSE
+ ret[d] = -10;
+ END IF;
+ RETURN ret;
+END
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION svm_generate_cls_data(
+ output_table text, num int, dim int)
+RETURNS VOID AS $$
+DECLARE
+ temp_table text;
+BEGIN
+ temp_table := 'madlib_temp_' || output_table;
+ EXECUTE 'DROP TABLE IF EXISTS ' || temp_table;
+ EXECUTE '
+ CREATE TABLE ' || temp_table || ' AS
+ SELECT
+ subq.val AS id,
+ __svm_random_ind(' || dim || ') AS ind
+ FROM
+ (SELECT generate_series(1, ' || num || ') AS val) subq';
+ EXECUTE '
+ CREATE TABLE ' || output_table || ' AS
+ SELECT id, ind, __svm_target_cl_func(ind) AS label
+ FROM ' || temp_table;
+END
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION svr_generate_cls_data(
+ output_table text, num int, dim int)
+RETURNS VOID AS $$
+DECLARE
+ temp_table text;
+BEGIN
+ temp_table := 'madlib_temp_' || output_table;
+ EXECUTE 'DROP TABLE IF EXISTS ' || temp_table;
+ EXECUTE '
+ CREATE TABLE ' || temp_table || ' AS
+ SELECT
+ subq.val AS id,
+ __svm_random_ind(' || dim || ') AS ind
+ FROM
+ (SELECT generate_series(1, ' || num || ') AS val) subq';
+ EXECUTE '
+ CREATE TABLE ' || output_table || ' AS
+ SELECT id, ind, __svr_target_cl_func(ind) AS label
+ FROM ' || temp_table;
+END
+$$ LANGUAGE plpgsql;
+
+DROP TABLE IF EXISTS svm_train_data;
+SELECT svm_generate_cls_data('svm_train_data', 1000, 4);
+DROP TABLE IF EXISTS svm_test_data;
+SELECT svm_generate_cls_data('svm_test_data', 1000, 4);
+DROP TABLE IF EXISTS svr_train_data;
+SELECT svr_generate_cls_data('svr_train_data', 1000, 4);
+DROP TABLE IF EXISTS svr_test_data;
+SELECT svr_generate_cls_data('svr_test_data', 1000, 4);
+
+-- check the default values
+DROP TABLE IF EXISTS svr_model, svr_model_summary;
+SELECT svm_regression(
+ 'svr_train_data',
+ 'svr_model',
+ 'label',
+ 'ind');
+\x on
+SELECT * FROM svr_model;
+SELECT * FROM svr_model_summary;
+\x off
+SELECT
+ assert(
+ norm1(coef) < 4,
+ 'optimal coef should be close to [1, 2, 0, 0]!')
+FROM svr_model;
+
+-- check the use of l1 norm
+DROP TABLE IF EXISTS svr_model, svr_model_summary;
+SELECT svm_regression(
+ 'svr_train_data',
+ 'svr_model',
+ 'label',
+ 'ind',
+ NULL,
+ NULL,
+ NULL,
+ 'init_stepsize=0.01, max_iter=50, lambda=2, norm=l2, epsilon=0.01',
+ false);
+DROP TABLE IF EXISTS svr_test_result;
+SELECT svm_predict('svr_model', 'svr_train_data', 'id', 'svr_test_result');
+\x on
+SELECT * FROM svr_model;
+\x off
+SELECT
+ assert(
+ avg(subq.err) < 0.1,
+ 'prediction error is too large!')
+FROM
+ (
+ SELECT
+ train.id,
+ abs(train.label - test.prediction) AS err
+ FROM svr_train_data AS train, svr_test_result AS test
+ WHERE train.id = test.id
+ ) AS subq;
+
+-- by default using epsilon == 0.1
+DROP TABLE IF EXISTS svr_model, svr_model_summary;
+SELECT svm_regression(
+ 'svr_train_data',
+ 'svr_model',
+ 'label',
+ 'ind',
+ NULL,
+ NULL,
+ NULL,
+ 'init_stepsize=1, max_iter=10, lambda=2');
+SELECT
+ assert(epsilon > 0,'default epsilon is positive!')
+FROM svr_model_summary;
+
+-- Example usage for LINEAR classification, replace the above by
+SELECT svm_classification(
+ 'svm_train_data',
+ 'lclss',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, --grouping_col
+ 'max_iter=10, tolerance=0' --optim_params
+ );
+SELECT * FROM lclss;
+SELECT * FROM lclss_summary;
+
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('lclss', 'svm_test_data', 'id', 'svm_test_predict');
+
+-- checking correctness with pre-conditioning
+DROP TABLE IF EXISTS svm_normalized CASCADE;
+CREATE TABLE svm_normalized AS
+SELECT
+ id,
+ array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
+ label
+FROM svm_train_data,
+ (
+ SELECT ARRAY[avg(ind[1]),avg(ind[2]),
+ avg(ind[3]),avg(ind[4])] AS ind_avg
+ FROM svm_train_data
+ ) AS svm_ind_avg,
+ (
+ SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
+ stddev(ind[3]),stddev(ind[4])] AS ind_stddev
+ FROM svm_train_data
+ ) AS svm_ind_stddev
+ORDER BY random();
+
+DROP TABLE IF EXISTS svm_test_normalized CASCADE;
+CREATE TABLE svm_test_normalized AS
+SELECT
+ id,
+ array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
+ label
+FROM svm_test_data,
+ (
+ SELECT ARRAY[avg(ind[1]),avg(ind[2]),
+ avg(ind[3]),avg(ind[4])] AS ind_avg
+ FROM svm_test_data
+ ) AS svm_test_ind_avg,
+ (
+ SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
+ stddev(ind[3]),stddev(ind[4])] AS ind_stddev
+ FROM svm_test_data
+ ) AS svm_test_ind_stddev;
+
+----------------------------------------------------------------
+-- serial
+-- learning
+DROP TABLE IF EXISTS svm_model CASCADE;
+DROP TABLE IF EXISTS svm_model_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized',
+ 'svm_model',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, -- grouping_col
+ 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=0',
+ true -- verbose
+ );
+\x on
+SELECT * FROM svm_model;
+SELECT * FROM svm_model_summary;
+\x off
+
+-- l2
+DROP TABLE IF EXISTS svm_model_small_norm2 CASCADE;
+DROP TABLE IF EXISTS svm_model_small_norm2_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized',
+ 'svm_model_small_norm2',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, --grouping_col
+ 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=1'
+ );
+\x on
+SELECT * FROM svm_model_small_norm2;
+\x off
+
+SELECT
+ assert(
+ norm2(l2.coef) < norm2(noreg.coef),
+ 'l2 regularization should produce coef with smaller l2 norm!')
+FROM svm_model AS noreg, svm_model_small_norm2 AS l2;
+
+
+-- l1 makes sprase models
+DROP TABLE IF EXISTS svm_model_very_sparse CASCADE;
+DROP TABLE IF EXISTS svm_model_very_sparse_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized',
+ 'svm_model_very_sparse',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, --grouping_col
+ 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=1, norm=L1'
+ );
+\x on
+SELECT * FROM svm_model_very_sparse;
+\x off
+SELECT
+ assert(
+ count(*) > 0,
+ 'The model is supposed to be sparse with reg=1')
+FROM
+(
+ SELECT unnest(coef) AS w_i FROM svm_model_very_sparse
+) subq
+WHERE w_i != 0;
+
+-- predicting
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('svm_model','svm_test_normalized', 'id', 'svm_test_predict');
+
+-- calculating accuracy
+-- the accuracy is not guaranteed to be high because the stepsize & decay_factor
+-- depend on the actual number of segments
+SELECT
+ count(*) AS misclassification_count
+FROM svm_test_predict NATURAL JOIN svm_test_normalized
+WHERE prediction <> label;
+
+----------------------------------------------------------------
+-- decay factor non-zero
+-- learning
+DROP TABLE IF EXISTS svm_model CASCADE;
+DROP TABLE IF EXISTS svm_model_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized',
+ 'svm_model',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, --grouping_col
+ 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda={0.001}',
+ true -- verbose
+ );
+SELECT norm_of_gradient FROM svm_model;
+
+-- predicting
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+CREATE TABLE svm_test_predict AS
+SELECT
+ svm_test_normalized.id,
+ CASE WHEN array_dot(coef, ind) >= 0 THEN 1 ELSE -1 END AS prediction,
+ label
+FROM svm_test_normalized, svm_model;
+
+-- stats for info
+SELECT count(*) AS misclassification_count
+FROM svm_test_predict
+WHERE prediction <> label;
+
+
+-----------------------------------------------------------------
+-- labels that are not just 1,-1
+DROP TABLE IF EXISTS svm_normalized_fancy_label CASCADE;
+CREATE TABLE svm_normalized_fancy_label AS
+SELECT
+ id,
+ array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
+ CASE when label = 1 THEN 'YES'
+ ELSE 'NO'
+ END AS label,
+ (id % 4) AS gid
+FROM svm_train_data,
+ (
+ SELECT ARRAY[avg(ind[1]),avg(ind[2]),
+ avg(ind[3]),avg(ind[4])] AS ind_avg
+ FROM svm_train_data
+ ) AS svm_ind_avg,
+ (
+ SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
+ stddev(ind[3]),stddev(ind[4])] AS ind_stddev
+ FROM svm_train_data
+ ) AS svm_ind_stddev
+ORDER BY random();
+INSERT INTO svm_normalized_fancy_label VALUES
+(1001, ARRAY[NULL,1,1,1,1]::float8[], 'YES', 1001 % 4),
+(1002, ARRAY[5,1,1,1,1]::float8[], NULL, 1002 % 4),
+(1003, ARRAY[5,1,NULL,1,1]::float8[], NULL, 1003 % 4);
+
+DROP TABLE IF EXISTS svm_test_normalized_fancy_label CASCADE;
+CREATE TABLE svm_test_normalized_fancy_label AS
+SELECT
+ id,
+ array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
+ CASE when label = 1 THEN 'YES'
+ ELSE 'NO'
+ END AS label,
+ (id % 4) as gid
+FROM svm_test_data,
+ (
+ SELECT ARRAY[avg(ind[1]),avg(ind[2]),
+ avg(ind[3]),avg(ind[4])] AS ind_avg
+ FROM svm_test_data
+ ) AS svm_test_ind_avg,
+ (
+ SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
+ stddev(ind[3]),stddev(ind[4])] AS ind_stddev
+ FROM svm_test_data
+ ) AS svm_test_ind_stddev;
+INSERT INTO svm_test_normalized_fancy_label VALUES
+(1001, ARRAY[NULL,1,1,1,1]::float8[], 'YES', 1001 % 4);
+
+-- training
+DROP TABLE IF EXISTS svm_model_fancy_label CASCADE;
+DROP TABLE IF EXISTS svm_model_fancy_label_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized_fancy_label',
+ 'svm_model_fancy_label',
+ 'label',
+ 'ind',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ 'gid', --grouping_col
+ 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda=0.001',
+ TRUE -- verbose
+ );
+\x on
+SELECT * FROM svm_model_fancy_label;
+SELECT * FROM svm_model_fancy_label_summary;
+\x off
+SELECT assert(count(*)=4, '4 group exist') FROM svm_model_fancy_label;
+-- SELECT assert(total_rows_skipped=3, 'total_rows_skipped is wrong')
+-- FROM svm_model_fancy_label_summary;
+
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('svm_model_fancy_label', 'svm_test_normalized_fancy_label', 'id', 'svm_test_predict');
+SELECT o.id, label, prediction, o.gid FROM svm_test_predict p, svm_test_normalized_fancy_label o where o.id = p.id;
+
+-- calculating accuracy
+-- the accuracy is not guaranteed to be high because the stepsize & decay_factor
+-- depend on the actual number of segments
+-- SELECT
+-- count(*) AS misclassification_count
+-- FROM svm_test_predict NATURAL JOIN svm_test_normalized_fancy_label
+-- WHERE prediction <> label;
+
+-- tests for depend varname being expression
+DROP TABLE IF EXISTS svm_model_expression CASCADE;
+DROP TABLE IF EXISTS svm_model_expression_summary CASCADE;
+SELECT svm_classification(
+ 'svm_normalized',
+ 'svm_model_expression',
+ 'label>(ind[2]+ind[4])',
+ 'ARRAY[ind[1],ind[3],ind[5]]',
+ NULL, -- kernel_func
+ NULL, -- kernel_pararms
+ NULL, --grouping_col
+ 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda=0.001',
+ true -- verbose
+ );
+\x on
+SELECT * FROM svm_model_expression;
+SELECT * FROM svm_model_expression_summary;
+\x off
+
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('svm_model_expression', 'svm_test_normalized', 'id', 'svm_test_predict');
+SELECT * FROM svm_test_predict;
+
+DROP TABLE IF EXISTS abalone_train_small_tmp;
+CREATE TABLE abalone_train_small_tmp (
+ sex TEXT,
+ id SERIAL NOT NULL,
+ length DOUBLE PRECISION,
+ diameter DOUBLE PRECISION,
+ height DOUBLE PRECISION,
+ whole DOUBLE PRECISION,
+ shucked DOUBLE PRECISION,
+ viscera DOUBLE PRECISION,
+ shell DOUBLE PRECISION,
+ rings INTEGER);
+
+INSERT INTO abalone_train_small_tmp(id,sex,length,diameter,height,whole,shucked,viscera,shell,rings) VALUES
+(1040,'F',0.66,0.475,0.18,1.3695,0.641,0.294,0.335,6),
+(3160,'F',0.34,0.255,0.085,0.204,0.097,0.021,0.05,6),
+(3984,'F',0.585,0.45,0.125,0.874,0.3545,0.2075,0.225,6),
+(861,'F',0.595,0.475,0.16,1.1405,0.547,0.231,0.271,6),
+(932,'F',0.445,0.335,0.11,0.4355,0.2025,0.1095,0.1195,6),
+(1585,'F',0.515,0.375,0.11,0.6065,0.3005,0.131,0.15,6),
+(3187,'F',0.47,0.36,0.11,0.4965,0.237,0.127,0.13,6),
+(3202,'F',0.385,0.3,0.1,0.2725,0.1115,0.057,0.08,6),
+(949,'F',0.475,0.36,0.12,0.5915,0.3245,0.11,0.127,6),
+(2582,'F',0.53,0.42,0.17,0.828,0.41,0.208,0.1505,6),
+(2551,'I',0.28,0.22,0.08,0.1315,0.066,0.024,0.03,5),
+(1246,'I',0.385,0.28,0.09,0.228,0.1025,0.042,0.0655,5),
+(819,'I',0.35,0.25,0.07,0.18,0.0655,0.048,0.054,6),
+(297,'I',0.275,0.205,0.075,0.1105,0.045,0.0285,0.035,6),
+(3630,'I',0.27,0.205,0.05,0.084,0.03,0.0185,0.029,6),
+(2196,'I',0.26,0.215,0.08,0.099,0.037,0.0255,0.045,5),
+(2343,'I',0.255,0.185,0.07,0.075,0.028,0.018,0.025,6),
+(49,'I',0.325,0.245,0.07,0.161,0.0755,0.0255,0.045,6),
+(2185,'I',0.32,0.235,0.08,0.1485,0.064,0.031,0.045,6),
+(2154,'I',0.28,0.2,0.075,0.1225,0.0545,0.0115,0.035,5),
+(1996,'I',0.32,0.24,0.07,0.133,0.0585,0.0255,0.041,6),
+(126,'I',0.27,0.195,0.06,0.073,0.0285,0.0235,0.03,5),
+(1227,'I',0.35,0.27,0.075,0.215,0.1,0.036,0.065,6),
+(3969,'I',0.375,0.29,0.095,0.2875,0.123,0.0605,0.08,6),
+(2505,'I',0.31,0.24,0.105,0.2885,0.118,0.065,0.083,6),
+(2039,'I',0.28,0.215,0.08,0.132,0.072,0.022,0.033,5),
+(829,'I',0.41,0.325,0.1,0.394,0.208,0.0655,0.106,6),
+(3197,'I',0.325,0.245,0.075,0.1495,0.0605,0.033,0.045,5),
+(1447,'I',0.44,0.34,0.105,0.369,0.164,0.08,0.1015,5),
+(2821,'I',0.375,0.285,0.09,0.2545,0.119,0.0595,0.0675,6),
+(1828,'I',0.34,0.26,0.085,0.1885,0.0815,0.0335,0.06,6),
+(2002,'I',0.36,0.27,0.085,0.2185,0.1065,0.038,0.062,6),
+(785,'I',0.215,0.155,0.06,0.0525,0.021,0.0165,0.015,5),
+(2199,'I',0.27,0.19,0.08,0.081,0.0265,0.0195,0.03,6),
+(3527,'I',0.335,0.26,0.085,0.192,0.097,0.03,0.054,6),
+(466,'I',0.175,0.125,0.05,0.0235,0.008,0.0035,0.008,5),
+(425,'I',0.26,0.2,0.07,0.092,0.037,0.02,0.03,6),
+(1825,'I',0.185,0.135,0.04,0.027,0.0105,0.0055,0.009,5),
+(3815,'I',0.38,0.275,0.095,0.2425,0.106,0.0485,0.21,6),
+(2503,'I',0.285,0.21,0.07,0.109,0.044,0.0265,0.033,5),
+(3998,'I',0.36,0.27,0.09,0.2075,0.098,0.039,0.062,6),
+(333,'I',0.3,0.22,0.08,0.121,0.0475,0.042,0.035,5),
+(1837,'I',0.415,0.31,0.09,0.2815,0.1245,0.0615,0.085,6),
+(2813,'I',0.24,0.17,0.05,0.0545,0.0205,0.016,0.0155,5),
+(930,'I',0.44,0.345,0.13,0.4495,0.209,0.0835,0.134,6),
+(1436,'I',0.385,0.3,0.09,0.247,0.1225,0.044,0.0675,5),
+(3972,'I',0.4,0.295,0.095,0.252,0.1105,0.0575,0.066,6),
+(1433,'I',0.365,0.255,0.08,0.1985,0.0785,0.0345,0.053,5),
+(1252,'I',0.405,0.285,0.09,0.2645,0.1265,0.0505,0.075,6),
+(3439,'I',0.43,0.335,0.105,0.378,0.188,0.0785,0.09,6),
+(1250,'I',0.395,0.27,0.1,0.2985,0.1445,0.061,0.082,5),
+(2865,'I',0.31,0.23,0.07,0.1245,0.0505,0.0265,0.038,6),
+(3411,'I',0.415,0.31,0.105,0.3595,0.167,0.083,0.0915,6),
+(1539,'I',0.355,0.27,0.075,0.1775,0.079,0.0315,0.054,6),
+(1990,'I',0.28,0.21,0.075,0.1195,0.053,0.0265,0.03,6),
+(1771,'I',0.455,0.335,0.105,0.422,0.229,0.0865,0.1,6),
+(2291,'I',0.325,0.27,0.1,0.185,0.08,0.0435,0.065,6),
+(3381,'I',0.19,0.13,0.045,0.0265,0.009,0.005,0.009,5),
+(1545,'I',0.37,0.27,0.095,0.2175,0.097,0.046,0.065,6),
+(652,'I',0.335,0.245,0.09,0.1665,0.0595,0.04,0.06,6),
+(3434,'I',0.365,0.27,0.105,0.2155,0.0915,0.0475,0.063,6),
+(2004,'I',0.375,0.28,0.08,0.226,0.105,0.047,0.065,6),
+(2000,'I',0.35,0.25,0.07,0.1605,0.0715,0.0335,0.046,6),
+(3946,'I',0.235,0.175,0.065,0.0615,0.0205,0.02,0.019,6),
+(177,'I',0.315,0.21,0.06,0.125,0.06,0.0375,0.035,5),
+(920,'I',0.41,0.31,0.09,0.3335,0.1635,0.061,0.091,6),
+(3437,'I',0.38,0.275,0.095,0.2505,0.0945,0.0655,0.075,6),
+(2630,'I',0.33,0.24,0.075,0.163,0.0745,0.033,0.048,6),
+(1092,'I',0.45,0.33,0.11,0.3685,0.16,0.0885,0.102,6),
+(3476,'I',0.4,0.315,0.085,0.2675,0.116,0.0585,0.0765,6),
+(3526,'I',0.33,0.23,0.085,0.1695,0.079,0.026,0.0505,6),
+(1534,'I',0.295,0.215,0.07,0.121,0.047,0.0155,0.0405,6),
+(921,'I',0.415,0.33,0.09,0.3595,0.17,0.081,0.09,6),
+(2206,'I',0.275,0.22,0.08,0.1365,0.0565,0.0285,0.042,6),
+(1218,'I',0.315,0.23,0.08,0.1375,0.0545,0.031,0.0445,5),
+(1998,'I',0.335,0.25,0.08,0.1695,0.0695,0.044,0.0495,6),
+(2455,'I',0.275,0.2,0.065,0.092,0.0385,0.0235,0.027,5),
+(2548,'I',0.23,0.18,0.05,0.064,0.0215,0.0135,0.02,5),
+(3996,'I',0.245,0.175,0.055,0.0785,0.04,0.018,0.02,5),
+(3408,'I',0.35,0.265,0.08,0.192,0.081,0.0465,0.053,6),
+(3907,'M',0.245,0.18,0.065,0.0635,0.0245,0.0135,0.02,4),
+(3850,'M',0.385,0.3,0.115,0.3435,0.1645,0.085,0.1025,6),
+(124,'M',0.37,0.265,0.075,0.214,0.09,0.051,0.07,6),
+(2583,'M',0.53,0.41,0.14,0.681,0.3095,0.1415,0.1835,6),
+(526,'M',0.175,0.125,0.04,0.024,0.0095,0.006,0.005,4),
+(2184,'M',0.495,0.4,0.155,0.8085,0.2345,0.1155,0.35,6),
+(2132,'M',0.32,0.24,0.08,0.18,0.08,0.0385,0.055,6),
+(651,'M',0.255,0.18,0.065,0.079,0.034,0.014,0.025,5),
+(612,'M',0.195,0.145,0.05,0.032,0.01,0.008,0.012,4),
+(958,'M',0.5,0.39,0.135,0.6595,0.3145,0.1535,0.1565,6),
+(3174,'M',0.35,0.265,0.09,0.2265,0.0995,0.0575,0.065,6),
+(265,'M',0.27,0.2,0.08,0.1205,0.0465,0.028,0.04,6),
+(519,'M',0.325,0.23,0.09,0.147,0.06,0.034,0.045,4),
+(2382,'M',0.155,0.115,0.025,0.024,0.009,0.005,0.0075,5),
+(698,'M',0.28,0.205,0.1,0.1165,0.0545,0.0285,0.03,5),
+(2381,'M',0.175,0.135,0.04,0.0305,0.011,0.0075,0.01,5),
+(516,'M',0.27,0.195,0.08,0.1,0.0385,0.0195,0.03,6),
+(831,'M',0.415,0.305,0.1,0.325,0.156,0.0505,0.091,6),
+(3359,'M',0.285,0.215,0.075,0.106,0.0415,0.023,0.035,5);
+
+DROP TABLE IF EXISTS abalone_train_small;
+CREATE TABLE abalone_train_small AS (
+ SELECT * FROM abalone_train_small_tmp
+);
+
+-- create epsilon input table
+
+DROP TABLE IF EXISTS abalone_eps;
+CREATE TABLE abalone_eps (
+ sex TEXT,
+ epsilon DOUBLE PRECISION);
+
+INSERT INTO abalone_eps(sex, epsilon) VALUES
+('I', 0.2),
+('M', 0.05);
+
+-- solve it with grouping and table of epsilon as inputs
+
+DROP TABLE IF EXISTS svr_mdl, svr_mdl_summary;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ NULL,NULL,'sex',
+ 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 50, eps_table=abalone_eps',
+ false);
+SELECT * FROM svr_mdl;
+
+
+DROP TABLE IF EXISTS svr_mdl_i, svr_mdl_i_summary;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl_i',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ NULL,NULL,'sex',
+ 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.2',
+ false);
+SELECT * FROM svr_mdl_i where sex = 'I';
+
+DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl_m',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ NULL,NULL,'sex',
+ 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.05',
+ false);
+SELECT * FROM svr_mdl_m where sex = 'M';
+
+DROP TABLE IF EXISTS svr_mdl_f, svr_mdl_f_summary;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl_f',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ NULL,NULL,'sex',
+ 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 50',
+ false);
+SELECT * FROM svr_mdl_f where sex = 'F';
+
+-- verify that the results are the same
+
+SELECT assert(
+ abs_err < 1e-5,
+ 'SVR with epsilon table input: Wrong results!')
+FROM (
+ SELECT
+ abs(t1.norm_of_gradient - t2.norm_of_gradient) AS abs_err
+ FROM svr_mdl_f AS t1 JOIN svr_mdl AS t2 USING (sex)
+ where sex = 'F'
+) AS q1;
+
+SELECT assert(
+ rel_err < 1e-1,
+ 'SVR with epsilon table input: Wrong results!')
+FROM (
+ SELECT
+ relative_error(t1.norm_of_gradient, t2.norm_of_gradient) AS rel_err
+ FROM svr_mdl_i AS t1 JOIN svr_mdl AS t2 USING (sex)
+ where sex = 'I'
+) AS q1;
+
+SELECT assert(
+ rel_err < 1e-1,
+ 'SVR with epsilon table input: Wrong results!')
+FROM (
+ SELECT
+ relative_error(t1.norm_of_gradient, t2.norm_of_gradient) AS rel_err
+ FROM svr_mdl_m AS t1 JOIN svr_mdl AS t2 USING (sex)
+ where sex = 'M'
+) AS q1;
+
+DROP TABLE IF EXISTS m1, m1_summary;
+SELECT svm_regression(
+ 'svr_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ NULL,NULL,NULL,
+ 'init_stepsize=0.01, max_iter=3, lambda=[0.0002, 0.2], '
+ 'n_folds=3, epsilon = [0.003, 0.2]',
+ true);
+
+DROP TABLE IF EXISTS m1, m1_summary;
+SELECT svm_regression(
+ 'svr_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ NULL,NULL,NULL,
+ 'init_stepsize=0.01, max_iter=2, lambda=[0.0002, 0.2], n_folds=3',
+ false);
+-- check which lambda is selected
+SELECT reg_params FROM m1_summary;
+
+-- epsilon values are ignored
+-- the validation table only contains
+-- init_stepsize and lambda
+DROP TABLE IF EXISTS m1, m1_summary, val_res;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ NULL,NULL,NULL,
+ 'init_stepsize=[0.01, 1], max_iter=3, lambda=[20, 0.0002, 0.02], '
+ 'n_folds=3, epsilon=[0.1, 1], validation_result=val_res');
+SELECT * FROM val_res;
+
+DROP TABLE IF EXISTS m1, m1_summary, val_res;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ NULL,NULL,NULL,
+ 'init_stepsize=0.01, max_iter=20, lambda=[20, 0.0002, 0.02], '
+ 'n_folds=3, validation_result=val_res');
+SELECT * FROM val_res;
+-- check which lambda is selected
+SELECT reg_params FROM m1_summary;
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+-- accuracy with cv
+SELECT
+ count(*) AS misclassification_count
+FROM svm_test_predict NATURAL JOIN svm_test_data
+WHERE prediction <> label;
+
+DROP TABLE IF EXISTS m1, m1_summary;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ NULL,NULL,NULL,
+ 'init_stepsize=0.01, max_iter=20, lambda=0.000002');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+-- accuracy without cv
+SELECT
+ count(*) AS misclassification_count
+FROM svm_test_predict NATURAL JOIN svm_test_data
+WHERE prediction <> label;
+
+-- SVM with kernels -----------------------------------------------------------
+-- verify guassian kernel mapping dimensions
+DROP TABLE IF EXISTS m1, m1_summary, m1_random;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3',
+ NULL,
+ 'max_iter=2');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+
+-- verify gaussian kernel with grouping
+-- verify partial string support in kernel specification
+DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary, svr_mdl_m_random;
+SELECT svm_regression(
+ 'abalone_train_small',
+ 'svr_mdl_m',
+ 'rings',
+ 'ARRAY[1,diameter,shell,shucked,length]',
+ 'gau',
+ 'n_components=10',
+ 'sex',
+ 'max_iter=2, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.05',
+ false);
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('svr_mdl_m','abalone_train_small', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 10,
+ 'The dimension of the coefficients must be equal to n_components (10)!')
+FROM svr_mdl_m;
+
+-- verify guassian kernel with cross validation
+DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3',
+ NULL,
+ 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+
+-- verify guassian kernel with out-of-memory support
+DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
+SELECT svm_classification(
+ 'svm_train_data',
+ 'm1',
+ 'label',
+ 'ind',
+ 'gaussian',
+ 'n_components=3, in_memory=0',
+ NULL,
+ 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
+DROP TABLE IF EXISTS svm_test_predict CASCADE;
+SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
+SELECT
+ assert(
+ array_upper(coef, 1) = 3,
+ 'The dimension of the coefficients must be equal to n_components (3)!')
+FROM m1;
+
+DROP TABLE IF EXISTS kernel_data;
+CREATE TABLE kernel_data (
+ index bigint,
+ x1 double precision,
+ x2 double precision,
+ y double precision
+);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (0, 0.400000000000000022, -0.699999999999999956, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (1, -1.5, -1, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (2, -1.39999999999999991, -0.900000000000000022, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (3, -1.30000000000000004, -1.19999999999999996, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (4, -1.10000000000000009, -0.200000000000000011, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (5, -1.19999999999999996, -0.400000000000000022, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (6, -0.5, 1.19999999999999996, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (7, -1.5, 2.10000000000000009, 0);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (8, 1, 1, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (9, 1.30000000000000004, 0.800000000000000044, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (10, 1.19999999999999996, 0.5, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (11, 0.200000000000000011, -2, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (12, 0.5, -2.39999999999999991, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (13, 0.200000000000000011, -2.29999999999999982, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (14, 0, -2.70000000000000018, 1);
+INSERT INTO kernel_data (index, x1, x2, y) VALUES (15, 1.30000000000000004, 2.10000000000000009, 1);
+
+
+DROP TABLE IF EXISTS m1, m1_summary, m1_random;
+SELECT svm_classification(
+ 'kernel_data',
+ 'm1',
+ 'y',
+ 'array[x1, x2]',
+ 'gaussian',
+ 'gamma=1, n_components=20, random_state=2',
+ NULL,
+ 'init_stepsize=1, max_iter=10');
+SELECT * FROM m1;
+DROP TABLE IF EXISTS kernel_predict CASCADE;
+SELECT svm_predict('m1','kernel_data', 'index', 'kernel_predict');
+SELECT
+ count(*) as misclassification
+FROM kernel_predict NATURAL JOIN kernel_data
+WHERE prediction <> y;
+SELECT
+ assert(count(*) = 0, 'Using kernel should perfectly fit the data!')
+FROM kernel_predict NATURAL JOIN kernel_data
+WHERE prediction <> y;
+
[5/5] incubator-madlib git commit: SVM: Ensure clean code and
consistency
Posted by ri...@apache.org.
SVM: Ensure clean code and consistency
Closes #10
Project: http://git-wip-us.apache.org/repos/asf/incubator-madlib/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-madlib/commit/8fa2f539
Tree: http://git-wip-us.apache.org/repos/asf/incubator-madlib/tree/8fa2f539
Diff: http://git-wip-us.apache.org/repos/asf/incubator-madlib/diff/8fa2f539
Branch: refs/heads/master
Commit: 8fa2f539f394bb38107ece3a0c9a2da714641978
Parents: 9b01260
Author: Rahul Iyer <ri...@pivotal.io>
Authored: Wed Feb 10 17:32:17 2016 -0800
Committer: Rahul Iyer <ri...@pivotal.io>
Committed: Fri Feb 12 10:53:35 2016 -0800
----------------------------------------------------------------------
methods/array_ops/src/pg_gp/array_ops.c | 2 -
methods/array_ops/src/pg_gp/array_ops.sql_in | 2 -
src/modules/linalg/matrix_ops.cpp | 18 +-
.../postgres/modules/linalg/matrix_ops.py_in | 64 +-
.../postgres/modules/linalg/matrix_ops.sql_in | 7 +-
.../modules/svm/kernel_approximation.py_in | 107 +--
src/ports/postgres/modules/svm/svm.py_in | 111 ++-
.../postgres/modules/svm/test/linear_svm.sql_in | 831 ------------------
src/ports/postgres/modules/svm/test/svm.sql_in | 838 +++++++++++++++++++
9 files changed, 987 insertions(+), 993 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/methods/array_ops/src/pg_gp/array_ops.c
----------------------------------------------------------------------
diff --git a/methods/array_ops/src/pg_gp/array_ops.c b/methods/array_ops/src/pg_gp/array_ops.c
index 57fd694..57ee3bf 100644
--- a/methods/array_ops/src/pg_gp/array_ops.c
+++ b/methods/array_ops/src/pg_gp/array_ops.c
@@ -1970,5 +1970,3 @@ General_Array_to_Array(
return pgarray;
}
-
-/******* internal functions ********/
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/methods/array_ops/src/pg_gp/array_ops.sql_in
----------------------------------------------------------------------
diff --git a/methods/array_ops/src/pg_gp/array_ops.sql_in b/methods/array_ops/src/pg_gp/array_ops.sql_in
index 70de776..80f50ab 100644
--- a/methods/array_ops/src/pg_gp/array_ops.sql_in
+++ b/methods/array_ops/src/pg_gp/array_ops.sql_in
@@ -620,5 +620,3 @@ DROP FUNCTION IF EXISTS MADLIB_SCHEMA.array_contains_null(float8[]) CASCADE;
CREATE OR REPLACE FUNCTION MADLIB_SCHEMA.array_contains_null(x anyarray) RETURNS BOOLEAN
AS 'MODULE_PATHNAME', 'array_contains_null' LANGUAGE C IMMUTABLE STRICT
m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `NO SQL', `');
-
-/* Internal functions */
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/modules/linalg/matrix_ops.cpp
----------------------------------------------------------------------
diff --git a/src/modules/linalg/matrix_ops.cpp b/src/modules/linalg/matrix_ops.cpp
index c6f9286..307fa52 100644
--- a/src/modules/linalg/matrix_ops.cpp
+++ b/src/modules/linalg/matrix_ops.cpp
@@ -238,15 +238,13 @@ AnyType normal_vector::run(AnyType & args)
if (dim < 1) {
throw std::invalid_argument("invalid argument - dim should be positive");
}
- MutableArrayHandle<double> r = madlib_construct_array(
- NULL, dim, FLOAT8TI.oid, FLOAT8TI.len, FLOAT8TI.byval, FLOAT8TI.align);
-
+ ColumnVector r(dim);
boost::minstd_rand generator(seed);
- boost::normal_distribution<> nd_dist(mu,sigma);
+ boost::normal_distribution<> nd_dist(mu, sigma);
boost::variate_generator<boost::minstd_rand&, boost::normal_distribution<> > nd(generator, nd_dist);
for (int i = 0; i < dim; i++){
- *(r.ptr() + i) = (double)nd();
+ r(i) = (double)nd();
}
return r;
}
@@ -261,15 +259,12 @@ AnyType uniform_vector::run(AnyType & args)
if (dim < 1) {
throw std::invalid_argument("invalid argument - dim should be positive");
}
- MutableArrayHandle<double> r = madlib_construct_array(
- NULL, dim, FLOAT8TI.oid, FLOAT8TI.len, FLOAT8TI.byval, FLOAT8TI.align);
-
+ ColumnVector r(dim);
boost::minstd_rand generator(seed);
boost::uniform_real<> uni_dist(min_,max_);
boost::variate_generator<boost::minstd_rand&, boost::uniform_real<> > uni(generator, uni_dist);
-
for (int i = 0; i < dim; i++){
- *(r.ptr() + i) = (double)uni();
+ r(i) = (double)uni();
}
return r;
}
@@ -309,8 +304,7 @@ AnyType matrix_vec_mult_in_mem_1d::run(AnyType & args){
return v;
}
-AnyType rand_block::run(AnyType & args)
-{
+AnyType rand_block::run(AnyType & args) {
int row_dim = args[0].getAs<int>();
int col_dim = args[1].getAs<int>();
if (row_dim < 1 || col_dim < 1) {
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/linalg/matrix_ops.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/linalg/matrix_ops.py_in b/src/ports/postgres/modules/linalg/matrix_ops.py_in
index 12d8cd8..53b5e59 100644
--- a/src/ports/postgres/modules/linalg/matrix_ops.py_in
+++ b/src/ports/postgres/modules/linalg/matrix_ops.py_in
@@ -3089,7 +3089,7 @@ def matrix_ones(schema_madlib, row_dim, col_dim, matrix_out, out_args):
def matrix_random(schema_madlib, distribution, row_dim, col_dim,
- in_args, matrix_out, out_args):
+ in_args, matrix_out, out_args):
""" Create a row_dim by col_dim random matrix from distribution.
"""
_validate_output_table(matrix_out)
@@ -3100,51 +3100,49 @@ def matrix_random(schema_madlib, distribution, row_dim, col_dim,
out_args = parse_matrix_args(
out_args, in_default_args={'row': 'row', 'col': 'col', 'val': 'val'})
- distribution = 'uniform' if not distribution else distribution.lower()
- supported_dist = ['uniform', 'normal']
- try:
- distribution = next(x for x in supported_dist
- if x.startswith(distribution))
- except StopIteration:
- # next() returns a StopIteration if no element found
- plpy.error("Matrix Error: Invalid distribution: "
- "{0}. Supported distribution are ({1})"
- .format(distribution, ','.join(sorted(supported_dist))))
+ if distribution:
+ supported_dist = ['uniform', 'normal']
+ try:
+ distribution = next(x for x in supported_dist
+ if x.startswith(distribution))
+ except StopIteration:
+ # next() returns a StopIteration if no element found
+ plpy.error("Matrix Error: Invalid distribution: "
+ "{0}. Supported distributions: ({1})"
+ .format(distribution, ', '.join(sorted(supported_dist))))
+ else:
+ distribution = 'uniform'
in_args_default = {
'seed': randint(1, 1000),
'mu': 0,
'sigma': 1,
- 'min_a': 0,
- 'max_b': 1}
+ 'min': 0,
+ 'max': 1}
in_args_types = {
'seed': int,
'mu': float,
'sigma': float,
- 'min_a': float,
- 'max_b': float}
+ 'min': float,
+ 'max': float}
- in_args_vals = extract_keyvalue_params(in_args,
- in_args_types,
- in_args_default)
+ in_args_vals = extract_keyvalue_params(in_args, in_args_types, in_args_default)
if distribution == 'normal':
- random_row = ('{schema_madlib}.__normal_vector({size},'
- '{mu},{sigma},{seed}+row)'
- .format(size=col_dim,
- mu=in_args_vals['mu'],
- sigma=in_args_vals['sigma'],
- seed=in_args_vals['seed'],
- schema_madlib=schema_madlib))
- elif distribution == 'uniform':
- random_row = ('{schema_madlib}.__uniform_vector({size},'
- '{a},{b},{seed}+row)'
- .format(size=col_dim,
- a=in_args_vals['min_a'],
- b=in_args_vals['max_b'],
- seed=in_args_vals['seed'],
- schema_madlib=schema_madlib))
+ random_row = ("""{schema_madlib}.__normal_vector(
+ {col_dim},
+ {in_args_vals[mu]},
+ {in_args_vals[sigma]},
+ {in_args_vals[seed]} + row)
+ """.format(**locals()))
+ else:
+ random_row = ("""{schema_madlib}.__uniform_vector(
+ {col_dim},
+ {in_args_vals[min]},
+ {in_args_vals[max]},
+ {in_args_vals[seed]} + row)
+ """.format(**locals()))
plpy.execute("""
CREATE TABLE {matrix_out}
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/linalg/matrix_ops.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/linalg/matrix_ops.sql_in b/src/ports/postgres/modules/linalg/matrix_ops.sql_in
index f74dd8e..65f4fdb 100644
--- a/src/ports/postgres/modules/linalg/matrix_ops.sql_in
+++ b/src/ports/postgres/modules/linalg/matrix_ops.sql_in
@@ -173,6 +173,9 @@ in the glossary.
-- Create a diag matrix initialized with given diagonal elements
<b>matrix_diag</b>( diag_elements, matrix_out, out_args)
+-- Create a matrix initialized with values sampled from a distribution
+-- Supported distributions: normal and uniform
+ <b>matrix_random</b>( distribution, row_dim, col_dim, in_args, matrix_out, out_args )
</pre>
- <b>Decomposition operations</b>
@@ -2372,10 +2375,10 @@ m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `CONTAINS SQL', `');
CREATE OR REPLACE FUNCTION
MADLIB_SCHEMA.matrix_random
(
- distribution TEXT,
row_dim INTEGER,
col_dim INTEGER,
in_args TEXT,
+ distribution TEXT,
matrix_out TEXT,
out_args TEXT
)
@@ -2395,7 +2398,7 @@ MADLIB_SCHEMA.matrix_random
matrix_out TEXT
)
RETURNS MADLIB_SCHEMA.matrix_result AS $$
- SELECT MADLIB_SCHEMA.matrix_random('uniform', $1, $2, ''::TEXT, $3, ''::TEXT)
+ SELECT MADLIB_SCHEMA.matrix_random($1, $2, ''::TEXT, 'uniform', $3, ''::TEXT)
$$ LANGUAGE SQL
m4_ifdef(`__HAS_FUNCTION_PROPERTIES__', `MODIFIES SQL DATA', `');
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/svm/kernel_approximation.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/kernel_approximation.py_in b/src/ports/postgres/modules/svm/kernel_approximation.py_in
index 2fe2318..04aa018 100644
--- a/src/ports/postgres/modules/svm/kernel_approximation.py_in
+++ b/src/ports/postgres/modules/svm/kernel_approximation.py_in
@@ -11,7 +11,9 @@ from math import pi
class GaussianKernelBase(object):
+
"""docstring for gaussianKernel"""
+
def __init__(self, schema_madlib, gamma, n_components, random_state,
random_weights, random_offset, id_col, val_col,
orig_data, **kwargs):
@@ -39,24 +41,26 @@ class GaussianKernelBase(object):
def _random_weights(self, row_dim, col_dim, rd_id, rd_val):
rd_weights = unique_string(desp='random_weights')
- sigma = sqrt(2*self.gamma)
+ sigma = sqrt(2 * self.gamma)
plpy.execute("""
drop table if exists {rd_weights};
select {self.schema_madlib}.matrix_random(
- 'normal',{row_dim},{col_dim},
+ {row_dim}, {col_dim},
'mu=0, sigma={sigma}, seed={self.random_state}',
+ 'normal',
'{rd_weights}','row={rd_id}, val={rd_val}');
""".format(**locals()))
return rd_weights
def _random_offsets(self, row_dim, col_dim, rd_id, rd_val):
rd_offset = unique_string(desp='random_offsets')
- max_b = 2*pi
+ max_ = 2 * pi
plpy.execute("""
drop table if exists {rd_offset};
select {self.schema_madlib}.matrix_random(
- 'uniform',{row_dim},{col_dim},
- 'min_a=0, max_b={max_b}, seed={self.random_state}',
+ {row_dim}, {col_dim},
+ 'min=0, max={max_}, seed={self.random_state}',
+ 'uniform',
'{rd_offset}','row={rd_id}, val={rd_val}');
""".format(**locals()))
return rd_offset
@@ -75,38 +79,34 @@ class GaussianKernelBase(object):
def __del__(self):
self.clear()
- def saveAs(self, name):
+ def save_as(self, name):
if self.orig_data:
plpy.warning("Gaussian Kernel Warning: no need to save."
- "Original data table exists: {0}"
- .format(self.orig_data))
+ "Original data table exists: {0}".
+ format(self.orig_data))
return
run_sql = """
create table {name} as
select
- {id} as id, {val} as val,
+ {self.rd_id} as id, {self.rd_val} as val,
'offsets' as desp
- from {rd_offset}
+ from {self.rd_offset}
union
select
- {id} as id, {val} as val,
+ {self.rd_id} as id, {self.rd_val} as val,
'weights' as desp
- from {rd_weights}
- """.format(name=name,
- id=self.rd_id,
- val=self.rd_val,
- rd_offset=self.rd_offset,
- rd_weights=self.rd_weights)
+ from {self.rd_weights}
+ """.format(**locals())
plpy.execute(run_sql)
@classmethod
def parse_params(cls, kernel_params='', n_features=10):
params_default = {
'in_memory': 1,
- 'gamma': 1/n_features,
+ 'gamma': 1 / n_features,
'random_state': 1,
- 'n_components': 2*n_features}
+ 'n_components': 2 * n_features}
params_types = {
'in_memory': int,
'gamma': float,
@@ -121,14 +121,14 @@ class GaussianKernelBase(object):
params = cls.parse_params(kernel_params, n_features)
in_memory = params.pop('in_memory', True)
# according to the 1gb limit on each entry of the table
- nelems = params['n_components']*n_features
- if in_memory and nelems <= 1e8:
+ n_elems = params['n_components'] * n_features
+ if in_memory and n_elems <= 1e8:
return GaussianKernelInMemory(schema_madlib, **params)
else:
return GaussianKernel(schema_madlib, **params)
@classmethod
- def loadFrom(cls, schema_madlib, data, kernel_params=''):
+ def load_from(cls, schema_madlib, data, kernel_params=''):
rd_weights = unique_string(desp='random_weights')
rd_offset = unique_string(desp='random_offsets')
rd_val = unique_string(desp='val')
@@ -148,25 +148,28 @@ class GaussianKernelBase(object):
in_memory = params.pop('in_memory', True)
if in_memory:
return GaussianKernelInMemory(schema_madlib,
- random_weights=rd_weights,
- random_offset=rd_offset,
- id_col=rd_id, val_col=rd_val,
- orig_data=data, **params)
+ random_weights=rd_weights,
+ random_offset=rd_offset,
+ id_col=rd_id, val_col=rd_val,
+ orig_data=data, **params)
else:
return GaussianKernel(schema_madlib,
- random_weights=rd_weights,
- random_offset=rd_offset,
- id_col=rd_id, val_col=rd_val,
- orig_data=data, **params)
+ random_weights=rd_weights,
+ random_offset=rd_offset,
+ id_col=rd_id, val_col=rd_val,
+ orig_data=data, **params)
class GaussianKernel(GaussianKernelBase):
+
"""docstring for gaussianKernel"""
+
def __init__(self, schema_madlib, gamma=1, n_components=100,
random_state=1, random_weights=None,
random_offset=None, id_col=None, val_col=None,
- orig_data=None):
- params = locals(); params.pop('self')
+ orig_data=None, **kwargs):
+ params = locals()
+ params.pop('self')
super(GaussianKernel, self).__init__(**params)
@property
@@ -200,9 +203,12 @@ class GaussianKernel(GaussianKernelBase):
schema_madlib = self.schema_madlib
- _null_str = "NULL::integer"
- _null_str_as = lambda s: _null_str + " as " + s if s else _null_str
- _verify = lambda x, s: str(x) if x else _null_str_as(s)
+ def _verify(x, s):
+ null_str = "NULL::integer"
+ if x:
+ return str(x)
+ else:
+ return null_str + " as " + s if s else null_str
grouping_col = _verify(grouping_col, unique_string('grp_col'))
dependent_varname = _verify(dependent_varname, '')
@@ -284,7 +290,7 @@ class GaussianKernel(GaussianKernelBase):
""".format(**locals())
plpy.execute(plpy.prepare(run_sql, ['float[]']), [rd_offset_vals])
# clear table generated from matrix mult
- plpy.execute("drop table {0};".format(temp_transformed))
+ plpy.execute("drop table if exists " + temp_transformed)
self.transformed_table = dict(index_col=index_col,
source_table=transformed,
dependent_varname=dependent_varname,
@@ -293,12 +299,15 @@ class GaussianKernel(GaussianKernelBase):
class GaussianKernelInMemory(GaussianKernelBase):
+
"""docstring for gaussianKernel"""
+
def __init__(self, schema_madlib, gamma=1, n_components=100,
random_state=1, random_weights=None,
random_offset=None, id_col=None,
- val_col=None, orig_data=None):
- params = locals(); params.pop('self')
+ val_col=None, orig_data=None, **kwargs):
+ params = locals()
+ params.pop('self')
super(GaussianKernelInMemory, self).__init__(**params)
@property
@@ -314,7 +323,7 @@ class GaussianKernelInMemory(GaussianKernelBase):
self.orig_data = None
self.rd_val = unique_string(desp='val')
self.rd_id = unique_string(desp='id')
- self.rd_weights = self._random_weights(1, n_features*self.n_components,
+ self.rd_weights = self._random_weights(1, n_features * self.n_components,
self.rd_id, self.rd_val)
self.rd_offset = self._random_offsets(1, self.n_components,
self.rd_id, self.rd_val)
@@ -332,9 +341,12 @@ class GaussianKernelInMemory(GaussianKernelBase):
schema_madlib = self.schema_madlib
- _null_str = "NULL::integer"
- _null_str_as = lambda s: _null_str + " as " + s if s else _null_str
- _verify = lambda x, s: str(x) if x else _null_str_as(s)
+ def _verify(x, s):
+ null_str = "NULL::integer"
+ if x:
+ return str(x)
+ else:
+ return null_str + " as " + s if s else null_str
grouping_col = _verify(grouping_col, unique_string('grp_col'))
dependent_varname = _verify(dependent_varname, '')
@@ -383,7 +395,7 @@ class GaussianKernelInMemory(GaussianKernelBase):
return self
-def createKernel(schema_madlib, n_features, kernel_func, kernel_params):
+def create_kernel(schema_madlib, n_features, kernel_func, kernel_params):
if kernel_func == 'linear':
return None
elif kernel_func == 'gaussian':
@@ -392,13 +404,8 @@ def createKernel(schema_madlib, n_features, kernel_func, kernel_params):
kernel_params)
-def loadKernel(schema_madlib, data, kernel_func, kernel_params):
+def load_kernel(schema_madlib, data, kernel_func, kernel_params):
if kernel_func == 'linear':
return None
elif kernel_func == 'gaussian':
- return GaussianKernelBase.loadFrom(schema_madlib, data, kernel_params)
-
-
-
-
-
+ return GaussianKernelBase.load_from(schema_madlib, data, kernel_params)
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/svm/svm.py_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/svm.py_in b/src/ports/postgres/modules/svm/svm.py_in
index 49e3ec0..4c5ac2c 100644
--- a/src/ports/postgres/modules/svm/svm.py_in
+++ b/src/ports/postgres/modules/svm/svm.py_in
@@ -2,6 +2,8 @@ from __future__ import division
import plpy
+from kernel_approximation import create_kernel, load_kernel
+
from utilities.control import MinWarning
from utilities.in_mem_group_control import GroupIterationController
from utilities.validate_args import explicit_bool_to_text
@@ -20,7 +22,6 @@ from utilities.validate_args import is_var_valid
from utilities.validate_args import get_expr_type
from validation.internal.cross_validation import CrossValidator
-from .kernel_approximation import createKernel, loadKernel
def _compute_svm(args):
@@ -92,7 +93,7 @@ def _verify_table(source_table, model_table, dependent_varname,
output_tbl_valid(summary_table, 'SVM')
-def _verify_grouping(schema_madlib, source_table, grouping_col):
+def _get_grouping_col_str(schema_madlib, source_table, grouping_col):
if grouping_col and grouping_col.lower() != 'null':
cols_in_tbl_valid(source_table,
_string_to_array_with_quotes(grouping_col),
@@ -138,7 +139,7 @@ def _verify_params_dict(params_dict):
return params_dict
-def _build_output_tables(n_iters_run, model_table, args, transformer,**kwargs):
+def _build_output_tables(n_iters_run, model_table, args, transformer, **kwargs):
if transformer is None:
dependent_varname = args['col_dep_var']
independent_varname = args['col_ind_var']
@@ -151,7 +152,7 @@ def _build_output_tables(n_iters_run, model_table, args, transformer,**kwargs):
independent_varname = original_table['independent_varname']
source_table = original_table['source_table']
random_table = add_postfix(model_table, "_random")
- transformer.saveAs(random_table)
+ transformer.save_as(random_table)
kernel_func = transformer.kernel_func
kernel_params = transformer.kernel_params
@@ -208,9 +209,16 @@ def _build_output_tables(n_iters_run, model_table, args, transformer,**kwargs):
dep_type=dep_type, **args)
plpy.execute(model_table_query)
- args['lambda_str'] = str(args['lambda'])
+ # summary table
+ n_failed_groups = plpy.execute("""
+ SELECT count(*) AS num_failed_groups
+ FROM {0}
+ WHERE coef IS NULL
+ """.format(model_table))[0]['num_failed_groups']
+
summary_table = add_postfix(model_table, "_summary")
grouping_text = "NULL" if not grouping_col else grouping_col
+ args.update(locals())
plpy.execute("""
CREATE TABLE {summary_table} AS
SELECT
@@ -227,25 +235,16 @@ def _build_output_tables(n_iters_run, model_table, args, transformer,**kwargs):
'decay_factor={decay_factor}, ' ||
'max_iter={max_iter}, ' ||
'tolerance={tolerance}'::text AS optim_params,
- 'lambda={lambda_str}, ' ||
- 'norm={norm}, ' ||
- 'n_folds={n_folds}'::text AS reg_params,
+ 'lambda={lambda}, norm={norm}, n_folds={n_folds}'::text
+ AS reg_params,
count(*)::integer AS num_all_groups,
- 0::integer AS num_failed_groups,
+ {n_failed_groups}::integer AS num_failed_groups,
sum(num_rows_processed)::bigint AS total_rows_processed,
sum(num_rows_skipped)::bigint AS total_rows_skipped,
'{epsilon}'::double precision AS epsilon,
'{eps_table}'::text AS eps_table
FROM {model_table};
- """.format(grouping_text=grouping_text,
- summary_table=summary_table,
- source_table=source_table,
- model_table=model_table,
- kernel_func=kernel_func,
- kernel_params=kernel_params,
- dependent_varname=dependent_varname,
- independent_varname=independent_varname,
- **args))
+ """.format(**args))
def svm_help(schema_madlib, message, is_svc, **kwargs):
@@ -464,12 +463,12 @@ def svm(schema_madlib, source_table, model_table,
model_table,
dependent_varname,
independent_varname)
- grouping_str, grouping_col = _verify_grouping(schema_madlib,
- source_table, grouping_col)
- kernel_func = _verify_kernel(kernel_func)
+ grouping_str, grouping_col = _get_grouping_col_str(schema_madlib,
+ source_table, grouping_col)
+ kernel_func = _get_kernel_name(kernel_func)
transformer = _random_feature_map(schema_madlib, source_table,
- dependent_varname, independent_varname,
- kernel_func, kernel_params, grouping_col)
+ dependent_varname, independent_varname,
+ kernel_func, kernel_params, grouping_col)
params_dict = _extract_params(schema_madlib, params)
args = locals()
if transformer is not None:
@@ -536,21 +535,23 @@ def _cross_validate_svm(args):
args.update(dict(transformer=transformer))
-def _verify_kernel(kernel_func):
- kernel_func = 'linear' if not kernel_func else kernel_func.lower()
- # Add non-linear kernels below after implementing them.
- supported_kernels = ['linear', 'gaussian']
- try:
- # allow user to specify a prefix substring of
- # supported kernel function names. This works because the supported
- # kernel functions have unique prefixes.
- kernel_func = next(x for x in supported_kernels
- if x.startswith(kernel_func))
- except StopIteration:
- # next() returns a StopIteration if no element found
- plpy.error("SVM Error: Invalid kernel function: "
- "{0}. Supported kernel functions are ({1})"
- .format(kernel_func, ','.join(sorted(supported_kernels))))
+def _get_kernel_name(kernel_func):
+ if not kernel_func:
+ kernel_func = 'linear'
+ else:
+ # Add non-linear kernels below after implementing them.
+ supported_kernels = ['linear', 'gaussian']
+ try:
+ # allow user to specify a prefix substring of
+ # supported kernels. This works because the supported
+ # kernels have unique prefixes.
+ kernel_func = next(x for x in supported_kernels
+ if x.startswith(kernel_func))
+ except StopIteration:
+ # next() returns a StopIteration if no element found
+ plpy.error("SVM Error: Invalid kernel function: "
+ "{0}. Supported kernel functions are ({1})"
+ .format(kernel_func, ','.join(sorted(supported_kernels))))
return kernel_func
@@ -561,8 +562,8 @@ def _random_feature_map(schema_madlib, source_table, dependent_varname,
return None
n_features = num_features(source_table, independent_varname)
- transformer = createKernel(schema_madlib, n_features,
- kernel_func, kernel_params)
+ transformer = create_kernel(schema_madlib, n_features,
+ kernel_func, kernel_params)
return (transformer.fit(n_features)
.transform(source_table, independent_varname,
dependent_varname, grouping_col))
@@ -653,9 +654,9 @@ def svm_predict(schema_madlib, model_table, new_data_table, id_col_name,
grouping_col = None if grouping_col == 'NULL' else grouping_col
input_tbl_valid(new_data_table, 'SVM')
- grouping_str, grouping_col = _verify_grouping(schema_madlib,
- new_data_table,
- grouping_col)
+ grouping_str, grouping_col = _get_grouping_col_str(schema_madlib,
+ new_data_table,
+ grouping_col)
_assert(is_var_valid(new_data_table, independent_varname),
"SVM Error: independent_varname ('" + independent_varname +
"') is invalid for new_data_table (" + new_data_table + ")!")
@@ -668,14 +669,10 @@ def svm_predict(schema_madlib, model_table, new_data_table, id_col_name,
if kernel_func.lower() != 'linear':
random_table = add_postfix(model_table, '_random')
input_tbl_valid(random_table, 'SVM')
- transformer = loadKernel(schema_madlib,
- random_table,
- kernel_func,
- kernel_params)
- transformer.transform(new_data_table,
- independent_varname,
- grouping_col=grouping_col,
- id_col=id_col_name)
+ transformer = load_kernel(schema_madlib, random_table,
+ kernel_func, kernel_params)
+ transformer.transform(new_data_table, independent_varname,
+ grouping_col=grouping_col, id_col=id_col_name)
transformed_table = transformer.transformed_table
new_data_table = transformed_table['source_table']
independent_varname = transformed_table['independent_varname']
@@ -820,13 +817,7 @@ def _process_epsilon(is_svc, args):
) q2
USING ({col_grp_key})
);
- """.format(rel_epsilon=rel_epsilon,
- col_grp_key=col_grp_key,
- epsilon=epsilon,
- grouping_str=grouping_str,
- rel_source=rel_source,
- grouping_col=grouping_col,
- eps_table=eps_table))
+ """.format(**locals()))
select_epsilon = (
"""
@@ -838,9 +829,7 @@ def _process_epsilon(is_svc, args):
{rel_epsilon}.{col_grp_key} = {as_rel_source}.{col_grp_key}
)
"""
- .format(rel_epsilon=rel_epsilon,
- as_rel_source=as_rel_source,
- col_grp_key=col_grp_key))
+ .format(**locals()))
return {'select_epsilon': select_epsilon,
'epsilon': epsilon,
http://git-wip-us.apache.org/repos/asf/incubator-madlib/blob/8fa2f539/src/ports/postgres/modules/svm/test/linear_svm.sql_in
----------------------------------------------------------------------
diff --git a/src/ports/postgres/modules/svm/test/linear_svm.sql_in b/src/ports/postgres/modules/svm/test/linear_svm.sql_in
deleted file mode 100644
index 8458190..0000000
--- a/src/ports/postgres/modules/svm/test/linear_svm.sql_in
+++ /dev/null
@@ -1,831 +0,0 @@
-/* -----------------------------------------------------------------------------
- * Test Linear Support Vector Machine
- * -------------------------------------------------------------------------- */
-
-CREATE OR REPLACE FUNCTION __svm_target_cl_func(ind float8[])
-RETURNS float8 AS $$
-BEGIN
- IF (ind[1] > 0 AND ind[2] < 0) THEN RETURN 1; END IF;
- RETURN -1;
-END
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION __svr_target_cl_func(ind float8[])
-RETURNS float8 AS $$
-BEGIN
- RETURN 1*ind[1] + 2*ind[2];
-END
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION __svm_random_ind(d INT)
-RETURNS float8[] AS $$
-DECLARE
- ret float8[];
-BEGIN
- FOR i IN 1..(d-1) LOOP
- ret[i] = RANDOM() * 40 - 20;
- END LOOP;
- IF (RANDOM() > 0.5) THEN
- ret[d] = 10;
- ELSE
- ret[d] = -10;
- END IF;
- RETURN ret;
-END
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION svm_generate_cls_data(
- output_table text, num int, dim int)
-RETURNS VOID AS $$
-DECLARE
- temp_table text;
-BEGIN
- temp_table := 'madlib_temp_' || output_table;
- EXECUTE '
- CREATE TABLE ' || temp_table || ' AS
- SELECT
- subq.val AS id,
- __svm_random_ind(' || dim || ') AS ind
- FROM
- (SELECT generate_series(1, ' || num || ') AS val) subq';
- EXECUTE '
- CREATE TABLE ' || output_table || ' AS
- SELECT id, ind, __svm_target_cl_func(ind) AS label
- FROM ' || temp_table;
-END
-$$ LANGUAGE plpgsql;
-
-CREATE OR REPLACE FUNCTION svr_generate_cls_data(
- output_table text, num int, dim int)
-RETURNS VOID AS $$
-DECLARE
- temp_table text;
-BEGIN
- temp_table := 'madlib_temp_' || output_table;
- EXECUTE '
- CREATE TABLE ' || temp_table || ' AS
- SELECT
- subq.val AS id,
- __svm_random_ind(' || dim || ') AS ind
- FROM
- (SELECT generate_series(1, ' || num || ') AS val) subq';
- EXECUTE '
- CREATE TABLE ' || output_table || ' AS
- SELECT id, ind, __svr_target_cl_func(ind) AS label
- FROM ' || temp_table;
-END
-$$ LANGUAGE plpgsql;
-
-SELECT svm_generate_cls_data('svm_train_data', 1000, 4);
-SELECT svm_generate_cls_data('svm_test_data', 1000, 4);
-SELECT svr_generate_cls_data('svr_train_data', 1000, 4);
-SELECT svr_generate_cls_data('svr_test_data', 1000, 4);
-
--- check the default values
-DROP TABLE IF EXISTS svr_model, svr_model_summary;
-SELECT svm_regression(
- 'svr_train_data',
- 'svr_model',
- 'label',
- 'ind');
-\x on
-SELECT * FROM svr_model;
-SELECT * FROM svr_model_summary;
-\x off
-SELECT
- assert(
- norm1(coef) < 4,
- 'optimal coef should be close to [1, 2, 0, 0]!')
-FROM svr_model;
-
--- check the use of l1 norm
-DROP TABLE IF EXISTS svr_model, svr_model_summary;
-SELECT svm_regression(
- 'svr_train_data',
- 'svr_model',
- 'label',
- 'ind',
- NULL,
- NULL,
- NULL,
- 'init_stepsize=0.01, max_iter=50, lambda=2, norm=l2, epsilon=0.01',
- false);
-DROP TABLE IF EXISTS svr_test_result;
-SELECT svm_predict('svr_model', 'svr_train_data', 'id', 'svr_test_result');
-\x on
-SELECT * FROM svr_model;
-\x off
-SELECT
- assert(
- avg(subq.err) < 0.1,
- 'prediction error is too large!')
-FROM
- (
- SELECT
- train.id,
- abs(train.label - test.prediction) AS err
- FROM svr_train_data AS train, svr_test_result AS test
- WHERE train.id = test.id
- ) AS subq;
-
--- by default using epsilon == 0.1
-DROP TABLE IF EXISTS svr_model, svr_model_summary;
-SELECT svm_regression(
- 'svr_train_data',
- 'svr_model',
- 'label',
- 'ind',
- NULL,
- NULL,
- NULL,
- 'init_stepsize=1, max_iter=10, lambda=2');
-SELECT
- assert(epsilon > 0,'default epsilon is positive!')
-FROM svr_model_summary;
-
--- Example usage for LINEAR classification, replace the above by
-SELECT svm_classification(
- 'svm_train_data',
- 'lclss',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, --grouping_col
- 'max_iter=10, tolerance=0' --optim_params
- );
-SELECT * FROM lclss;
-SELECT * FROM lclss_summary;
-
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('lclss', 'svm_test_data', 'id', 'svm_test_predict');
-
--- checking correctness with pre-conditioning
-DROP TABLE IF EXISTS svm_normalized CASCADE;
-CREATE TABLE svm_normalized AS
-SELECT
- id,
- array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
- label
-FROM svm_train_data,
- (
- SELECT ARRAY[avg(ind[1]),avg(ind[2]),
- avg(ind[3]),avg(ind[4])] AS ind_avg
- FROM svm_train_data
- ) AS svm_ind_avg,
- (
- SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
- stddev(ind[3]),stddev(ind[4])] AS ind_stddev
- FROM svm_train_data
- ) AS svm_ind_stddev
-ORDER BY random();
-
-DROP TABLE IF EXISTS svm_test_normalized CASCADE;
-CREATE TABLE svm_test_normalized AS
-SELECT
- id,
- array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
- label
-FROM svm_test_data,
- (
- SELECT ARRAY[avg(ind[1]),avg(ind[2]),
- avg(ind[3]),avg(ind[4])] AS ind_avg
- FROM svm_test_data
- ) AS svm_test_ind_avg,
- (
- SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
- stddev(ind[3]),stddev(ind[4])] AS ind_stddev
- FROM svm_test_data
- ) AS svm_test_ind_stddev;
-
-----------------------------------------------------------------
--- serial
--- learning
-DROP TABLE IF EXISTS svm_model CASCADE;
-DROP TABLE IF EXISTS svm_model_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized',
- 'svm_model',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, -- grouping_col
- 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=0',
- true -- verbose
- );
-\x on
-SELECT * FROM svm_model;
-SELECT * FROM svm_model_summary;
-\x off
-
--- l2
-DROP TABLE IF EXISTS svm_model_small_norm2 CASCADE;
-DROP TABLE IF EXISTS svm_model_small_norm2_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized',
- 'svm_model_small_norm2',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, --grouping_col
- 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=1'
- );
-\x on
-SELECT * FROM svm_model_small_norm2;
-\x off
-
-SELECT
- assert(
- norm2(l2.coef) < norm2(noreg.coef),
- 'l2 regularization should produce coef with smaller l2 norm!')
-FROM svm_model AS noreg, svm_model_small_norm2 AS l2;
-
-
--- l1 makes sprase models
-DROP TABLE IF EXISTS svm_model_very_sparse CASCADE;
-DROP TABLE IF EXISTS svm_model_very_sparse_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized',
- 'svm_model_very_sparse',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, --grouping_col
- 'init_stepsize=0.03, decay_factor=1, max_iter=5, tolerance=0, lambda=1, norm=L1'
- );
-\x on
-SELECT * FROM svm_model_very_sparse;
-\x off
-SELECT
- assert(
- count(*) > 0,
- 'The model is supposed to be sparse with reg=1')
-FROM
-(
- SELECT unnest(coef) AS w_i FROM svm_model_very_sparse
-) subq
-WHERE w_i != 0;
-
--- predicting
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('svm_model','svm_test_normalized', 'id', 'svm_test_predict');
-
--- calculating accuracy
--- the accuracy is not guaranteed to be high because the stepsize & decay_factor
--- depend on the actual number of segments
-SELECT
- count(*) AS misclassification_count
-FROM svm_test_predict NATURAL JOIN svm_test_normalized
-WHERE prediction <> label;
-
-----------------------------------------------------------------
--- decay factor non-zero
--- learning
-DROP TABLE IF EXISTS svm_model CASCADE;
-DROP TABLE IF EXISTS svm_model_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized',
- 'svm_model',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, --grouping_col
- 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda={0.001}',
- true -- verbose
- );
-SELECT norm_of_gradient FROM svm_model;
-
--- predicting
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-CREATE TABLE svm_test_predict AS
-SELECT
- svm_test_normalized.id,
- CASE WHEN array_dot(coef, ind) >= 0 THEN 1 ELSE -1 END AS prediction,
- label
-FROM svm_test_normalized, svm_model;
-
--- stats for info
-SELECT count(*) AS misclassification_count
-FROM svm_test_predict
-WHERE prediction <> label;
-
-
------------------------------------------------------------------
--- labels that are not just 1,-1
-DROP TABLE IF EXISTS svm_normalized_fancy_label CASCADE;
-CREATE TABLE svm_normalized_fancy_label AS
-SELECT
- id,
- array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
- CASE when label = 1 THEN 'YES'
- ELSE 'NO'
- END AS label,
- (id % 4) AS gid
-FROM svm_train_data,
- (
- SELECT ARRAY[avg(ind[1]),avg(ind[2]),
- avg(ind[3]),avg(ind[4])] AS ind_avg
- FROM svm_train_data
- ) AS svm_ind_avg,
- (
- SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
- stddev(ind[3]),stddev(ind[4])] AS ind_stddev
- FROM svm_train_data
- ) AS svm_ind_stddev
-ORDER BY random();
-INSERT INTO svm_normalized_fancy_label VALUES
-(1001, ARRAY[NULL,1,1,1,1]::float8[], 'YES', 1001 % 4),
-(1002, ARRAY[5,1,1,1,1]::float8[], NULL, 1002 % 4),
-(1003, ARRAY[5,1,NULL,1,1]::float8[], NULL, 1003 % 4);
-
-DROP TABLE IF EXISTS svm_test_normalized_fancy_label CASCADE;
-CREATE TABLE svm_test_normalized_fancy_label AS
-SELECT
- id,
- array_append(array_div(array_sub(ind, ind_avg), ind_stddev), 1::FLOAT8) AS ind,
- CASE when label = 1 THEN 'YES'
- ELSE 'NO'
- END AS label,
- (id % 4) as gid
-FROM svm_test_data,
- (
- SELECT ARRAY[avg(ind[1]),avg(ind[2]),
- avg(ind[3]),avg(ind[4])] AS ind_avg
- FROM svm_test_data
- ) AS svm_test_ind_avg,
- (
- SELECT ARRAY[stddev(ind[1]),stddev(ind[2]),
- stddev(ind[3]),stddev(ind[4])] AS ind_stddev
- FROM svm_test_data
- ) AS svm_test_ind_stddev;
-INSERT INTO svm_test_normalized_fancy_label VALUES
-(1001, ARRAY[NULL,1,1,1,1]::float8[], 'YES', 1001 % 4);
-
--- training
-DROP TABLE IF EXISTS svm_model_fancy_label CASCADE;
-DROP TABLE IF EXISTS svm_model_fancy_label_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized_fancy_label',
- 'svm_model_fancy_label',
- 'label',
- 'ind',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- 'gid', --grouping_col
- 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda=0.001',
- TRUE -- verbose
- );
-\x on
-SELECT * FROM svm_model_fancy_label;
-SELECT * FROM svm_model_fancy_label_summary;
-\x off
-SELECT assert(count(*)=4, '4 group exist') FROM svm_model_fancy_label;
--- SELECT assert(total_rows_skipped=3, 'total_rows_skipped is wrong')
--- FROM svm_model_fancy_label_summary;
-
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('svm_model_fancy_label', 'svm_test_normalized_fancy_label', 'id', 'svm_test_predict');
-SELECT o.id, label, prediction, o.gid FROM svm_test_predict p, svm_test_normalized_fancy_label o where o.id = p.id;
-
--- calculating accuracy
--- the accuracy is not guaranteed to be high because the stepsize & decay_factor
--- depend on the actual number of segments
--- SELECT
--- count(*) AS misclassification_count
--- FROM svm_test_predict NATURAL JOIN svm_test_normalized_fancy_label
--- WHERE prediction <> label;
-
--- tests for depend varname being expression
-DROP TABLE IF EXISTS svm_model_expression CASCADE;
-DROP TABLE IF EXISTS svm_model_expression_summary CASCADE;
-SELECT svm_classification(
- 'svm_normalized',
- 'svm_model_expression',
- 'label>(ind[2]+ind[4])',
- 'ARRAY[ind[1],ind[3],ind[5]]',
- NULL, -- kernel_func
- NULL, -- kernel_pararms
- NULL, --grouping_col
- 'init_stepsize=0.03, decay_factor=0.9, max_iter=5, tolerance=0, lambda=0.001',
- true -- verbose
- );
-\x on
-SELECT * FROM svm_model_expression;
-SELECT * FROM svm_model_expression_summary;
-\x off
-
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('svm_model_expression', 'svm_test_normalized', 'id', 'svm_test_predict');
-SELECT * FROM svm_test_predict;
-
-DROP TABLE IF EXISTS abalone_train_small_tmp;
-CREATE TABLE abalone_train_small_tmp (
- sex TEXT,
- id SERIAL NOT NULL,
- length DOUBLE PRECISION,
- diameter DOUBLE PRECISION,
- height DOUBLE PRECISION,
- whole DOUBLE PRECISION,
- shucked DOUBLE PRECISION,
- viscera DOUBLE PRECISION,
- shell DOUBLE PRECISION,
- rings INTEGER);
-
-INSERT INTO abalone_train_small_tmp(id,sex,length,diameter,height,whole,shucked,viscera,shell,rings) VALUES
-(1040,'F',0.66,0.475,0.18,1.3695,0.641,0.294,0.335,6),
-(3160,'F',0.34,0.255,0.085,0.204,0.097,0.021,0.05,6),
-(3984,'F',0.585,0.45,0.125,0.874,0.3545,0.2075,0.225,6),
-(861,'F',0.595,0.475,0.16,1.1405,0.547,0.231,0.271,6),
-(932,'F',0.445,0.335,0.11,0.4355,0.2025,0.1095,0.1195,6),
-(1585,'F',0.515,0.375,0.11,0.6065,0.3005,0.131,0.15,6),
-(3187,'F',0.47,0.36,0.11,0.4965,0.237,0.127,0.13,6),
-(3202,'F',0.385,0.3,0.1,0.2725,0.1115,0.057,0.08,6),
-(949,'F',0.475,0.36,0.12,0.5915,0.3245,0.11,0.127,6),
-(2582,'F',0.53,0.42,0.17,0.828,0.41,0.208,0.1505,6),
-(2551,'I',0.28,0.22,0.08,0.1315,0.066,0.024,0.03,5),
-(1246,'I',0.385,0.28,0.09,0.228,0.1025,0.042,0.0655,5),
-(819,'I',0.35,0.25,0.07,0.18,0.0655,0.048,0.054,6),
-(297,'I',0.275,0.205,0.075,0.1105,0.045,0.0285,0.035,6),
-(3630,'I',0.27,0.205,0.05,0.084,0.03,0.0185,0.029,6),
-(2196,'I',0.26,0.215,0.08,0.099,0.037,0.0255,0.045,5),
-(2343,'I',0.255,0.185,0.07,0.075,0.028,0.018,0.025,6),
-(49,'I',0.325,0.245,0.07,0.161,0.0755,0.0255,0.045,6),
-(2185,'I',0.32,0.235,0.08,0.1485,0.064,0.031,0.045,6),
-(2154,'I',0.28,0.2,0.075,0.1225,0.0545,0.0115,0.035,5),
-(1996,'I',0.32,0.24,0.07,0.133,0.0585,0.0255,0.041,6),
-(126,'I',0.27,0.195,0.06,0.073,0.0285,0.0235,0.03,5),
-(1227,'I',0.35,0.27,0.075,0.215,0.1,0.036,0.065,6),
-(3969,'I',0.375,0.29,0.095,0.2875,0.123,0.0605,0.08,6),
-(2505,'I',0.31,0.24,0.105,0.2885,0.118,0.065,0.083,6),
-(2039,'I',0.28,0.215,0.08,0.132,0.072,0.022,0.033,5),
-(829,'I',0.41,0.325,0.1,0.394,0.208,0.0655,0.106,6),
-(3197,'I',0.325,0.245,0.075,0.1495,0.0605,0.033,0.045,5),
-(1447,'I',0.44,0.34,0.105,0.369,0.164,0.08,0.1015,5),
-(2821,'I',0.375,0.285,0.09,0.2545,0.119,0.0595,0.0675,6),
-(1828,'I',0.34,0.26,0.085,0.1885,0.0815,0.0335,0.06,6),
-(2002,'I',0.36,0.27,0.085,0.2185,0.1065,0.038,0.062,6),
-(785,'I',0.215,0.155,0.06,0.0525,0.021,0.0165,0.015,5),
-(2199,'I',0.27,0.19,0.08,0.081,0.0265,0.0195,0.03,6),
-(3527,'I',0.335,0.26,0.085,0.192,0.097,0.03,0.054,6),
-(466,'I',0.175,0.125,0.05,0.0235,0.008,0.0035,0.008,5),
-(425,'I',0.26,0.2,0.07,0.092,0.037,0.02,0.03,6),
-(1825,'I',0.185,0.135,0.04,0.027,0.0105,0.0055,0.009,5),
-(3815,'I',0.38,0.275,0.095,0.2425,0.106,0.0485,0.21,6),
-(2503,'I',0.285,0.21,0.07,0.109,0.044,0.0265,0.033,5),
-(3998,'I',0.36,0.27,0.09,0.2075,0.098,0.039,0.062,6),
-(333,'I',0.3,0.22,0.08,0.121,0.0475,0.042,0.035,5),
-(1837,'I',0.415,0.31,0.09,0.2815,0.1245,0.0615,0.085,6),
-(2813,'I',0.24,0.17,0.05,0.0545,0.0205,0.016,0.0155,5),
-(930,'I',0.44,0.345,0.13,0.4495,0.209,0.0835,0.134,6),
-(1436,'I',0.385,0.3,0.09,0.247,0.1225,0.044,0.0675,5),
-(3972,'I',0.4,0.295,0.095,0.252,0.1105,0.0575,0.066,6),
-(1433,'I',0.365,0.255,0.08,0.1985,0.0785,0.0345,0.053,5),
-(1252,'I',0.405,0.285,0.09,0.2645,0.1265,0.0505,0.075,6),
-(3439,'I',0.43,0.335,0.105,0.378,0.188,0.0785,0.09,6),
-(1250,'I',0.395,0.27,0.1,0.2985,0.1445,0.061,0.082,5),
-(2865,'I',0.31,0.23,0.07,0.1245,0.0505,0.0265,0.038,6),
-(3411,'I',0.415,0.31,0.105,0.3595,0.167,0.083,0.0915,6),
-(1539,'I',0.355,0.27,0.075,0.1775,0.079,0.0315,0.054,6),
-(1990,'I',0.28,0.21,0.075,0.1195,0.053,0.0265,0.03,6),
-(1771,'I',0.455,0.335,0.105,0.422,0.229,0.0865,0.1,6),
-(2291,'I',0.325,0.27,0.1,0.185,0.08,0.0435,0.065,6),
-(3381,'I',0.19,0.13,0.045,0.0265,0.009,0.005,0.009,5),
-(1545,'I',0.37,0.27,0.095,0.2175,0.097,0.046,0.065,6),
-(652,'I',0.335,0.245,0.09,0.1665,0.0595,0.04,0.06,6),
-(3434,'I',0.365,0.27,0.105,0.2155,0.0915,0.0475,0.063,6),
-(2004,'I',0.375,0.28,0.08,0.226,0.105,0.047,0.065,6),
-(2000,'I',0.35,0.25,0.07,0.1605,0.0715,0.0335,0.046,6),
-(3946,'I',0.235,0.175,0.065,0.0615,0.0205,0.02,0.019,6),
-(177,'I',0.315,0.21,0.06,0.125,0.06,0.0375,0.035,5),
-(920,'I',0.41,0.31,0.09,0.3335,0.1635,0.061,0.091,6),
-(3437,'I',0.38,0.275,0.095,0.2505,0.0945,0.0655,0.075,6),
-(2630,'I',0.33,0.24,0.075,0.163,0.0745,0.033,0.048,6),
-(1092,'I',0.45,0.33,0.11,0.3685,0.16,0.0885,0.102,6),
-(3476,'I',0.4,0.315,0.085,0.2675,0.116,0.0585,0.0765,6),
-(3526,'I',0.33,0.23,0.085,0.1695,0.079,0.026,0.0505,6),
-(1534,'I',0.295,0.215,0.07,0.121,0.047,0.0155,0.0405,6),
-(921,'I',0.415,0.33,0.09,0.3595,0.17,0.081,0.09,6),
-(2206,'I',0.275,0.22,0.08,0.1365,0.0565,0.0285,0.042,6),
-(1218,'I',0.315,0.23,0.08,0.1375,0.0545,0.031,0.0445,5),
-(1998,'I',0.335,0.25,0.08,0.1695,0.0695,0.044,0.0495,6),
-(2455,'I',0.275,0.2,0.065,0.092,0.0385,0.0235,0.027,5),
-(2548,'I',0.23,0.18,0.05,0.064,0.0215,0.0135,0.02,5),
-(3996,'I',0.245,0.175,0.055,0.0785,0.04,0.018,0.02,5),
-(3408,'I',0.35,0.265,0.08,0.192,0.081,0.0465,0.053,6),
-(3907,'M',0.245,0.18,0.065,0.0635,0.0245,0.0135,0.02,4),
-(3850,'M',0.385,0.3,0.115,0.3435,0.1645,0.085,0.1025,6),
-(124,'M',0.37,0.265,0.075,0.214,0.09,0.051,0.07,6),
-(2583,'M',0.53,0.41,0.14,0.681,0.3095,0.1415,0.1835,6),
-(526,'M',0.175,0.125,0.04,0.024,0.0095,0.006,0.005,4),
-(2184,'M',0.495,0.4,0.155,0.8085,0.2345,0.1155,0.35,6),
-(2132,'M',0.32,0.24,0.08,0.18,0.08,0.0385,0.055,6),
-(651,'M',0.255,0.18,0.065,0.079,0.034,0.014,0.025,5),
-(612,'M',0.195,0.145,0.05,0.032,0.01,0.008,0.012,4),
-(958,'M',0.5,0.39,0.135,0.6595,0.3145,0.1535,0.1565,6),
-(3174,'M',0.35,0.265,0.09,0.2265,0.0995,0.0575,0.065,6),
-(265,'M',0.27,0.2,0.08,0.1205,0.0465,0.028,0.04,6),
-(519,'M',0.325,0.23,0.09,0.147,0.06,0.034,0.045,4),
-(2382,'M',0.155,0.115,0.025,0.024,0.009,0.005,0.0075,5),
-(698,'M',0.28,0.205,0.1,0.1165,0.0545,0.0285,0.03,5),
-(2381,'M',0.175,0.135,0.04,0.0305,0.011,0.0075,0.01,5),
-(516,'M',0.27,0.195,0.08,0.1,0.0385,0.0195,0.03,6),
-(831,'M',0.415,0.305,0.1,0.325,0.156,0.0505,0.091,6),
-(3359,'M',0.285,0.215,0.075,0.106,0.0415,0.023,0.035,5);
-
-DROP TABLE IF EXISTS abalone_train_small;
-CREATE TABLE abalone_train_small AS (
- SELECT * FROM abalone_train_small_tmp
-);
-
--- create epsilon input table
-
-DROP TABLE IF EXISTS abalone_eps;
-CREATE TABLE abalone_eps (
- sex TEXT,
- epsilon DOUBLE PRECISION);
-
-INSERT INTO abalone_eps(sex, epsilon) VALUES
-('I', 0.2),
-('M', 0.05);
-
--- solve it with grouping and table of epsilon as inputs
-
-DROP TABLE IF EXISTS svr_mdl, svr_mdl_summary;
-SELECT svm_regression(
- 'abalone_train_small',
- 'svr_mdl',
- 'rings',
- 'ARRAY[1,diameter,shell,shucked,length]',
- NULL,NULL,'sex',
- 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 50, eps_table=abalone_eps',
- false);
-SELECT * FROM svr_mdl;
-
-
-DROP TABLE IF EXISTS svr_mdl_i, svr_mdl_i_summary;
-SELECT svm_regression(
- 'abalone_train_small',
- 'svr_mdl_i',
- 'rings',
- 'ARRAY[1,diameter,shell,shucked,length]',
- NULL,NULL,'sex',
- 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.2',
- false);
-SELECT * FROM svr_mdl_i where sex = 'I';
-
-DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary;
-SELECT svm_regression(
- 'abalone_train_small',
- 'svr_mdl_m',
- 'rings',
- 'ARRAY[1,diameter,shell,shucked,length]',
- NULL,NULL,'sex',
- 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.05',
- false);
-SELECT * FROM svr_mdl_m where sex = 'M';
-
-DROP TABLE IF EXISTS svr_mdl_f, svr_mdl_f_summary;
-SELECT svm_regression(
- 'abalone_train_small',
- 'svr_mdl_f',
- 'rings',
- 'ARRAY[1,diameter,shell,shucked,length]',
- NULL,NULL,'sex',
- 'max_iter=50, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 50',
- false);
-SELECT * FROM svr_mdl_f where sex = 'F';
-
--- verify that the results are the same
-
-SELECT assert(
- abs_err < 1e-5,
- 'SVR with epsilon table input: Wrong results!')
-FROM (
- SELECT
- abs(t1.norm_of_gradient - t2.norm_of_gradient) AS abs_err
- FROM svr_mdl_f AS t1 JOIN svr_mdl AS t2 USING (sex)
- where sex = 'F'
-) AS q1;
-
-SELECT assert(
- rel_err < 1e-1,
- 'SVR with epsilon table input: Wrong results!')
-FROM (
- SELECT
- relative_error(t1.norm_of_gradient, t2.norm_of_gradient) AS rel_err
- FROM svr_mdl_i AS t1 JOIN svr_mdl AS t2 USING (sex)
- where sex = 'I'
-) AS q1;
-
-SELECT assert(
- rel_err < 1e-1,
- 'SVR with epsilon table input: Wrong results!')
-FROM (
- SELECT
- relative_error(t1.norm_of_gradient, t2.norm_of_gradient) AS rel_err
- FROM svr_mdl_m AS t1 JOIN svr_mdl AS t2 USING (sex)
- where sex = 'M'
-) AS q1;
-
-DROP TABLE IF EXISTS m1, m1_summary;
-SELECT svm_regression(
- 'svr_train_data',
- 'm1',
- 'label',
- 'ind',
- NULL,NULL,NULL,
- 'init_stepsize=0.01, max_iter=3, lambda=[0.0002, 0.2], '
- 'n_folds=3, epsilon = [0.003, 0.2]',
- true);
-
-DROP TABLE IF EXISTS m1, m1_summary;
-SELECT svm_regression(
- 'svr_train_data',
- 'm1',
- 'label',
- 'ind',
- NULL,NULL,NULL,
- 'init_stepsize=0.01, max_iter=2, lambda=[0.0002, 0.2], n_folds=3',
- false);
--- check which lambda is selected
-SELECT reg_params FROM m1_summary;
-
--- epsilon values are ignored
--- the validation table only contains
--- init_stepsize and lambda
-DROP TABLE IF EXISTS m1, m1_summary, val_res;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- NULL,NULL,NULL,
- 'init_stepsize=[0.01, 1], max_iter=3, lambda=[20, 0.0002, 0.02], '
- 'n_folds=3, epsilon=[0.1, 1], validation_result=val_res');
-SELECT * FROM val_res;
-
-DROP TABLE IF EXISTS m1, m1_summary, val_res;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- NULL,NULL,NULL,
- 'init_stepsize=0.01, max_iter=20, lambda=[20, 0.0002, 0.02], '
- 'n_folds=3, validation_result=val_res');
-SELECT * FROM val_res;
--- check which lambda is selected
-SELECT reg_params FROM m1_summary;
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
--- accuracy with cv
-SELECT
- count(*) AS misclassification_count
-FROM svm_test_predict NATURAL JOIN svm_test_data
-WHERE prediction <> label;
-
-DROP TABLE IF EXISTS m1, m1_summary;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- NULL,NULL,NULL,
- 'init_stepsize=0.01, max_iter=20, lambda=0.000002');
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
--- accuracy without cv
-SELECT
- count(*) AS misclassification_count
-FROM svm_test_predict NATURAL JOIN svm_test_data
-WHERE prediction <> label;
-
--- verify guassian kernel mapping dimensions
-DROP TABLE IF EXISTS m1, m1_summary, m1_random;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- 'gaussian',
- 'n_components=3',
- NULL,
- 'max_iter=2');
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
-SELECT
- assert(
- array_upper(coef, 1) = 3,
- 'The dimension of the coefficients must be equal to n_components (3)!')
-FROM m1;
-
--- verify gaussian kernel with grouping
--- verify partial string support in kernel specification
-DROP TABLE IF EXISTS svr_mdl_m, svr_mdl_m_summary, svr_mdl_m_random;
-SELECT svm_regression(
- 'abalone_train_small',
- 'svr_mdl_m',
- 'rings',
- 'ARRAY[1,diameter,shell,shucked,length]',
- 'gau',
- 'n_components=10',
- 'sex',
- 'max_iter=2, init_stepsize=1, decay_factor=0.9, tolerance=1e-16, epsilon = 0.05',
- false);
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('svr_mdl_m','abalone_train_small', 'id', 'svm_test_predict');
-SELECT
- assert(
- array_upper(coef, 1) = 10,
- 'The dimension of the coefficients must be equal to n_components (10)!')
-FROM svr_mdl_m;
-
--- verify guassian kernel with cross validation
-DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- 'gaussian',
- 'n_components=3',
- NULL,
- 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
-SELECT
- assert(
- array_upper(coef, 1) = 3,
- 'The dimension of the coefficients must be equal to n_components (3)!')
-FROM m1;
-
--- verify guassian kernel with out-of-memory support
-DROP TABLE IF EXISTS m1, m1_summary, m1_random CASCADE;
-SELECT svm_classification(
- 'svm_train_data',
- 'm1',
- 'label',
- 'ind',
- 'gaussian',
- 'n_components=3, in_memory=0',
- NULL,
- 'max_iter=2, n_folds=3, lambda=[0.01, 0.1, 0.5]');
-DROP TABLE IF EXISTS svm_test_predict CASCADE;
-SELECT svm_predict('m1','svm_test_data', 'id', 'svm_test_predict');
-SELECT
- assert(
- array_upper(coef, 1) = 3,
- 'The dimension of the coefficients must be equal to n_components (3)!')
-FROM m1;
-
-DROP TABLE IF EXISTS kernel_data;
-CREATE TABLE kernel_data (
- index bigint,
- x1 double precision,
- x2 double precision,
- y double precision
-);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (0, 0.400000000000000022, -0.699999999999999956, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (1, -1.5, -1, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (2, -1.39999999999999991, -0.900000000000000022, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (3, -1.30000000000000004, -1.19999999999999996, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (4, -1.10000000000000009, -0.200000000000000011, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (5, -1.19999999999999996, -0.400000000000000022, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (6, -0.5, 1.19999999999999996, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (7, -1.5, 2.10000000000000009, 0);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (8, 1, 1, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (9, 1.30000000000000004, 0.800000000000000044, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (10, 1.19999999999999996, 0.5, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (11, 0.200000000000000011, -2, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (12, 0.5, -2.39999999999999991, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (13, 0.200000000000000011, -2.29999999999999982, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (14, 0, -2.70000000000000018, 1);
-INSERT INTO kernel_data (index, x1, x2, y) VALUES (15, 1.30000000000000004, 2.10000000000000009, 1);
-
-
-DROP TABLE IF EXISTS m1, m1_summary, m1_random;
-SELECT svm_classification(
- 'kernel_data',
- 'm1',
- 'y',
- 'array[x1, x2]',
- 'gaussian',
- 'gamma=1, n_components=20, random_state=2',
- NULL,
- 'init_stepsize=1, max_iter=10');
-SELECT * FROM m1;
-DROP TABLE IF EXISTS kernel_predict CASCADE;
-SELECT svm_predict('m1','kernel_data', 'index', 'kernel_predict');
-SELECT
- count(*) as misclassification
-FROM kernel_predict NATURAL JOIN kernel_data
-WHERE prediction <> y;
-SELECT
- assert(count(*) = 0, 'Using kernel should perfectly fit the data!')
-FROM kernel_predict NATURAL JOIN kernel_data
-WHERE prediction <> y;
-