STATS_COMPUTE function – compute row metrics and expressions
What it does
Creates new columns from a text query.
Works with a data range where columns are variables and rows are cases.
Use colFilter to include names, exclude with -name, or match with a /regex/.
The last parameter may be either a suffix or a "|"-separated list of explicit output names.
The whole expression is read with the usual arithmetic (decimals, exponents, powers of brackets); see query.
Syntax
=STATS_COMPUTE(columns, query, colFilter, outputNames)Parameters
columns — required
Cell range with data, e.g., A1:D100 or A:D.
Usually the first row should contain column names.
You can also add labels as the first row and column names as the second row.
Labels should use formats like "male:1,female:2" or "low:1:3,mid:3:5,high:5:7".
Examples:
A1:D100— use 4 columnsA1:C200— use 3 columnsA:F— use 6 columnsA1:D100 where row 1 contains labels and row 2 contains column names— use labels from the sheet
If every non-empty cell of the first row holds at least two label rules ("low:1,high:2"), it is the labels row, and the next row holds the column names; an empty cell there is a column without labels.
One rule in a cell ("yes:1") is read as a name, so a header such as "T:1", "Ratio 1:2" or "Note:" stays the names row. Give such a column a second rule, or pass one label in the labels parameter, where one rule is valid.
If the first row contains ordinary text, it is treated as the column names row as before.
A number, a date or a checkbox in the names row is a name: 2025, 2025-01-01, TRUE.
Column names must be unique: two identical headers are an error "Duplicate column name: x".
Every column with values needs a name: an empty header cell over values is an error "The name of column 2 is empty: a column with values needs a name", even when colFilter does not select that column. A column with neither a name nor values (the empty right edge of a range such as A:Z) is dropped without an error.
Column names that start with "#" are reserved/unsupported in filters, because "#" is used for index-based colFilter rules (for example #1, #2-#5).
What counts as a number (the same in every function):
- A column is numeric when it holds more numbers than text; with as many texts as numbers, or more, it is a text column.
- Every cell is typed by itself: a number written as text ('10', '007') is the number, a checkbox is 1 (checked) or 0 (unchecked). The texts 'TRUE'/'FALSE' stay text.
- A cell that does not match the type of its own column (text in a numeric column, a number in a text column) is missing for calculations and is counted in missing.
- An empty cell is a missing answer; the sign "." means "not applicable" — it is not a missing answer, not a category and not counted in missing.
- A text column with value labels (a labels row above the names) is analysed by the codes of its labels. A text column without labels is not analysed as numbers: lists of columns skip it with a note, tests on a pair of columns and models show an error.
An empty tail of the range (rows below the data) is dropped — only blank cells make it: a row of "." at the end stays and counts as not applicable, as in the middle. A column with neither a name nor values is dropped; a named empty column stays.
query — required
Comma-separated expressions; each one becomes a new column computed row by row.
Operators: + - * / ^ and brackets; absolute value as |x|. Numbers may have decimals and exponents (0.5, 1e-2).
^ is computed right to left (2^3^2 = 2^9) and before a unary minus (-x^2 = −x²); any exponent works: x^0.5, x^-1, x^(1/3).
Column names are variables: exact header text (case matters), and only columns chosen by colFilter.
Row metrics over the values of the row in the colFilter columns: sum,mean,slope,sumOfSquares,variance,std,cv,skewness,kurtosis,geometricMean,harmonicMean,flatness,median,q1,q3,p10,p90,relativeDispersion,iqr,range,min,max,rSlope,mad,weight,spd,regressionSlope,spectralPowerDensityMetric,stdDev,missing
Examples:
"mean,std"— mean and standard deviation of each row"|x|", "mean^2"— two columns: absolute value of x, and the squared row mean"score*0.5,(x+1)^2,x^0.5"— decimals, powers of brackets, a square root as a powerxCol*yCol
There are no functions: sqrt(x) is an error — write x^0.5.
The whole expression is read; anything it cannot read is one error cell for the whole formula, for example:
compute: unknown name "sqrt" in "sqrt(score)"
compute: unknown name "height" in "score*height" (not in colFilter)
compute: unexpected end in "(x"
A row with a missing value gives "."; 0/0 gives "." too.
A non-zero value divided by zero, or a result too large for a number, shows #NUM! in its cell (as =1/0 in Sheets);
SUM or AVERAGE over such a column is #NUM! as well.
Text with value labels (a labels row above the names) counts by its codes; a text column without labels gives ".".
Metrics with a parameter (weightedMean.w, percentile.95, zScore.v) are not available in an expression.
colFilter — optional, default "*"
Comma-separated column selector.
Use names ("age,score"), negative rules ("-id,-note"), a regex ("/^q/"), or index rules ("#N", "#A-#B", "-#N", "-#A-#B").
Case-sensitive; flags are not supported.
A name that does not exist is an error: "Column nope does not exist" (excluding it, "-nope", is ignored). Empty — all columns ("*").
Examples:
"age,score"— Names only (include only "age" and "score")"-id,-group"— Exclude some (include all except "id" and "group")"/^q/"— Regex only (all starts with "q")"#1,#3-#5"— Index include rules (first, and range 3..5)"-#1,-#3-#4"— Index exclude rules (drop first and 3..4)"age,#2-#4,-#3"— Mixed name/index rules with deterministic order"age,/^q/,-q5"— Mixed (include age, all starts with "q" except "q5")"/^x1{1,2}$/"— Regex with a comma inside: x1 and x11
Choose which columns from columns to use - a comma-separated string of rules.
⚙️ Four rule types (you can mix them):
- By name - exact header text (case-sensitive)
- "age,score,total"
- Negative rules - exclude by name (prefix with
-)- "-id,-notes" (include all except
idandnotes)
- "-id,-notes" (include all except
- Regex - a regular expression between slashes
/.../- "/^q/" (all headers starting with
q), "/(score|age)/", "/^x1{1,2}$/" (commas inside /.../ do not split the filter) - ❗— case-sensitive
- ❗— flags are not supported.
- "/^q/" (all headers starting with
- Index rules - position-based rules with
#- "#1" (first selected column), "#2-#5" (range), "-#1", "-#2-#4"
"*" alone selects every column; it cannot be combined with other rules ("*,-id" is an error) — write "-id" instead.
Rules are applied in the written order, and the selected columns keep that order ("/^q/,-q5,age" puts age last).
Index rules count the columns of the range: "#1" is its first column.
A name that does not exist is an error: "Column nope does not exist" — also in colName, yName, steps, rowCol, colCol and colNameForSplit. Excluding a name that does not exist ("-nope") is ignored.
A filter that selects no column — a regex without a match ("/^Q/" where the columns are q1, q2), index rules past the end, exclusions that remove every column — is an error that names the filter and the columns of the range: colFilter "/^Q/" selects no columns (columns: q1, q2, t). Empty and "*" select every column.
In STATS_ANALYZE, a regex with brackets or | needs the new syntax: PEARSON('/(score|age)/').
A colFilter saved in Settings applies to every formula without its own filter: on a range without those columns the formula shows the error above.
# prefix is reserved for index syntax and is not treated as a column-name filter token.
colFilter applies to all expressions in query. It does not create separate groups per expression.
outputNames — optional
Controls names of new output columns.
You can pass a regular suffix, for example "_bin" or "-calc".
You can also pass explicit output names as a "|"-separated list.
In COMPUTE, names are assigned in the same order as expressions in query.
In RECODE, names are assigned in the same order as selected source columns.
In RECODE, template naming is supported, for example "code{1}" or "group{5}".
Short "|"-separated lists are allowed; a missing name becomes <column>_missing ("z|" on x1,x2 gives z and x2_missing).
One name without "|" is a suffix: "x2" turns x1 into x1x2.
New names must be different: a repeated name is an error "Duplicate column name: z" in STATS_COLUMNS, STATS_RECODE and STATS_COMPUTE (there also when the same expression is written twice without names).
Examples:
"-calc""_bin""ratio|row_mean|row_std""age_bin|income_bin""code{1}""new_a||new_c"
Examples
- — the sample data (50 rows) all examples use
- —
=STATS_COMPUTE(Data!A1:T51, "median,range", "x,x1,x2","-stat") - — Use -calc as postfix for columns
=STATS_COMPUTE(Data!A1:T51, "x1/x2,(x+x1)/(x2+1),y^2", "x,x1,x2,y","-calc") - —
=STATS_COMPUTE(Data!A1:T51, "mean,std", "*", "s-") - — Use explicit names with |
=STATS_COMPUTE(Data!A1:T51, "x1/x2,mean,std", "x,x1,x2", "ratio|row_mean|row_std")
What the result contains
2D array that spills below the formula cell:
- First row — headers: the expression itself plus the suffix ("median-stat"), or the explicit names.
- Following rows — computed values aligned to input data rows.
A row with a missing value shows "."; 0/0 shows "." too.
A non-zero value divided by zero, or a result too large for a number, shows #NUM! in its cell (as =1/0 in Sheets).
Text with value labels counts by its codes; a text column without labels gives ".".
Errors
An unknown name, a function or a syntax error is one error cell for the whole formula:
compute: unknown name "sqrt" in "sqrt(score)"; compute: unknown name "y" in "x*y" (not in colFilter); compute: unexpected end in "(x".
A column name that does not exist in colFilter: "Column nope does not exist".
Two new columns with one name ("a|a", or the same expression twice without names): "Duplicate column name: a".
About STATS_COMPUTE
STATS_COMPUTE creates new columns from a text query. Each comma-separated expression becomes a column computed row by row, for example the ratio of two answers or a squared score. Column names are the variables; the operators are + - * / ^ with brackets, and |x| is the absolute value. The result spills below the formula cell, aligned with the rows of your data, and recalculates by itself when new responses arrive from Google Forms.
Row metrics work over the values of the row in the columns chosen by colFilter: mean, std, median, sum, min, max, range, q1, q3, iqr, missing and more, so "mean,std" gives the mean and standard deviation of each row. There are no functions: write x^0.5 instead of sqrt(x). Headers are the expression plus a suffix, or your own names given as a list separated by |.
A row with a missing value gives ".", and so does 0/0; a non-zero value divided by zero shows #NUM!, as =1/0 does in Sheets. A text column with value labels counts by its codes. Anything the formula cannot read, such as an unknown name, a function or a missing bracket, is one error cell for the whole formula that names the problem, for example: compute: unknown name "sqrt" in "sqrt(score)".