]> granicus.if.org Git - liblinear/commitdiff
add two functions get_decfun_coef and get_decfun_bias
authorHsiang-Fu Yu <rofuyu@cs.utexas.edu>
Mon, 28 Jul 2014 18:22:42 +0000 (13:22 -0500)
committerYu-Chin <guestwalk@gmail.com>
Sun, 19 Oct 2014 19:35:31 +0000 (03:35 +0800)
README
linear.cpp
linear.h
matlab/predict.c
predict.c
python/README
python/liblinear.py
python/liblinearutil.py

diff --git a/README b/README
index b5e1506f295901d429bc41279453851c927d9d55..256028798ac90c0baa5ac2ac97586012a3f69330 100644 (file)
--- a/README
+++ b/README
@@ -448,6 +448,21 @@ Library Usage
     This function outputs the name of labels into an array called label.
     For a regression model, label is unchanged.
 
+- Function: double get_decfun_coef(const struct model *model_, int feat_idx,
+            int label_idx);
+
+    This function gives the coefficient for the feature with feature index =
+    feat_idx and the class with label index = label_idx. Note that feat_idx
+    starts from 1, while label_idx starts from 0. If label_idx is not in the
+    valid range (0 to nr_class-1), then a NaN will be returned; and if feat_idx
+    is not in the valid range (1 to nr_feature), then a zero value will be
+    returned. For regression models, label_idx is ignored.
+
+- Function: double get_decfun_bias(const struct model *model_, int label_idx);
+
+    This function gives the bias term corresponding to the class with the 
+    label_idx. For regression models, label_idx is ignored.
+
 - Function: const char *check_parameter(const struct problem *prob,
             const struct parameter *param);
 
@@ -456,6 +471,16 @@ Library Usage
     train() and cross_validation(). It returns NULL if the
     parameters are feasible, otherwise an error message is returned.
 
+- Function: int check_probability_model(const struct model *model);
+
+    This function returns 1 if the model supports probability output;
+    otherwise, it returns 0.
+
+- Function: int check_regression_model(const struct model *model);
+
+    This function returns 1 if the model is a regression model; otherwise
+    it returns 0.
+
 - Function: int save_model(const char *model_file_name,
             const struct model *model_);
 
index 76623c10de41853951486265572de1e13e899afe..6efbf100d39ba94fd46683b12faad78d43e461c0 100644 (file)
@@ -2305,9 +2305,7 @@ model* train(const problem *prob, const parameter *param)
        model_->param = *param;
        model_->bias = prob->bias;
 
-       if(param->solver_type == L2R_L2LOSS_SVR ||
-          param->solver_type == L2R_L1LOSS_SVR_DUAL ||
-          param->solver_type == L2R_L2LOSS_SVR_DUAL)
+       if(check_regression_model(model_))
        {
                model_->w = Malloc(double, w_size);
                model_->nr_class = 2;
@@ -2512,9 +2510,7 @@ double predict_values(const struct model *model_, const struct feature_node *x,
 
        if(nr_class==2)
        {
-               if(model_->param.solver_type == L2R_L2LOSS_SVR ||
-                  model_->param.solver_type == L2R_L1LOSS_SVR_DUAL ||
-                  model_->param.solver_type == L2R_L2LOSS_SVR_DUAL)
+               if(check_regression_model(model_))
                        return dec_values[0];
                else
                        return (dec_values[0]>0)?model_->label[0]:model_->label[1];
@@ -2764,6 +2760,56 @@ void get_labels(const model *model_, int* label)
                        label[i] = model_->label[i];
 }
 
+// use inline here for better performance (around 20% faster than the non-inline one)
+static inline double get_w_value(const struct model *model_, int idx, int label_idx) 
+{
+       int nr_class = model_->nr_class;
+       int solver_type = model_->param.solver_type;
+       const double *w = model_->w;
+
+       if(!check_regression_model(model_) && (label_idx < 0 || label_idx >= nr_class)) 
+       {
+               const double nan = 0.0/0.0;
+               return nan;
+       }
+       if(idx < 0 || idx > model_->nr_feature)
+               return 0;
+       if(check_regression_model(model_))
+               return w[idx];
+       else 
+       {
+               if(nr_class == 2 && solver_type != MCSVM_CS)
+               {
+                       if(label_idx == 0)
+                               return w[idx];
+                       else
+                               return -w[idx];
+               }
+               else
+                       return w[idx*nr_class+label_idx];
+       }
+}
+
+// feat_idx: starting from 1 to nr_feature
+// label_idx: starting from 0 to nr_class-1 for classification models;
+//            for regression models, label_idx is ignored.
+double get_decfun_coef(const struct model *model_, int feat_idx, int label_idx)
+{
+       if(feat_idx > model_->nr_feature)
+               return 0;
+       return get_w_value(model_, feat_idx-1, label_idx);
+}
+
+double get_decfun_bias(const struct model *model_, int label_idx)
+{
+       int bias_idx = model_->nr_feature;
+       double bias = model_->bias;
+       if(bias <= 0)
+               return 0;
+       else
+               return bias*get_w_value(model_, bias_idx, label_idx);
+}
+
 void free_model_content(struct model *model_ptr)
 {
        if(model_ptr->w != NULL)
@@ -2824,6 +2870,13 @@ int check_probability_model(const struct model *model_)
                        model_->param.solver_type==L1R_LR);
 }
 
+int check_regression_model(const struct model *model_)
+{
+       return (model_->param.solver_type==L2R_L2LOSS_SVR ||
+                       model_->param.solver_type==L2R_L1LOSS_SVR_DUAL ||
+                       model_->param.solver_type==L2R_L2LOSS_SVR_DUAL);
+}
+
 void set_print_string_function(void (*print_func)(const char*))
 {
        if (print_func == NULL)
index 22a356743a790616aac00794598a451b8080b78f..6b07b477dd1de388f9b70e355b8ae395ac700448 100644 (file)
--- a/linear.h
+++ b/linear.h
@@ -57,6 +57,8 @@ struct model *load_model(const char *model_file_name);
 int get_nr_feature(const struct model *model_);
 int get_nr_class(const struct model *model_);
 void get_labels(const struct model *model_, int* label);
+double get_decfun_coef(const struct model *model_, int feat_idx, int label_idx);
+double get_decfun_bias(const struct model *model_, int label_idx);
 
 void free_model_content(struct model *model_ptr);
 void free_and_destroy_model(struct model **model_ptr_ptr);
@@ -64,6 +66,7 @@ void destroy_param(struct parameter *param);
 
 const char *check_parameter(const struct problem *prob, const struct parameter *param);
 int check_probability_model(const struct model *model);
+int check_regression_model(const struct model *model);
 void set_print_string_function(void (*print_func) (const char*));
 
 #ifdef __cplusplus
index 36c6046206a48858393f9af37e5dff645be54496..3548bdc6ff8dbaa47866ebfb8ab1c6ca9bc95452 100644 (file)
@@ -176,9 +176,7 @@ void do_predict(int nlhs, mxArray *plhs[], const mxArray *prhs[], struct model *
                ++total;
        }
 
-       if(model_->param.solver_type==L2R_L2LOSS_SVR ||
-          model_->param.solver_type==L2R_L1LOSS_SVR_DUAL ||
-          model_->param.solver_type==L2R_L2LOSS_SVR_DUAL)
+       if(check_regression_model(model_))
        {
                info("Mean squared error = %g (regression)\n",error/total);
                info("Squared correlation coefficient = %g (regression)\n",
index c5b3f1d56ee0883a387ab721d0d98aa0e254473f..a0431811c004900883d7f273f3d21d41cf6be0c5 100644 (file)
--- a/predict.c
+++ b/predict.c
@@ -158,9 +158,7 @@ void do_predict(FILE *input, FILE *output)
                sumpt += predict_label*target_label;
                ++total;
        }
-       if(model_->param.solver_type==L2R_L2LOSS_SVR ||
-          model_->param.solver_type==L2R_L1LOSS_SVR_DUAL ||
-          model_->param.solver_type==L2R_L2LOSS_SVR_DUAL)
+       if(check_regression_model(model_))
        {
                info("Mean squared error = %g (regression)\n",error/total);
                info("Squared correlation coefficient = %g (regression)\n",
index e12b298f86f676eb9687b4e26d9590a576684e93..e6349cf9fa948560d338c1f135d5b39b51e41356 100644 (file)
@@ -205,6 +205,36 @@ LIBLINEAR shared library:
     >>> nr_class = model_.get_nr_class()
     >>> class_labels = model_.get_labels()
     >>> is_prob_model = model_.is_probability_model()
+    >>> is_regression_model = model_.is_regression_model()
+
+    The decision function is W*x + b, where
+        W is an nr_class-by-nr_feature matrix, and
+        b is a vector of size nr_class.
+    To access W_kj (i.e., coefficient for the k-th class and the j-th feature)
+    and b_k (i.e., bias for the k-th class), use the following functions.
+
+    >>> W_kj = model_.get_decfun_coef(feat_idx=j, label_idx=k)
+    >>> b_k = model_.get_decfun_bias(label_idx=k)
+
+    We also provide a function to extract w_k (i.e., the k-th row of W) and
+    b_k directly as follows.
+
+    >>> [w_k, b_k] = model_.get_decfun(label_idx=k)
+
+    Note that w_k is a Python list of length nr_feature, which means that
+        w_k[0] = W_k1.
+    For regression models, W is just a vector of length nr_feature. Either
+       set label_idx=0 or omit the label_idx parameter to access the coefficients.
+
+    >>> W_j = model_.get_decfun_coef(feat_idx=j)
+    >>> b = model_.get_decfun_bias()
+    >>> [W, b] = model_.get_decfun()
+
+    Note that in get_decfun_coef, get_decfun_bias, and get_decfun, feat_idx
+    starts from 1, while label_idx starts from 0. If label_idx is not in the
+    valid range (0 to nr_class-1), then a NaN will be returned; and if feat_idx
+    is not in the valid range (1 to nr_feature), then a zero value will be
+    returned. For regression models, label_idx is ignored.
 
 Utility Functions
 =================
index ac06a33d420fb8d5ef7cfd1ea87098f64b3e2bc8..9587718d844ffb9bff97f5a19e24fc5027f19456 100644 (file)
@@ -250,9 +250,23 @@ class model(Structure):
                liblinear.get_labels(self, labels)
                return labels[:nr_class]
 
+       def get_decfun_coef(self, feat_idx, label_idx=0):
+               return liblinear.get_decfun_coef(self, feat_idx, label_idx)
+
+       def get_decfun_bias(self, label_idx=0):
+               return liblinear.get_decfun_bias(self, label_idx)
+
+       def get_decfun(self, label_idx=0):
+               w = [liblinear.get_decfun_coef(self, feat_idx, label_idx) for feat_idx in range(1, self.nr_feature+1)]
+               b = liblinear.get_decfun_bias(self, label_idx)
+               return (w, b)
+
        def is_probability_model(self):
                return (liblinear.check_probability_model(self) == 1)
 
+       def is_regression_model(self):
+               return (liblinear.check_regression_model(self) == 1)
+
 def toPyModel(model_ptr):
        """
        toPyModel(model_ptr) -> model
@@ -278,10 +292,13 @@ fillprototype(liblinear.load_model, POINTER(model), [c_char_p])
 fillprototype(liblinear.get_nr_feature, c_int, [POINTER(model)])
 fillprototype(liblinear.get_nr_class, c_int, [POINTER(model)])
 fillprototype(liblinear.get_labels, None, [POINTER(model), POINTER(c_int)])
+fillprototype(liblinear.get_decfun_coef, c_double, [POINTER(model), c_int, c_int])
+fillprototype(liblinear.get_decfun_bias, c_double, [POINTER(model), c_int])
 
 fillprototype(liblinear.free_model_content, None, [POINTER(model)])
 fillprototype(liblinear.free_and_destroy_model, None, [POINTER(POINTER(model))])
 fillprototype(liblinear.destroy_param, None, [POINTER(parameter)])
 fillprototype(liblinear.check_parameter, c_char_p, [POINTER(problem), POINTER(parameter)])
 fillprototype(liblinear.check_probability_model, c_int, [POINTER(model)])
+fillprototype(liblinear.check_regression_model, c_int, [POINTER(model)])
 fillprototype(liblinear.set_print_string_function, None, [CFUNCTYPE(None, c_char_p)])
index 626489bd2caf64790f08f8f28a6dd782029553cf..40de52a2d4011efe644598f91f08747642eea9bb 100644 (file)
@@ -3,10 +3,11 @@
 import os, sys
 sys.path = [os.path.dirname(os.path.abspath(__file__))] + sys.path 
 from liblinear import *
+from liblinear import __all__ as liblinear_all
 from ctypes import c_double
 
 __all__ = ['svm_read_problem', 'load_model', 'save_model', 'evaluations',
-           'train', 'predict']
+           'train', 'predict'] + liblinear_all
 
 
 def svm_read_problem(data_file_name):
@@ -246,7 +247,7 @@ def predict(y, x, m, options=""):
                y = [0] * len(x)
        ACC, MSE, SCC = evaluations(y, pred_labels)
        l = len(y)
-       if solver_type in [L2R_L2LOSS_SVR, L2R_L2LOSS_SVR_DUAL, L2R_L1LOSS_SVR_DUAL]:
+       if m.is_regression_model():
                info("Mean squared error = %g (regression)" % MSE)
                info("Squared correlation coefficient = %g (regression)" % SCC)
        else: