[gnumeric] Calculate residuals when using the regression tool. [#635064]



commit 2e143616e2c5e5011200d5536ca53026277a4a70
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Thu Nov 25 18:58:19 2010 -0700

    Calculate residuals when using the regression tool. [#635064]
    
    2010-11-25 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* analysis-tools.h (analysis_tools_data_regression_t): add field
    	* analysis-tools.c (calculate_n_obs): new
    	(analysis_tool_regression_engine_run): calculate residuals
    	(analysis_tool_regression_engine): allocate space for residuals
    
    2010-11-25  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* regression.ui: added residuals checkbox
    	* dialog-analysis-tools.c (RegressionToolState): add field
    	(regression_tool_ok_clicked_cb): handle residuals checkbox
    	(regression_tool_regression_radio_toggled_cb): ditto
    	(dialog_regression_tool): ditto

 NEWS                                |    3 +
 src/dialogs/ChangeLog               |    8 +++
 src/dialogs/dialog-analysis-tools.c |   22 +++++++-
 src/dialogs/regression.ui           |   15 +++++-
 src/tools/ChangeLog                 |    8 +++
 src/tools/analysis-tools.c          |   89 +++++++++++++++++++++++++++++++++--
 src/tools/analysis-tools.h          |    4 +-
 7 files changed, 138 insertions(+), 11 deletions(-)
---
diff --git a/NEWS b/NEWS
index f5508b1..db6e857 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 Gnumeric 1.10.13
 
+Andreas:
+	* Calculate residuals when using the regression tool. [#635064]
+
 --------------------------------------------------------------------------
 Gnumeric 1.10.12
 
diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog
index ecd1e1f..80f3ae0 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,11 @@
+2010-11-25  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* regression.ui: added residuals checkbox
+	* dialog-analysis-tools.c (RegressionToolState): add field
+	(regression_tool_ok_clicked_cb): handle residuals checkbox
+	(regression_tool_regression_radio_toggled_cb): ditto
+	(dialog_regression_tool): ditto
+
 2010-11-25  Morten Welinder <terra gnome org>
 
 	* Release 1.10.12
diff --git a/src/dialogs/dialog-analysis-tools.c b/src/dialogs/dialog-analysis-tools.c
index ce760df..6c81b84 100644
--- a/src/dialogs/dialog-analysis-tools.c
+++ b/src/dialogs/dialog-analysis-tools.c
@@ -235,6 +235,7 @@ typedef struct {
 	GtkWidget *confidence_entry;
 	GtkWidget *simple_linear_regression_radio;
 	GtkWidget *switch_variables_check;
+	GtkWidget *residuals_check;
 } RegressionToolState;
 
 typedef struct {
@@ -2180,7 +2181,10 @@ regression_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
 	data->base.alpha = 1 - confidence;
 
 	w = go_gtk_builder_get_widget (state->base.gui, "intercept-button");
-	data->intercept = 1 - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+	data->intercept = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
+
+	data->residual = gtk_toggle_button_get_active
+		(GTK_TOGGLE_BUTTON (state->residuals_check));
 
 	data->multiple_regression
 		= !gtk_toggle_button_get_active
@@ -2332,11 +2336,17 @@ regression_tool_regression_radio_toggled_cb (G_GNUC_UNUSED
 					     GtkToggleButton *togglebutton,
 					     RegressionToolState *state)
 {
-	if (!gtk_toggle_button_get_active
-	    (GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio)))
+	gboolean simple = gtk_toggle_button_get_active
+		(GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio));
+	if (!simple)
 		gtk_toggle_button_set_active
 			(GTK_TOGGLE_BUTTON (state->switch_variables_check),
 			 FALSE);
+	
+	gtk_toggle_button_set_active
+		(GTK_TOGGLE_BUTTON (state->residuals_check), !simple);
+	gtk_widget_set_sensitive (state->residuals_check, !simple);
+	
 }
 
 static void
@@ -2422,12 +2432,18 @@ dialog_regression_tool (WBCGtk *wbcg, Sheet *sheet)
 	state->switch_variables_check
 		= go_gtk_builder_get_widget
 		(state->base.gui, "multiple-independent-check");
+	state->residuals_check
+		= go_gtk_builder_get_widget
+		(state->base.gui, "residuals-button");
 	gtk_toggle_button_set_active
 		(GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio),
 		 FALSE);
 	gtk_toggle_button_set_active
 		(GTK_TOGGLE_BUTTON (state->switch_variables_check),
 		 FALSE);
+	gtk_toggle_button_set_active
+		(GTK_TOGGLE_BUTTON (state->residuals_check),
+		 TRUE);
 	g_signal_connect
 		(G_OBJECT (state->simple_linear_regression_radio),
 		 "toggled",
diff --git a/src/dialogs/regression.ui b/src/dialogs/regression.ui
index 66c3b18..73b8ac5 100644
--- a/src/dialogs/regression.ui
+++ b/src/dialogs/regression.ui
@@ -9,7 +9,6 @@
     <child internal-child="vbox">
       <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
         <property name="spacing">8</property>
         <child>
           <object class="GtkNotebook" id="notebook1">
@@ -163,7 +162,6 @@
               <object class="GtkVBox" id="vbox2">
                 <property name="visible">True</property>
                 <property name="border_width">12</property>
-                <property name="orientation">vertical</property>
                 <child>
                   <object class="GtkHBox" id="hbox1">
                     <property name="visible">True</property>
@@ -214,7 +212,18 @@
                   </packing>
                 </child>
                 <child>
-                  <placeholder/>
+                  <object class="GtkCheckButton" id="residuals-button">
+                    <property name="label" translatable="yes">Calculate residuals</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">False</property>
+                    <property name="border_width">3</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
                 </child>
                 <child>
                   <placeholder/>
diff --git a/src/tools/ChangeLog b/src/tools/ChangeLog
index 2733981..ddaf13c 100644
--- a/src/tools/ChangeLog
+++ b/src/tools/ChangeLog
@@ -1,3 +1,11 @@
+<<<<<<< HEAD
+2010-11-25 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* analysis-tools.h (analysis_tools_data_regression_t): add field
+	* analysis-tools.c (calculate_n_obs): new
+	(analysis_tool_regression_engine_run): calculate residuals
+	(analysis_tool_regression_engine): allocate space for residuals
+	
 2010-11-25  Morten Welinder <terra gnome org>
 
 	* Release 1.10.12
diff --git a/src/tools/analysis-tools.c b/src/tools/analysis-tools.c
index 5723e7f..1d3831d 100644
--- a/src/tools/analysis-tools.c
+++ b/src/tools/analysis-tools.c
@@ -2820,6 +2820,22 @@ calculate_xdim (GnmValue *input, group_by_t  group_by)
 		return range_width (&r);
 }
 
+static gint
+calculate_n_obs (GnmValue *input, group_by_t  group_by)
+{
+		GnmRange r;
+
+		g_return_val_if_fail (input != NULL, 0);
+
+		if (NULL == range_init_value (&r, input))
+			return 0;
+
+		if (group_by == GROUPED_BY_ROW)
+			return range_width (&r);
+
+		return range_height (&r);
+}
+
 
 static gboolean
 analysis_tool_regression_engine_run (data_analysis_output_t *dao,
@@ -2859,6 +2875,7 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 	GnmFunc *fd_concatenate = NULL;
 	GnmFunc *fd_cell = NULL;
 	GnmFunc *fd_offset = NULL;
+	GnmFunc *fd_sumproduct = NULL;
 
 	char const *str = ((info->group_by == GROUPED_BY_ROW) ? "row" : "col");
 	char const *label = ((info->group_by == GROUPED_BY_ROW) ? _("Row")
@@ -2870,6 +2887,8 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 		fd_cell        = analysis_tool_get_function ("CELL", dao);
 		fd_offset      = analysis_tool_get_function ("OFFSET", dao);
 	}
+	if (info->residual)
+		fd_sumproduct  = analysis_tool_get_function ("SUMPRODUCT", dao);
 
 	cb_adjust_areas (val_1, NULL);
 	cb_adjust_areas (val_2, NULL);
@@ -3253,11 +3272,59 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 	gnm_expr_free (expr_lower);
 	gnm_expr_free (expr_upper);
 
-	value_release (val_1);
-	value_release (val_2);
 	value_release (val_1_cp);
 	value_release (val_2_cp);
 
+	if (info->residual) {
+		gint n_obs = calculate_n_obs (val_1, info->group_by);
+		GnmExpr const *expr_diff;
+		GnmExpr const *expr_prediction;
+
+		dao->offset_row += xdim + 1;
+		dao_set_italic (dao, 0, 0, xdim + 3, 0);
+		dao_set_array_expr (dao, 0, 0, xdim, 1, 
+				    gnm_expr_new_funcall1 
+				    (fd_transpose, 
+				     make_rangeref (0, - xdim - 1, 0, -2)));
+		set_cell_text_row (dao, xdim, 0, _("/Prediction"
+						   "/"
+						   "/Residual"));
+		dao_set_cell_expr (dao, xdim + 1, 0, make_cellref (2 - xdim, - 18 - xdim));
+		if (info->group_by == GROUPED_BY_ROW) {
+			dao_set_array_expr (dao, 0, 1, xdim, n_obs,
+					    gnm_expr_new_funcall1
+					    (fd_transpose,
+					     gnm_expr_new_constant (val_1)));
+			dao_set_array_expr (dao, xdim + 1, 1, 1, n_obs,
+					    gnm_expr_new_funcall1
+					    (fd_transpose,
+					     gnm_expr_new_constant (val_2)));
+		} else {
+			dao_set_array_expr (dao, 0, 1, xdim, n_obs,
+					    gnm_expr_new_constant (val_1));
+			dao_set_array_expr (dao, xdim + 1, 1, 1, n_obs,
+					    gnm_expr_new_constant (val_2));
+		}
+
+		expr_prediction =  gnm_expr_new_binary 
+			(gnm_expr_new_funcall2 (fd_sumproduct,
+						dao_get_rangeref (dao, 1, - 1 - xdim, 1, - 2),
+						gnm_expr_new_funcall1
+						(fd_transpose, make_rangeref (- xdim, 0, -1, 0))), 
+			 GNM_EXPR_OP_ADD, dao_get_cellref (dao, 1, - 2 - xdim));
+		expr_diff = gnm_expr_new_binary (make_cellref (-1, 0), GNM_EXPR_OP_SUB,make_cellref (-2, 0));
+
+		for (i = 0; i < n_obs; i++) {
+			dao_set_cell_expr (dao, xdim, i + 1, gnm_expr_copy (expr_prediction));
+			dao_set_cell_expr (dao, xdim + 2, i + 1, gnm_expr_copy (expr_diff));
+		}
+		gnm_expr_free (expr_diff);
+		gnm_expr_free (expr_prediction);
+	} else {
+		value_release (val_1);
+		value_release (val_2);
+	}
+
 	gnm_func_unref (fd_linest);
 	gnm_func_unref (fd_index);
 	gnm_func_unref (fd_fdist);
@@ -3273,6 +3340,8 @@ analysis_tool_regression_engine_run (data_analysis_output_t *dao,
 		gnm_func_unref (fd_cell);
 	if (fd_offset != NULL)
 		gnm_func_unref (fd_offset);
+	if (fd_sumproduct != NULL)
+		gnm_func_unref (fd_sumproduct);
 
 	dao_redraw_respan (dao);
 
@@ -3404,16 +3473,28 @@ analysis_tool_regression_engine (data_analysis_output_t *dao, gpointer specs,
 	case TOOL_ENGINE_UPDATE_DAO:
 	{
 		gint xdim = calculate_xdim (info->base.range_1, info->group_by);
+		gint cols, rows;
 
 		if (info->multiple_regression) {
+			cols = 7;
+			rows = 17 + xdim;
 			info->indep_vars = NULL;
-			dao_adjust (dao, 7, 17 + xdim);
+			if (info->residual) {
+				gint residual_cols = xdim + 3;
+				GnmValue *val = info->base.range_1;
+				
+				if (cols < residual_cols)
+					cols = residual_cols;
+				rows += 2 + calculate_n_obs (val, info->group_by); 
+			}
 		} else {
 			info->indep_vars = g_slist_prepend (NULL, info->base.range_1);
 			info->base.range_1 = NULL;
 			prepare_input_range (&info->indep_vars, info->group_by);
-			dao_adjust (dao, 6, 3 + xdim);
+			cols = 6;
+			rows = 3 + xdim;
 		}
+		dao_adjust (dao, cols, rows);
 		return FALSE;
 	}
 	case TOOL_ENGINE_CLEAN_UP:
diff --git a/src/tools/analysis-tools.h b/src/tools/analysis-tools.h
index 2d47b26..d323e2e 100644
--- a/src/tools/analysis-tools.h
+++ b/src/tools/analysis-tools.h
@@ -1,3 +1,4 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 #ifndef GNUMERIC_ANALYSIS_TOOLS_H
 #define GNUMERIC_ANALYSIS_TOOLS_H
 
@@ -167,10 +168,11 @@ gboolean analysis_tool_ftest_engine (data_analysis_output_t *dao, gpointer specs
 
 typedef struct {
 	analysis_tools_data_generic_b_t base;
-	gint       intercept;
 	group_by_t group_by;
+	gboolean   intercept;
 	gboolean   multiple_regression;
         gboolean   multiple_y;
+        gboolean   residual;
 	GSList    *indep_vars;
 } analysis_tools_data_regression_t;
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]