Created
August 19, 2026 13:32
-
-
Save Medohh2120/4c684ea7121c43ef5f69f5c2a64afdca to your computer and use it in GitHub Desktop.
Excel's version of python's DESCRIBE() function
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| Name: DESCRIBE | |
| Description: Generates a descriptive-statistics summary for each selected column, | |
| similar to Python's pandas .describe() function. | |
| [isSample] default: TRUE; uses sample variance, standard deviation, and skewness. | |
| [include] default: 0; 0 = numeric columns, 1 = text columns, 2 = all columns. | |
| [Has_hdrs?] default: TRUE; specifies whether the first row contains headers. | |
| Made By: Medohh2120 | |
| */ | |
| DESCRIBE = LAMBDA(table, [isSample], [include], [Has_hdrs?], | |
| LET( | |
| /* Set defaults and dynamic statistical function assignments */ | |
| isSample, IF(ISOMITTED(isSample), TRUE, isSample), | |
| hasHeaders, IF(ISOMITTED(Has_hdrs?), TRUE, Has_hdrs?), | |
| include, IF(ISOMITTED(include), 0, include), | |
| varFn, IF(isSample, VAR.S, VAR.P), | |
| stdFn, IF(isSample, STDEV.S, STDEV.P), | |
| skewFn, IF(isSample, SKEW, SKEW.P), | |
| /* Isolate headers and evaluate sample row to filter data columns */ | |
| vals_sample_row, IF(hasHeaders, CHOOSEROWS(table, 2), CHOOSEROWS(table, 1)), // filter columns based on 1st row. | |
| select_colsλ, SWITCH( | |
| TRUE, | |
| include = 0, ISNUMBER, | |
| include = 1, ISTEXT, | |
| include = 2, LAMBDA(item, SEQUENCE(, COLUMNS(item))) //Include everything | |
| ), | |
| filtered_tbl, FILTER(table, select_colsλ(vals_sample_row)), | |
| filtered_core_Data, IF(hasHeaders, DROP(filtered_tbl, 1), filtered_tbl), | |
| headers, IF(hasHeaders, TAKE(filtered_tbl, 1), ""), | |
| /* Define 17 metrics and calculations for numeric columns */ | |
| Numeric_stat_labels, { | |
| "Count"; "Mode"; "Mean"; "Min"; "Max"; "Range"; | |
| "Variance"; "Std Dev"; "Q1 (25%)"; "Q2 (50%)"; "Q3 (75%)"; "IQR"; | |
| "Lower Bound"; "Upper Bound"; "Low Outliers"; "High Outliers"; "Skewness" | |
| }, | |
| Numeric_statλ, LAMBDA(col, | |
| LET( | |
| _q1, QUARTILE.INC(col, 1), | |
| _q2, MEDIAN(col), | |
| _q3, QUARTILE.INC(col, 3), | |
| iqr, _q3 - _q1, | |
| lowBound, _q1 - 1.5 * iqr, | |
| highBound, _q3 + 1.5 * iqr, | |
| result, VSTACK( | |
| COUNTA(col), | |
| IFNA(TEXTJOIN(", ", , MODE.MULT(col)), "No mode"), | |
| AVERAGE(col), | |
| MIN(col), | |
| MAX(col), | |
| MAX(col) - MIN(col), | |
| varFn(col), | |
| stdFn(col), | |
| _q1, | |
| _q2, | |
| _q3, | |
| iqr, | |
| lowBound, | |
| highBound, | |
| TEXTJOIN(", ", , FILTER(col, col <= lowBound, "No outliers")), | |
| TEXTJOIN(", ", , FILTER(col, col >= highBound, "No outliers")), | |
| skewFn(col) | |
| ), | |
| IFERROR(result, EXPAND("", 17, , "")) //handle error from running on textual data | |
| ) | |
| ), | |
| /* Define 4 metrics and calculations for textual columns */ | |
| Textual_stat_labels, {"Count"; "Unique"; "Top"; "Freq"}, | |
| Textual_statλ, LAMBDA(col, | |
| LET( | |
| _count, COUNTA(col), | |
| _unique,UNIQUE(col), | |
| _unique_count, COUNTA(_unique), | |
| count_per_item, MAP(_unique, LAMBDA(cell, SUM(--(cell = col)))), //countif only accepts ranges so re-engineer it. | |
| _freq, MAX(count_per_item), | |
| _top, XLOOKUP(_freq,count_per_item,_unique), | |
| VSTACK(_count, _unique_count, _top, _freq) | |
| ) | |
| ), | |
| /* Branch the execution logic based on include value (0=Numeric, 1=Text, 2=Combined) */ | |
| result, CHOOSE(include + 1, | |
| HSTACK(Numeric_stat_labels, _bycolλ(filtered_core_Data, Numeric_statλ)), | |
| HSTACK(Textual_stat_labels, _bycolλ(filtered_core_Data, Textual_statλ)), | |
| LET( | |
| stat_labels, VSTACK(Textual_stat_labels, Numeric_stat_labels), | |
| stats_grid, _Mapλ( | |
| VSTACK(Textual_statλ, Numeric_statλ), //We can map through array of functions in excel. | |
| LAMBDA(func, _bycolλ(filtered_core_Data, func)) | |
| ), | |
| labeled_stats,HSTACK(stat_labels, stats_grid), | |
| FILTER(labeled_stats,SEQUENCE(21)<>5) //Remove extra "Count" row from Numeric_statλ ouput. | |
| ) | |
| ), | |
| /* Combine extracted top headers with compiled matrix grid */ | |
| Vstack(Hstack("",headers),result) | |
| ) | |
| ); | |
| /* A compressed classical REDUCE+HSTACK acting similar to BYCOL with nested arrays support */ | |
| _bycolλ = LAMBDA(array, func, DROP( REDUCE("", SEQUENCE(COLUMNS(array)), LAMBDA(acc, nxt, HSTACK(acc, func(INDEX(array, , nxt))))), , 1 ) ); | |
| /* A compressed classical REDUCE+VSTACK acting similar to MAP with nested arrays support */ | |
| _Mapλ = LAMBDA(array, func, DROP(REDUCE("", array, LAMBDA(acc, nxt, VSTACK(acc, func(nxt)))), 1)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment