{"id":13698996,"url":"https://github.com/zenrosadira/abap-tbox-stats","last_synced_at":"2025-10-24T03:32:01.609Z","repository":{"id":171884722,"uuid":"607726603","full_name":"zenrosadira/abap-tbox-stats","owner":"zenrosadira","description":"ABAP Statistical Tools - An ABAP class to compute descriptive statistics, empirical inferences, distribution sampling generation","archived":false,"fork":false,"pushed_at":"2023-06-12T13:21:33.000Z","size":246,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-30T22:51:27.304Z","etag":null,"topics":["abap","abap-development","abap-oo","statistics"],"latest_commit_sha":null,"homepage":"","language":"ABAP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zenrosadira.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-02-28T14:59:26.000Z","updated_at":"2024-11-23T14:08:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"4b2428ab-80f8-4937-99be-952f6e316eaa","html_url":"https://github.com/zenrosadira/abap-tbox-stats","commit_stats":null,"previous_names":["zenrosadira/abap-tbox-stats"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zenrosadira%2Fabap-tbox-stats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zenrosadira%2Fabap-tbox-stats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zenrosadira%2Fabap-tbox-stats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zenrosadira%2Fabap-tbox-stats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zenrosadira","download_url":"https://codeload.github.com/zenrosadira/abap-tbox-stats/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237910078,"owners_count":19385829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abap","abap-development","abap-oo","statistics"],"created_at":"2024-08-02T19:00:55.823Z","updated_at":"2025-10-24T03:32:01.229Z","avatar_url":"https://github.com/zenrosadira.png","language":"ABAP","funding_links":[],"categories":["Categories"],"sub_categories":["🧰 Generic Utilities"],"readme":"# ABAP Statistical Tools\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/zenrosadira/abap-tbox-stats/blob/main/img/stat_abap.png?raw=true\"\u003e\n\u003c/p\u003e\n\nStatistics with ABAP: why not? This project consist of an ABAP class `ztbox_cl_stats` where some of the most common descriptive statistics functions have been included together with simple tools to generate distributions and produce empirical inference analyses.\n\n## Basic Features \u0026 Elementary Statistics\nLet's compute some statistics on `SBOOK` table\n```abap\nSELECT * FROM sbook INTO TABLE @DATA(T_SBOOK).\n\nDATA(stats) = NEW ztbox_cl_stats( t_sbook ).\n```\n\nUse `-\u003ecol( )` method to select a column on which make calculations\n\n```abap\nDATA(prices) = stats-\u003ecol( `LOCCURAM` ).\n```\n\nEach statistic has its own method\n\n```abap\n* The smallest value\nDATA(min)        = prices-\u003emin( ).                       \" [148.00]\n\n* The largest value\nDATA(max)        = prices-\u003emax( ).                       \" [6960.12]\n\n* The range, i.e. the difference between largest and smallest values\nDATA(range)      = prices-\u003erange( ).                     \" [6812.12]\n\n* The sum of the values\nDATA(tot)        = prices-\u003esum( ).                       \" [25055655.41]\n\n* The sample mean of the values\nDATA(mean)       = prices-\u003emean( ).                      \" [922.96]\n\n* The mean absolute deviation (MAD) from the mean\nDATA(mad_mean)   = prices-\u003emad_mean( ).                  \" [480.41]\n\n* The sample median of the values\nDATA(median)     = prices-\u003emedian( ).                    \" [670.34]\n\n* The mean absolute deviation (MAD) from the median\nDATA(mad_median) = prices-\u003emad_median( ).                \" [436.36]\n\n* The sample variance of the values\nDATA(variance)   = prices-\u003evariance( ).                  \" [572404.48]\n\n* The sample standard deviation of the values\nDATA(std_dev)    = prices-\u003estandard_deviation( ).        \" [756.57]\n\n* The coefficent of variation, ratio of the standard deviation to the mean\nDATA(coeff_var)  = prices-\u003ecoefficient_variation( ).     \" [0.819]\n\n* The dispersion index, ratio of the variance to the mean\nDATA(disp_index) = prices-\u003edispersion_index( ).          \" [620.18]\n\n* The number of distinct values\nDATA(dist_val)   = prices-\u003ecount_distinct( ).            \" [324]\n\n* The number of not initial values\nDATA(not_init)   = prices-\u003ecount_not_initial( ).         \" [27147]\n```\n\nAlternatively, you can use the main instance, which represents the entire table, passing the name of the relevant column:\n\n```abap\nDATA(min_price)  = stats-\u003emin( `LOCCURAM` ).\n```\n\n## More specific descriptive statistics\n\n### Quartiles\n25% of the data is below the *first quartile* $Q1$\n\n```abap\nDATA(first_quartile) = prices-\u003efirst_quartile( ). \" [566.10]\n```\n\n50% of the data is below the *second quartile* or *median* $Q2$\n\n```abap\nDATA(second_quartile) = prices-\u003esecond_quartile( ). \" [670.34]\nDATA(median)          = prices-\u003emedian( ). \" It's just a synonym for second_quartile( )\n```\n\n75% of the data is below the *third quartile* $Q3$\n\n```abap\nDATA(third_quartile) = prices-\u003ethird_quartile( ). \" [978.50]\n```\n\nThe difference between third and first quartile is called *interquartile range* $\\mathrm{IQR} = Q3 - Q1$, and it is a measure of spread of the data\n\n```abap\nDATA(iqr) = prices-\u003einterquartile_range( ). \" [412.40]\n```\n\nA value outside the range $\\left[Q1 - 1.5\\mathrm{IQR},\\ Q3 + 1.5\\mathrm{IQR}\\right]$ can be considered an *outlier*\n```abap\nDATA(outliers) = prices-\u003eoutliers( ). \" Found 94 outliers, from 1638.36 to 6960.12\n```\n\n### Means\n\nHarmonic Mean is $\\frac{n}{\\frac{1}{x_1}\\+\\ \\ldots\\ +\\ \\frac{1}{x_n}}$, used often in averaging rates\n\n```abap\nDATA(hmean) = prices-\u003eharmonic_mean( ). \" [586.17]\n```\n\nGeometric Mean is $\\sqrt[n]{x_1\\cdot \\ldots \\cdot x_n}$, used for population growth or interest rates\n\n```abap\nDATA(gmean) = prices-\u003egeometric_mean( ). \" [731.17]\n```\n\nQuadratic Mean is $\\sqrt{\\frac{x_1^2\\ +\\ \\ldots\\ +\\ x_n^2}{n}}$, used, among other things, to measure the fit of an estimator to a data set\n\n```abap\nDATA(qmean) = prices-\u003equadratic_mean( ). \" [1193.42]\n\n* The values calculated so far confirm the HM-GM-AM-QM inequalities\n* harmonic mean \u003c= geometric mean \u003c= arithmetic mean \u003c= quadratic mean\n```\n \n### Moments\n\n*Skewness* is a measure of the asymmetry of the distribution of a real random value about its mean. We estimate it with a sample skewness computed with the adjusted Fisher-Pearson standardized moment coefficient (the same used by Excel).\n\n$$\\mathrm{skewness} = \\frac{n}{(n-1)(n-2)}\\frac{\\sum\\limits_{i=1}^n {(x_i - \\bar{x})}^3}{\\left[\\frac{1}{n-1}\\sum\\limits_{i=1}^{n} (x_i - \\bar{x})^2 \\right]^{3/2}}$$\n\n```abap\nDATA(skewness) = prices-\u003eskenewss( ). \" [3.19] \n* positive skewness: right tail is longer, the mass of the distribution is concentrated on the left\n```\n\n*Kurtosis* is a measure of the tailedness of the distribution of a real random value: higher kurtosis corresponds to greater extremity of outliers\n\n$$\\mathrm{kurtosis} = \\frac{1}{(n-1)}\\frac{\\sum\\limits_{i=1}^n {(x_i - \\bar{x})}^4}{\\left[\\frac{1}{n-1}\\sum\\limits_{i=1}^{n} (x_i - \\bar{x})^2 \\right]^2}$$\n\n```abap\nDATA(kurtosis) = prices-\u003ekurtosis( ). \" [19.18]\n* positive excess kurtosis (kurtosis minus 3): leptokurtic distribution with fatter tails\n```\n\n## Empirical Inference\n\nThe *histogram* is a table of couples $(\\mathrm{bin}_i, \\mathrm{f}_i)$ where $\\mathrm{bin}_i$ is the first endpoint of the $i$-th *bin*, i.e. the interval with which the values were partitioned, and $\\mathrm{f}_i$ is the $i$-th frequency, i.e. the number of values inside the $i$-th bin.\n\n```abap\nDATA(histogram) = prices-\u003ehistogram( ).\n```\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/zenrosadira/abap-tbox-stats/blob/main/img/hist.png?raw=true\" width=\"400\" height=\"250\"\u003e\n\u003c/p\u003e\n\nThe bins are created using *Freedman-Diaconis rule*: the bins width is $\\frac{2\\mathrm{iqr}}{\\sqrt[3]{n}}$ where $\\mathrm{iqr}$ is the interquartile range, and the total number of bins is $\\mathrm{floor}\\left(\\frac{\\mathrm{max} - \\mathrm{min}}{\\mathrm{bin\\ width}}\\right)$\n\nDividing each frequency by the total we get an estimate of the probability to draw a value in the corresponding bin, this is the *empirical probability*\n\n```abap\nDATA(empirical_prob) = prices-\u003eempirical_pdf( ).\n```\n\nSimilarly, for each distinct value $x$, we can compute the number $\\frac{\\mathrm{number\\ of\\ elements}\\ \\le\\ x}{n}$, this is the *empirical distribution function*\n\n```abap\nDATA(empirical_dist) = prices-\u003eempirical_cdf( ).\n```\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/zenrosadira/abap-tbox-stats/blob/main/img/ecdf.png?raw=true\" width=\"400\" height=\"250\"\u003e\n\u003c/p\u003e\n\nIn order to answer the question \"are the values normally distributed?\" you can use method `-\u003eare_normal( )`\n\n```abap\nDATA(normality_test) = prices-\u003eare_normal( ) \" [abap_false].\n```\n\nThis method implements the [Jarque-Bera normality test](https://en.wikipedia.org/wiki/Jarque%E2%80%93Bera_test). The $p$-value is an exported parameter and the test is considered passed if $p\\mathrm{-value} \u003e \\alpha$ where $\\alpha = 0.5$ by default (it's an optional parameter).\n\n## Distributions\n\nThe following are static methods to generate samples from various distributions\n\n```abap\n\" Continuous Uniform Distribution\nDATA(uniform_values) = ztbox_cl_stats=\u003euniform( low = 1 high = 50 size = 10000 ).\n\" Generate a sample of 10000 values from a uniform distribution in the interval [1, 50]\n\" default is =\u003euniform( low = 0 high = 1 size = 1 )\n\n\" Continuous Normal Distribution\nDATA(normal_values) = ztbox_cl_stats=\u003enormal( mean = `-3` variance = 13 size = 1000 ).\n\" Generate a sample of 1000 values from a normal distribution with mean = -3 and variance 13\n\" default is =\u003enormal( mean = 0 variance = 1 size = 1 )\n\n\" Continuous Standard Distribution\nDATA(standard_values) = ztbox_cl_stats=\u003estandard( size = 100 ).\n\" Generate a sample of 100 values from a standard distribution, i.e. a normal distribution \n\" with mean = 0 and variance = 1\n\" default is =\u003enormal( size = 1 )\n\n\" Discrete Bernoulli Distribution\nDATA(bernoulli_values) = ztbox_cl_stats=\u003ebernoulli( p = `0.8` size = 100 ).\n\" Generate a sample of 100 values from a bernoulli distribution with probability parameter = 0.8\n\" default is =\u003ebernoulli( p = `0.5` size = 1 )\n\n\" Discrete Binomial Distribution\nDATA(binomial_values) = ztbox_cl_stats=\u003ebinomial( n = 15 p = `0.4` size = 100 ).\n\" Generate a sample of 100 values from a binomial distribution \n\" with probability parameter = 0.4 and number of trials = 15\n\" default is =\u003ebinomial( n = 2 p = `0.5` size = 1 )\n\n\" Discrete Geometric Distribution\nDATA(geometric_values) = ztbox_cl_stats=\u003egeometric( p = `0.6` size = 100 ).\n\" Generate a sample of 100 values from a geometric distribution with probability parameter = 0.6\n\" default is =\u003egeometric( p = `0.5` size = 1 )\n\n\" Discrete Poisson Distribution\nDATA(poisson_values) = ztbox_cl_stats=\u003epoisson( l = 4 size = 100 ).\n\" Generate a sample of 100 values from a poisson distribution with lambda parameter = 4\n\" default is =\u003epoisson( l = `1.0` size = 1 )\n```\n\nLet's plot the *empirical probability density function* of a sample of 100000 values drawn from a generated standard normal distribution:\n\n```abap\nDATA(gauss)      = ztbox_cl_stats=\u003estandard( size = 100000 ).\nDATA(gauss_stat) = NEW ztbox_cl_stats( gauss ).\nDATA(g_pdf)      = gauss_stat-\u003eempirical_pdf( ).\n```\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://github.com/zenrosadira/abap-tbox-stats/blob/main/img/gauss.png?raw=true\" width=\"400\" height=\"250\"\u003e\n\u003c/p\u003e\n\nyep! I recognize this shape.\n\n## Feature Scaling\nIn some cases can be useful to work with normalized data\n\n```abap\nDATA(normalized_prices) = prices-\u003enormalize( ).\n\" Each value is transformed subtracting the minimal value and dividing by the range (max - min)\n\nDATA(standardized_prices) = prices-\u003estandardize( ).\n\" Each value is transformed subtracting the mean and dividing by the standard deviation\n```\n\n## Joint Variability\n### Covariance\nIn order to compute the sample covariance of two columns call method `-\u003ecovariance` passing the columns separated by comma\n\n```abap\nDATA(stats)      = NEW ztbox_cl_stats( t_sbook ).\nDATA(covariance) = stats-\u003ecovariance( `LOCCURAM, LUGGWEIGHT` ). \" [1037.40]\n```\n\n### Correlation\nThe sample correlation coefficient is computed by calling `-\u003ecorrelation` method\n```abap\nDATA(stats)      = NEW ztbox_cl_stats( t_sbook ).\nDATA(covariance) = stats-\u003ecovariance( `LOCCURAM, LUGGWEIGHT` ). \" [0.17]\n```\n\n## Aggregations\nEach descriptive statistics explained so far can be calculated performing first a group-by with other columns\n\n```abap\nDATA(stats)               = NEW ztbox_cl_stats( sbook ).\nDATA(grouped_by_currency) = stats-\u003egroup_by( `FORCURKEY` ).\n\" You can also perform a group-by with multiple columns, just comma-separate them\n\" e.g. stats-\u003egroup_by( `FORCURKEY, SMOKER` ).\nDATA(prices_per_currency) = grouped_by_currency-\u003ecol( `FORCURAM` ).\nDATA(dev_cur)             = prices_per_currency-\u003estandard_deviation( ).\n```\n\n`dev_cur` is a table with two fields: the first one is a table with the group-by conditions (group-by field and value), the second one contains the statistics computed (standard deviation in this example).\n\nThe same result can be obtained passing a table having the group-by fields and an additional field for the statistic\n\n```abap\nTYPES: BEGIN OF ty_dev_cur,\n         forcurkey          TYPE sbook-forcurkey,\n         price_std_dev      TYPE f,\n       END OF ty_dev_cur.\n\nDATA t_dev_cur TYPE TABLE OF ty_dev_cur.\n\nprices_per_currency-\u003estandard_deviation( IMPORTING e_result = t_dev_cur ).\n```\n\n| FORCURKEY | PRICE_STD_DEV |\n| :---: | :---: |\n| EUR\t| 5.1572747413790194E+02 |\n| USD\t| 4.5762828742456850E+02 |\n| GBP\t| 2.9501066968757806E+02 |\n| JPY\t| 5.2009995569407386E+02 |\n| CHF\t| 8.5376086718562442E+02 |\n| AUD\t| 3.9095624219014348E+02 |\n| ZAR\t| 4.3830708141667837E+03 |\n| SGD\t| 1.0340758423220680E+03 |\n| SEK\t| 4.4754710657225996E+03 |\n| CAD\t| 7.7769277990938747E+02 |\n\n# Contributions\nMany features can be improved or extended (new distribution generators? implementing statistic tests?) every contribution is appreciated\n\n# Installation\nInstall this project using [abapGit](https://abapgit.org/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzenrosadira%2Fabap-tbox-stats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzenrosadira%2Fabap-tbox-stats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzenrosadira%2Fabap-tbox-stats/lists"}