Browse Source

Implemented regression via Catmull-Rom-Splines for one-dimensional data.

Frank Prüfer 11 years ago
parent
commit
d63b2ee330

+ 2 - 2
regression/progs/testNPRegression.cpp

@@ -1,6 +1,6 @@
 /**
-* @file testLinRegression.cpp
-* @brief test of linear regression
+* @file testNPRegression.cpp
+* @brief test of non-parametric regression
 * @author Frank Prüfer
 * @date 08/29/2013
 

BIN
regression/splineregression/.swp.CRSplineReg.cpp


+ 179 - 0
regression/splineregression/CRSplineReg.cpp

@@ -0,0 +1,179 @@
+/**
+* @file CRSplineReg.cpp
+* @brief Implementation of Catmull-Rom-Splines for regression purposes
+* @author Frank Prüfer
+* @date 09/03/2013
+
+*/  
+
+#include <iostream>
+
+#include "vislearning/regression/splineregression/CRSplineReg.h"
+
+#include "vislearning/math/mathbase/FullVector.h"
+
+using namespace OBJREC;
+
+using namespace std;
+using namespace NICE;
+
+CRSplineReg::CRSplineReg ( )
+{
+  tau = 0.5;
+}
+
+CRSplineReg::CRSplineReg ( const CRSplineReg & src ) : RegressionAlgorithm ( src )
+{
+  tau = src.tau;
+  dataSet = src.dataSet;
+  labelSet = src.labelSet;
+}
+
+CRSplineReg::~CRSplineReg()
+{
+}
+
+void CRSplineReg::teach ( const NICE::VVector & _dataSet, const NICE::Vector & _labelSet)
+{
+    fprintf (stderr, "teach using all !\n");
+    //NOTE this is crucial if we clear _teachSet afterwards!
+    //therefore, take care NOT to call _techSet.clear() somewhere out of this method
+    this->dataSet = _dataSet;
+    this->labelSet = _labelSet.std_vector();
+    
+    std::cerr << "number of known training samples: " << this->dataSet.size() << std::endl;   
+    
+}
+
+void CRSplineReg::teach ( const NICE::Vector & x, const double & y )
+{
+    std::cerr << "CRSplineReg::teach one new example" << std::endl;
+    
+    for ( size_t i = 0 ; i < x.size() ; i++ )
+      if ( isnan(x[i]) ) 
+      {
+          fprintf (stderr, "There is a NAN value in within this vector: x[%d] = %f\n", (int)i, x[i]);
+          cerr << x << endl;
+          exit(-1);
+      }
+
+    dataSet.push_back ( x );
+    
+    labelSet.push_back ( y );
+    
+    std::cerr << "number of known training samples: " << dataSet.size()<< std::endl;
+}
+
+double CRSplineReg::predict ( const NICE::Vector & x )
+{
+  
+  if ( dataSet.size() <= 0 ) {
+    fprintf (stderr, "CRSplineReg: please use the train method first\n");
+    exit(-1);
+  }
+  
+  if ( dataSet[0].size() == 1 ){	//one-dimensional case
+    FullVector data ( dataSet.size()+1 );
+    for ( uint i = 0; i < dataSet.size(); i++ ){
+      data[i] = dataSet[i][0];
+    }
+    cerr<<"data x: "<<x[0]<<endl;
+    data[dataSet.size()] = x[0];
+    
+    std::vector<int> ind;
+    data.getSortedIndices(ind);
+    
+    int index;
+    for ( uint i = 0; i < ind.size(); i++ ){
+      if ( ind[i] == dataSet.size() ){
+	index = i;
+	break;
+      }
+    }
+    
+    
+    NICE::Matrix points (4,2,0.0);
+    if ( index >= 2 && index < (ind.size() - 2) ){	//everything is okay
+      points(0,0) = data[ind[index-2]];
+      points(0,1) = labelSet[ind[index-2]];
+      points(1,0) = data[ind[index-1]];
+      points(1,1) = labelSet[ind[index-1]];
+      points(2,0) = data[ind[index+1]];
+      points(2,1) = labelSet[ind[index+1]];
+      points(3,0) = data[ind[index+2]];
+      points(3,1) = labelSet[ind[index+2]];      
+    }
+    else if ( index == 1 ){	//just one point left from x
+      points(0,0) = data[ind[index-1]];
+      points(0,1) = labelSet[ind[index-1]];
+      points(1,0) = data[ind[index-1]];
+      points(1,1) = labelSet[ind[index-1]];
+      points(2,0) = data[ind[index+1]];
+      points(2,1) = labelSet[ind[index+1]];
+      points(3,0) = data[ind[index+2]];
+      points(3,1) = labelSet[ind[index+2]];       
+    }
+    else if ( index == 0 ){	//x is the farthest left point
+      //do linear approximation
+    }
+    else if ( index == (ind.size() - 2) ){	//just one point right from x
+      points(0,0) = data[ind[index-2]];
+      points(0,1) = labelSet[ind[index-2]];
+      points(1,0) = data[ind[index-1]];
+      points(1,1) = labelSet[ind[index-1]];
+      points(2,0) = data[ind[index+1]];
+      points(2,1) = labelSet[ind[index+1]];
+      points(3,0) = data[ind[index+1]];
+      points(3,1) = labelSet[ind[index+1]];  
+    }
+    else if ( index == (ind.size() - 1) ){	//x is the farthest right point
+      //do linear approximation
+    }
+    
+    double t = (x[0] - points(1,0)) / (points(2,0) - points(1,0));
+    cerr<<"t: "<<t<<endl;
+    
+//     NICE::Vector vecT(4,1.0);
+//     
+//     vecT[1] = t;
+//     vecT[2] = t*t;
+//     vecT[3] = t*t*t;
+//     
+//     Matrix coeffMatrix (4,4,0.0);	// M = (0 2 0 0
+//     coeffMatrix(0,1) = 2.0;		//	-1 0 1 0
+//     coeffMatrix(1,0) = -1.0;		//	2 -5 4 -1
+//     coeffMatrix(1,2) = 1.0;		//	-1 3 -3 1)
+//     coeffMatrix(2,0) = 2.0;
+//     coeffMatrix(2,1) = -5.0;
+//     coeffMatrix(2,2) = 4.0;
+//     coeffMatrix(2,3) = -1.0;
+//     coeffMatrix(3,0) = -1.0;
+//     coeffMatrix(3,1) = 3.0;
+//     coeffMatrix(3,2) = -3.0;
+//     coeffMatrix(3,3) = 1.0;
+//     
+//     // P(t) = tau * vecT * coeffMatrix * points;
+//     NICE::Vector P;
+//     NICE::Matrix tmp;
+//     tmp.multiply(coeffMatrix,points);
+//     P.multiply(vecT,tmp);
+//     P *= tau;
+    
+    //P(t) = b0*P0 + b1*P1 + b2*P2 + b3*P3
+    NICE::Vector P(2);
+    double b0,b1,b2,b3;
+    b0 = tau * (-(t*t*t) + 2*t*t - t);
+    b1 = tau * (3*t*t*t - 5*t*t + 2);
+    b2 = tau * (-3*t*t*t + 4*t*t + t);
+    b3 = tau * (t*t*t - t*t);
+    
+    P[0] = b0*points(0,0) + b1*points(1,0) + b2*points(2,0) + b3*points(3,0);
+    P[1] = b0*points(0,1) + b1*points(1,1) + b2*points(2,1) + b3*points(3,1);
+    
+    cerr<<"Response x: "<<P[0]<<endl;
+    cerr<<"Response y: "<<P[1]<<endl;
+    
+    return P[1];  
+  }
+  
+}

+ 59 - 0
regression/splineregression/CRSplineReg.h

@@ -0,0 +1,59 @@
+/**
+* @file CRSplineReg.h
+* @brief Implementation of Catmull-Rom-Splines for regression purposes
+* @author Frank Prüfer
+* @date 09/03/2013
+
+*/  
+#ifndef CRSPLINEREGINCLUDE
+#define CRSPLINEREGINCLUDE
+
+#include "core/vector/VectorT.h"
+#include "core/vector/VVector.h"
+#include "core/vector/MatrixT.h"
+
+#include "core/basics/Config.h"
+
+#include "vislearning/regression/regressionbase/RegressionAlgorithm.h"
+
+namespace OBJREC
+{
+class CRSplineReg : public RegressionAlgorithm
+{
+  protected:
+    /** smoothness parameter */
+    double tau;
+    
+    /** set of data points */
+    NICE::VVector dataSet;
+    
+    /** set of responses according to dataset */
+    std::vector<double> labelSet;
+  
+  public:
+    /** simple constructor */
+    CRSplineReg();
+    
+    /** copy constructor */
+    CRSplineReg ( const CRSplineReg & src );
+    
+    /** simple destructor */
+    virtual ~CRSplineReg();
+    
+    /** predict response using simple vector */
+    double predict ( const NICE::Vector & x );
+    
+    /** teach whole set at once */
+    void teach ( const NICE::VVector & dataSet, const NICE::Vector & labelSet );
+
+    /** teach one data point at a time */
+    void teach ( const NICE::Vector & x, const double & y );
+  
+};
+}	//nameospace
+
+
+
+
+
+#endif

+ 8 - 0
regression/splineregression/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
regression/splineregression/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 1 - 0
regression/splineregression/libdepend.inc

@@ -0,0 +1 @@
+$(call PKG_DEPEND_INT,vislearning/regression/regressionbase)