stats.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. * Calculates univariate statistics from the non-null cells
  3. *
  4. * Copyright (C) 2004-2007 by the GRASS Development Team
  5. * Author(s): Hamish Bowman, University of Otago, New Zealand
  6. * Martin Landa and Soeren Gebbert
  7. *
  8. * This program is free software under the GNU General Public
  9. * License (>=v2). Read the file COPYING that comes with GRASS
  10. * for details.
  11. *
  12. */
  13. #include "globals.h"
  14. /* *************************************************************** */
  15. /* **** univar_stat constructor ********************************** */
  16. /* *************************************************************** */
  17. univar_stat *create_univar_stat_struct(int map_type, int n_perc)
  18. {
  19. univar_stat *stats;
  20. int i;
  21. int n_zones = zone_info.n_zones;
  22. if (n_zones == 0)
  23. n_zones = 1;
  24. stats = (univar_stat *) G_calloc(n_zones, sizeof(univar_stat));
  25. for (i = 0; i < n_zones; i++) {
  26. stats[i].sum = 0.0;
  27. stats[i].sumsq = 0.0;
  28. stats[i].min = 0.0 / 0.0; /* set to nan as default */
  29. stats[i].max = 0.0 / 0.0; /* set to nan as default */
  30. stats[i].n_perc = n_perc;
  31. if (n_perc > 0)
  32. stats[i].perc = (double *)G_malloc(n_perc * sizeof(double));
  33. else
  34. stats[i].perc = NULL;
  35. stats[i].sum_abs = 0.0;
  36. stats[i].n = 0;
  37. stats[i].size = 0;
  38. stats[i].dcell_array = NULL;
  39. stats[i].fcell_array = NULL;
  40. stats[i].cell_array = NULL;
  41. stats[i].map_type = map_type;
  42. stats[i].n_alloc = 0;
  43. stats[i].first = TRUE;
  44. /* allocate memory for extended computation */
  45. /* changed to on-demand block allocation */
  46. /* if (param.extended->answer) {
  47. if (map_type == DCELL_TYPE) {
  48. stats[i].dcell_array = NULL;
  49. }
  50. else if (map_type == FCELL_TYPE) {
  51. stats[i].fcell_array =NULL;
  52. }
  53. else if (map_type == CELL_TYPE) {
  54. stats[i].cell_array = NULL;
  55. }
  56. }
  57. */
  58. }
  59. return stats;
  60. }
  61. /* *************************************************************** */
  62. /* **** univar_stat destructor *********************************** */
  63. /* *************************************************************** */
  64. void free_univar_stat_struct(univar_stat * stats)
  65. {
  66. int i;
  67. int n_zones = zone_info.n_zones;
  68. if (n_zones == 0)
  69. n_zones = 1;
  70. for (i = 0; i < n_zones; i++){
  71. if (stats[i].perc)
  72. G_free(stats[i].perc);
  73. if (stats[i].dcell_array)
  74. G_free(stats[i].dcell_array);
  75. if (stats[i].fcell_array)
  76. G_free(stats[i].fcell_array);
  77. if (stats[i].cell_array)
  78. G_free(stats[i].cell_array);
  79. }
  80. G_free(stats);
  81. return;
  82. }
  83. /* *************************************************************** */
  84. /* **** compute and print univar statistics to stdout ************ */
  85. /* *************************************************************** */
  86. int print_stats(univar_stat * stats)
  87. {
  88. int z, n_zones = zone_info.n_zones;
  89. if (n_zones == 0)
  90. n_zones = 1;
  91. for (z = 0; z < n_zones; z++) {
  92. char sum_str[100];
  93. double mean, variance, stdev, var_coef;
  94. /* for extended stats */
  95. double quartile_25 = 0.0, quartile_75 = 0.0, *quartile_perc;
  96. double median = 0.0;
  97. unsigned int i;
  98. int qpos_25, qpos_75, *qpos_perc;
  99. /* all these calculations get promoted to doubles, so any DIV0 becomes nan */
  100. mean = stats[z].sum / stats[z].n;
  101. variance = (stats[z].sumsq - stats[z].sum * stats[z].sum / stats[z].n) / stats[z].n;
  102. if (variance < GRASS_EPSILON)
  103. variance = 0.0;
  104. stdev = sqrt(variance);
  105. var_coef = (stdev / mean) * 100.; /* perhaps stdev/fabs(mean) ? */
  106. if (stats[z].n == 0)
  107. stats[z].sum = stats[z].sum_abs = 0.0 / 0.0;
  108. sprintf(sum_str, "%.15g", stats[z].sum);
  109. G_trim_decimal(sum_str);
  110. if (!param.shell_style->answer) {
  111. if (zone_info.n_zones) {
  112. int z_cat = z + zone_info.min;
  113. fprintf(stdout, "\nzone %d %s\n\n", z_cat, Rast_get_c_cat(&z_cat, &(zone_info.cats)));
  114. }
  115. fprintf(stdout, "total null and non-null cells: %lu\n", stats[z].size);
  116. fprintf(stdout, "total null cells: %lu\n\n", stats[z].size - stats[z].n);
  117. fprintf(stdout, "Of the non-null cells:\n----------------------\n");
  118. }
  119. if (param.shell_style->answer) {
  120. if (zone_info.n_zones) {
  121. int z_cat = z + zone_info.min;
  122. fprintf(stdout, "zone=%d;%s\n", z_cat, Rast_get_c_cat(&z_cat, &(zone_info.cats)));
  123. }
  124. fprintf(stdout, "n=%lu\n", stats[z].n);
  125. fprintf(stdout, "null_cells=%lu\n", stats[z].size - stats[z].n);
  126. fprintf(stdout, "cells=%lu\n", stats->size);
  127. fprintf(stdout, "min=%.15g\n", stats[z].min);
  128. fprintf(stdout, "max=%.15g\n", stats[z].max);
  129. fprintf(stdout, "range=%.15g\n", stats[z].max - stats[z].min);
  130. fprintf(stdout, "mean=%.15g\n", mean);
  131. fprintf(stdout, "mean_of_abs=%.15g\n", stats[z].sum_abs / stats[z].n);
  132. fprintf(stdout, "stddev=%.15g\n", stdev);
  133. fprintf(stdout, "variance=%.15g\n", variance);
  134. fprintf(stdout, "coeff_var=%.15g\n", var_coef);
  135. fprintf(stdout, "sum=%s\n", sum_str);
  136. }
  137. else {
  138. fprintf(stdout, "n: %lu\n", stats[z].n);
  139. fprintf(stdout, "minimum: %g\n", stats[z].min);
  140. fprintf(stdout, "maximum: %g\n", stats[z].max);
  141. fprintf(stdout, "range: %g\n", stats[z].max - stats[z].min);
  142. fprintf(stdout, "mean: %g\n", mean);
  143. fprintf(stdout, "mean of absolute values: %g\n",
  144. stats[z].sum_abs / stats[z].n);
  145. fprintf(stdout, "standard deviation: %g\n", stdev);
  146. fprintf(stdout, "variance: %g\n", variance);
  147. fprintf(stdout, "variation coefficient: %g %%\n", var_coef);
  148. fprintf(stdout, "sum: %s\n", sum_str);
  149. }
  150. /* TODO: mode, skewness, kurtosis */
  151. if (param.extended->answer) {
  152. qpos_perc = (int *)G_calloc(stats[z].n_perc, sizeof(int));
  153. quartile_perc = (double *)G_calloc(stats[z].n_perc, sizeof(double));
  154. if (stats[z].n == 0) {
  155. quartile_25 = median = quartile_75 = 0.0 / 0.0;
  156. for (i = 0; i < stats[z].n_perc; i++)
  157. quartile_perc[i] = 0.0 / 0.0;
  158. }
  159. else {
  160. for (i = 0; i < stats[z].n_perc; i++) {
  161. qpos_perc[i] = (int)(stats[z].n * 1e-2 * stats[z].perc[i] - 0.5);
  162. }
  163. qpos_25 = (int)(stats[z].n * 0.25 - 0.5);
  164. qpos_75 = (int)(stats[z].n * 0.75 - 0.5);
  165. switch (stats[z].map_type) {
  166. case CELL_TYPE:
  167. heapsort_int(stats[z].cell_array, stats[z].n);
  168. quartile_25 = (double)stats[z].cell_array[qpos_25];
  169. if (stats[z].n % 2) /* odd */
  170. median = (double)stats[z].cell_array[(int)(stats[z].n / 2)];
  171. else /* even */
  172. median =
  173. (double)(stats[z].cell_array[stats[z].n / 2 - 1] +
  174. stats[z].cell_array[stats[z].n / 2]) / 2.0;
  175. quartile_75 = (double)stats[z].cell_array[qpos_75];
  176. for (i = 0; i < stats[z].n_perc; i++) {
  177. quartile_perc[i] = (double)stats[z].cell_array[qpos_perc[i]];
  178. }
  179. break;
  180. case FCELL_TYPE:
  181. heapsort_float(stats[z].fcell_array, stats[z].n);
  182. quartile_25 = (double)stats[z].fcell_array[qpos_25];
  183. if (stats[z].n % 2) /* odd */
  184. median = (double)stats[z].fcell_array[(int)(stats[z].n / 2)];
  185. else /* even */
  186. median =
  187. (double)(stats[z].fcell_array[stats[z].n / 2 - 1] +
  188. stats[z].fcell_array[stats[z].n / 2]) / 2.0;
  189. quartile_75 = (double)stats[z].fcell_array[qpos_75];
  190. for (i = 0; i < stats[z].n_perc; i++) {
  191. quartile_perc[i] = (double)stats[z].fcell_array[qpos_perc[i]];
  192. }
  193. break;
  194. case DCELL_TYPE:
  195. heapsort_double(stats[z].dcell_array, stats[z].n);
  196. quartile_25 = stats[z].dcell_array[qpos_25];
  197. if (stats[z].n % 2) /* odd */
  198. median = stats[z].dcell_array[(int)(stats[z].n / 2)];
  199. else /* even */
  200. median =
  201. (stats[z].dcell_array[stats[z].n / 2 - 1] +
  202. stats[z].dcell_array[stats[z].n / 2]) / 2.0;
  203. quartile_75 = stats[z].dcell_array[qpos_75];
  204. for (i = 0; i < stats[z].n_perc; i++) {
  205. quartile_perc[i] = stats[z].dcell_array[qpos_perc[i]];
  206. }
  207. break;
  208. default:
  209. break;
  210. }
  211. }
  212. if (param.shell_style->answer) {
  213. fprintf(stdout, "first_quartile=%g\n", quartile_25);
  214. fprintf(stdout, "median=%g\n", median);
  215. fprintf(stdout, "third_quartile=%g\n", quartile_75);
  216. for (i = 0; i < stats[z].n_perc; i++) {
  217. char buf[24];
  218. sprintf(buf, "%.15g", stats[z].perc[i]);
  219. G_strchg(buf, '.', '_');
  220. fprintf(stdout, "percentile_%s=%g\n", buf,
  221. quartile_perc[i]);
  222. }
  223. }
  224. else {
  225. fprintf(stdout, "1st quartile: %g\n", quartile_25);
  226. if (stats[z].n % 2)
  227. fprintf(stdout, "median (odd number of cells): %g\n", median);
  228. else
  229. fprintf(stdout, "median (even number of cells): %g\n",
  230. median);
  231. fprintf(stdout, "3rd quartile: %g\n", quartile_75);
  232. for (i = 0; i < stats[z].n_perc; i++) {
  233. if (stats[z].perc[i] == (int)stats[z].perc[i]) {
  234. /* percentile is an exact integer */
  235. if ((int)stats[z].perc[i] % 10 == 1 && (int)stats[z].perc[i] != 11)
  236. fprintf(stdout, "%dst percentile: %g\n", (int)stats[z].perc[i],
  237. quartile_perc[i]);
  238. else if ((int)stats[z].perc[i] % 10 == 2 && (int)stats[z].perc[i] != 12)
  239. fprintf(stdout, "%dnd percentile: %g\n", (int)stats[z].perc[i],
  240. quartile_perc[i]);
  241. else if ((int)stats[z].perc[i] % 10 == 3 && (int)stats[z].perc[i] != 13)
  242. fprintf(stdout, "%drd percentile: %g\n", (int)stats[z].perc[i],
  243. quartile_perc[i]);
  244. else
  245. fprintf(stdout, "%dth percentile: %g\n", (int)stats[z].perc[i],
  246. quartile_perc[i]);
  247. }
  248. else {
  249. /* percentile is not an exact integer */
  250. fprintf(stdout, "%.15g percentile: %g\n", stats[z].perc[i],
  251. quartile_perc[i]);
  252. }
  253. }
  254. }
  255. G_free((void *)quartile_perc);
  256. G_free((void *)qpos_perc);
  257. }
  258. /* G_message() prints to stderr not stdout: disabled. this \n is printed above with zone */
  259. /* if (!(param.shell_style->answer))
  260. G_message("\n"); */
  261. }
  262. return 1;
  263. }
  264. int print_stats_table(univar_stat * stats)
  265. {
  266. unsigned int i;
  267. int z, n_zones = zone_info.n_zones;
  268. if (n_zones == 0)
  269. n_zones = 1;
  270. /* print column headers */
  271. if (zone_info.n_zones) {
  272. fprintf(stdout, "zone%s", zone_info.sep);
  273. fprintf(stdout, "label%s", zone_info.sep);
  274. }
  275. fprintf(stdout, "non_null_cells%s", zone_info.sep);
  276. fprintf(stdout, "null_cells%s", zone_info.sep);
  277. fprintf(stdout, "min%s", zone_info.sep);
  278. fprintf(stdout, "max%s", zone_info.sep);
  279. fprintf(stdout, "range%s", zone_info.sep);
  280. fprintf(stdout, "mean%s", zone_info.sep);
  281. fprintf(stdout, "mean_of_abs%s", zone_info.sep);
  282. fprintf(stdout, "stddev%s", zone_info.sep);
  283. fprintf(stdout, "variance%s", zone_info.sep);
  284. fprintf(stdout, "coeff_var%s", zone_info.sep);
  285. fprintf(stdout, "sum%s", zone_info.sep);
  286. fprintf(stdout, "sum_abs");
  287. if (param.extended->answer) {
  288. fprintf(stdout, "%sfirst_quart", zone_info.sep);
  289. fprintf(stdout, "%smedian", zone_info.sep);
  290. fprintf(stdout, "%sthird_quart", zone_info.sep);
  291. for (i = 0; i < stats[0].n_perc; i++) {
  292. if (stats[0].perc[i] == (int)stats[0].perc[i]) {
  293. /* percentile is an exact integer */
  294. fprintf(stdout, "%sperc_%d", zone_info.sep, (int)stats[0].perc[i]);
  295. }
  296. else {
  297. /* percentile is not an exact integer */
  298. char buf[24];
  299. sprintf(buf, "%.15g", stats[0].perc[i]);
  300. G_strchg(buf, '.', '_');
  301. fprintf(stdout, "%sperc_%s", zone_info.sep, buf);
  302. }
  303. }
  304. }
  305. fprintf(stdout, "\n");
  306. /* print stats */
  307. for (z = 0; z < n_zones; z++) {
  308. char sum_str[100];
  309. double mean, variance, stdev, var_coef;
  310. /* for extendet stats */
  311. double quartile_25 = 0.0, quartile_75 = 0.0, *quartile_perc;
  312. double median = 0.0;
  313. int qpos_25, qpos_75, *qpos_perc;
  314. /* stats collected for this zone? */
  315. if (stats[z].size == 0)
  316. continue;
  317. i = 0;
  318. /* all these calculations get promoted to doubles, so any DIV0 becomes nan */
  319. mean = stats[z].sum / stats[z].n;
  320. variance = (stats[z].sumsq - stats[z].sum * stats[z].sum / stats[z].n) / stats[z].n;
  321. if (variance < GRASS_EPSILON)
  322. variance = 0.0;
  323. stdev = sqrt(variance);
  324. var_coef = (stdev / mean) * 100.; /* perhaps stdev/fabs(mean) ? */
  325. if (stats[z].n == 0)
  326. stats[z].sum = stats[z].sum_abs = 0.0 / 0.0;
  327. if (zone_info.n_zones) {
  328. int z_cat = z + zone_info.min;
  329. /* zone number */
  330. fprintf(stdout, "%d%s", z + zone_info.min, zone_info.sep);
  331. /* zone label */
  332. fprintf(stdout,"%s%s", Rast_get_c_cat(&z_cat, &(zone_info.cats)), zone_info.sep);
  333. }
  334. /* non-null cells cells */
  335. fprintf(stdout, "%lu%s", stats[z].n, zone_info.sep);
  336. /* null cells */
  337. fprintf(stdout, "%lu%s", stats[z].size - stats[z].n, zone_info.sep);
  338. /* min */
  339. fprintf(stdout, "%.15g%s", stats[z].min, zone_info.sep);
  340. /* max */
  341. fprintf(stdout, "%.15g%s", stats[z].max, zone_info.sep);
  342. /* range */
  343. fprintf(stdout, "%.15g%s", stats[z].max - stats[z].min, zone_info.sep);
  344. /* mean */
  345. fprintf(stdout, "%.15g%s", mean, zone_info.sep);
  346. /* mean of abs */
  347. fprintf(stdout, "%.15g%s", stats[z].sum_abs / stats[z].n, zone_info.sep);
  348. /* stddev */
  349. fprintf(stdout, "%.15g%s", stdev, zone_info.sep);
  350. /* variance */
  351. fprintf(stdout, "%.15g%s", variance, zone_info.sep);
  352. /* coefficient of variance */
  353. fprintf(stdout, "%.15g%s", var_coef, zone_info.sep);
  354. /* sum */
  355. sprintf(sum_str, "%.15g", stats[z].sum);
  356. G_trim_decimal(sum_str);
  357. fprintf(stdout, "%s%s", sum_str, zone_info.sep);
  358. /* absolute sum */
  359. sprintf(sum_str, "%.15g", stats[z].sum_abs);
  360. G_trim_decimal(sum_str);
  361. fprintf(stdout, "%s", sum_str);
  362. /* TODO: mode, skewness, kurtosis */
  363. if (param.extended->answer) {
  364. qpos_perc = (int *)G_calloc(stats[z].n_perc, sizeof(int));
  365. quartile_perc = (double *)G_calloc(stats[z].n_perc, sizeof(double));
  366. if (stats[z].n == 0) {
  367. quartile_25 = median = quartile_75 = 0.0 / 0.0;
  368. for (i = 0; i < stats[z].n_perc; i++)
  369. quartile_perc[i] = 0.0 / 0.0;
  370. }
  371. else {
  372. for (i = 0; i < stats[z].n_perc; i++) {
  373. qpos_perc[i] = (int)(stats[z].n * 1e-2 * stats[z].perc[i] - 0.5);
  374. }
  375. qpos_25 = (int)(stats[z].n * 0.25 - 0.5);
  376. qpos_75 = (int)(stats[z].n * 0.75 - 0.5);
  377. switch (stats[z].map_type) {
  378. case CELL_TYPE:
  379. heapsort_int(stats[z].cell_array, stats[z].n);
  380. quartile_25 = (double)stats[z].cell_array[qpos_25];
  381. if (stats[z].n % 2) /* odd */
  382. median = (double)stats[z].cell_array[(int)(stats[z].n / 2)];
  383. else /* even */
  384. median =
  385. (double)(stats[z].cell_array[stats[z].n / 2 - 1] +
  386. stats[z].cell_array[stats[z].n / 2]) / 2.0;
  387. quartile_75 = (double)stats[z].cell_array[qpos_75];
  388. for (i = 0; i < stats[z].n_perc; i++) {
  389. quartile_perc[i] = (double)stats[z].cell_array[qpos_perc[i]];
  390. }
  391. break;
  392. case FCELL_TYPE:
  393. heapsort_float(stats[z].fcell_array, stats[z].n);
  394. quartile_25 = (double)stats[z].fcell_array[qpos_25];
  395. if (stats[z].n % 2) /* odd */
  396. median = (double)stats[z].fcell_array[(int)(stats[z].n / 2)];
  397. else /* even */
  398. median =
  399. (double)(stats[z].fcell_array[stats[z].n / 2 - 1] +
  400. stats[z].fcell_array[stats[z].n / 2]) / 2.0;
  401. quartile_75 = (double)stats[z].fcell_array[qpos_75];
  402. for (i = 0; i < stats[z].n_perc; i++) {
  403. quartile_perc[i] = (double)stats[z].fcell_array[qpos_perc[i]];
  404. }
  405. break;
  406. case DCELL_TYPE:
  407. heapsort_double(stats[z].dcell_array, stats[z].n);
  408. quartile_25 = stats[z].dcell_array[qpos_25];
  409. if (stats[z].n % 2) /* odd */
  410. median = stats[z].dcell_array[(int)(stats[z].n / 2)];
  411. else /* even */
  412. median =
  413. (stats[z].dcell_array[stats[z].n / 2 - 1] +
  414. stats[z].dcell_array[stats[z].n / 2]) / 2.0;
  415. quartile_75 = stats[z].dcell_array[qpos_75];
  416. for (i = 0; i < stats[z].n_perc; i++) {
  417. quartile_perc[i] = stats[z].dcell_array[qpos_perc[i]];
  418. }
  419. break;
  420. default:
  421. break;
  422. }
  423. }
  424. /* first quartile */
  425. fprintf(stdout, "%s%g", zone_info.sep, quartile_25);
  426. /* median */
  427. fprintf(stdout, "%s%g", zone_info.sep, median);
  428. /* third quartile */
  429. fprintf(stdout, "%s%g", zone_info.sep, quartile_75);
  430. /* percentiles */
  431. for (i = 0; i < stats[z].n_perc; i++) {
  432. fprintf(stdout, "%s%g", zone_info.sep ,
  433. quartile_perc[i]);
  434. }
  435. G_free((void *)quartile_perc);
  436. G_free((void *)qpos_perc);
  437. }
  438. fprintf(stdout, "\n");
  439. /* zone z finished */
  440. }
  441. return 1;
  442. }