Browse Source

support for non-integer percentiles (trac https://trac.osgeo.org/grass/ticket/873; merge from devbr6)

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@40966 15284696-431f-4ddb-bdfa-cd5b030d7da7
Hamish Bowman 15 years ago
parent
commit
2aab98e7ed

+ 1 - 1
raster/r.univar/globals.h

@@ -31,7 +31,7 @@ typedef struct
     double min;
     double max;
     unsigned int n_perc;
-    int *perc;
+    double *perc;
     double sum_abs;
     int n;
     int size;

+ 4 - 0
raster/r.univar/r.univar.html

@@ -19,6 +19,9 @@ This module can use large amounts of system memory when the <b>-e</b>
 extended statistics flag is used with a very large region setting. If the
 region is too large the module should exit gracefully with a memory allocation
 error. Basic statistics can be calculated using any size input region.
+<p>
+The <em>r.quantile</em> module will be significantly more efficient for
+calculating percentiles with large maps.
 
 
 <h2>TODO</h2>
@@ -36,6 +39,7 @@ error. Basic statistics can be calculated using any size input region.
 <a href="r.average.html">r.average</a><br>
 <a href="r.median.html">r.median</a><br>
 <a href="r.mode.html">r.mode</a><br>
+<a href="r.quantile.html">r.quantile</a><br>
 <a href="r.sum.html">r.sum</a><br>
 <a href="r.series.html">r.series</a><br>
 <a href="r.stats.html">r.stats</a><br>

+ 2 - 2
raster/r.univar/r.univar_main.c

@@ -29,7 +29,7 @@ void set_params(void)
 
     param.percentile = G_define_option();
     param.percentile->key = "percentile";
-    param.percentile->type = TYPE_INTEGER;
+    param.percentile->type = TYPE_DOUBLE;
     param.percentile->required = NO;
     param.percentile->multiple = YES;
     param.percentile->options = "0-100";
@@ -152,7 +152,7 @@ static univar_stat *univar_stat_with_percentiles(int map_type, int size)
 	i++;
     stats = create_univar_stat_struct(map_type, size, i);
     for (i = 0; i < stats->n_perc; i++) {
-	sscanf(param.percentile->answers[i], "%i", &stats->perc[i]);
+	sscanf(param.percentile->answers[i], "%lf", &stats->perc[i]);
     }
 
     /* . */

+ 6 - 1
raster/r.univar/r3.univar.html

@@ -19,7 +19,11 @@ This module can use large amounts of system memory when the <b>-e</b>
 extended statistics flag is used with a very large region setting. If the
 region is too large the module should exit gracefully with a memory allocation
 error. Basic statistics can be calculated using any size input region.
-
+<!-- no rast3D support?
+<p>
+The <em>r.quantile</em> module will be significantly more efficient for
+calculating percentiles with large maps.
+-->
 
 <h2>TODO</h2>
 
@@ -36,6 +40,7 @@ error. Basic statistics can be calculated using any size input region.
 <a href="r.average.html">r.average</a><br>
 <a href="r.median.html">r.median</a><br>
 <a href="r.mode.html">r.mode</a><br>
+<a href="r.quantile.html">r.quantile</a><br>
 <a href="r.sum.html">r.sum</a><br>
 <a href="r.series.html">r.series</a><br>
 <a href="r.stats.html">r.stats</a><br>

+ 2 - 2
raster/r.univar/r3.univar_main.c

@@ -28,7 +28,7 @@ void set_params(void)
 
     param.percentile = G_define_option();
     param.percentile->key = "percentile";
-    param.percentile->type = TYPE_INTEGER;
+    param.percentile->type = TYPE_DOUBLE;
     param.percentile->required = NO;
     param.percentile->multiple = YES;
     param.percentile->options = "0-100";
@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
 	i++;
     stats = create_univar_stat_struct(map_type, cols * rows * depths, i);
     for (i = 0; i < stats->n_perc; i++) {
-	sscanf(param.percentile->answers[i], "%i", &stats->perc[i]);
+	sscanf(param.percentile->answers[i], "%lf", &stats->perc[i]);
     }
 
     stats->n = 0;

+ 36 - 14
raster/r.univar/stats.c

@@ -28,7 +28,7 @@ univar_stat *create_univar_stat_struct(int map_type, int size, int n_perc)
     stats->max = 0.0 / 0.0;	/*set to nan as default */
     stats->n_perc = n_perc;
     if (n_perc > 0)
-	stats->perc = (int *)G_malloc(n_perc * sizeof(int));
+	stats->perc = (double *)G_malloc(n_perc * sizeof(double));
     else
 	stats->perc = NULL;
     stats->sum_abs = 0.0;
@@ -204,8 +204,10 @@ int print_stats(univar_stat * stats)
 	    fprintf(stdout, "median=%g\n", median);
 	    fprintf(stdout, "third_quartile=%g\n", quartile_75);
 	    for (i = 0; i < stats->n_perc; i++) {
-		fprintf(stdout, "percentile_%d=%g\n", stats->perc[i],
-			quartile_perc[i]);
+		char buf[24];
+		sprintf(buf, "%.15g", stats->perc[i]);
+		G_strchg(buf, '.', '_');
+		fprintf(stdout, "percentile_%s=%g\n", buf, quartile_perc[i]);
 	    }
 	}
 	else {
@@ -219,18 +221,38 @@ int print_stats(univar_stat * stats)
 
 
 	    for (i = 0; i < stats->n_perc; i++) {
-		if (stats->perc[i] % 10 == 1 && stats->perc[i] != 11)
-		    fprintf(stdout, "%dst percentile: %g\n", stats->perc[i],
-			    quartile_perc[i]);
-		else if (stats->perc[i] % 10 == 2 && stats->perc[i] != 12)
-		    fprintf(stdout, "%dnd percentile: %g\n", stats->perc[i],
-			    quartile_perc[i]);
-		else if (stats->perc[i] % 10 == 3 && stats->perc[i] != 13)
-		    fprintf(stdout, "%drd percentile: %g\n", stats->perc[i],
-			    quartile_perc[i]);
-		else
-		    fprintf(stdout, "%dth percentile: %g\n", stats->perc[i],
+		if (stats->perc[i] == (int)stats->perc[i]) {
+		    /* percentile is an exact integer */
+		    if ((int)stats->perc[i] % 10 == 1 && (int)stats->perc[i] != 11)
+			fprintf(stdout, "%dst percentile: %g\n", (int)stats->perc[i],
+				quartile_perc[i]);
+		    else if ((int)stats->perc[i] % 10 == 2 && (int)stats->perc[i] != 12)
+			fprintf(stdout, "%dnd percentile: %g\n", (int)stats->perc[i],
+				quartile_perc[i]);
+		    else if ((int)stats->perc[i] % 10 == 3 && (int)stats->perc[i] != 13)
+			fprintf(stdout, "%drd percentile: %g\n", (int)stats->perc[i],
+				quartile_perc[i]);
+		    else
+			fprintf(stdout, "%dth percentile: %g\n", (int)stats->perc[i],
+				quartile_perc[i]);
+		}
+		else {
+		    /* percentile is not an exact integer */
+/*
+		    char buf[24], suffix[3];
+		    sprintf(buf, "%.15g", stats->perc[i]);
+		    if (buf[strlen(buf)-1] == '1')
+			strcpy(suffix, "st");
+		    else if (buf[strlen(buf)-1] == '2')
+			strcpy(suffix, "nd");
+		    else if (buf[strlen(buf)-1] == '3')
+			strcpy(suffix, "rd");
+		    else
+			strcpy(suffix, "th");
+*/
+		    fprintf(stdout, "%.15g percentile: %g\n", stats->perc[i],
 			    quartile_perc[i]);
+		}
 	    }
 	}
 	G_free((void *)quartile_perc);