STATS_COLUMNS – rename selected columns with flexible naming rules

What it does

Renames the selected columns and returns them with the new headers; columns that are not selected are not returned.

Uses colFilter to choose which columns to rename (by name, regex, or index rules).

The last parameter supports three modes: suffix, explicit "|" list, or template naming like "name{1}".

Syntax

=STATS_COLUMNS(columns, 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 columns
  • A1:C200 — use 3 columns
  • A:F — use 6 columns
  • A1: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.

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):

  1. By name - exact header text (case-sensitive)
    • "age,score,total"
  2. Negative rules - exclude by name (prefix with -)
    • "-id,-notes" (include all except id and notes)
  3. 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.
  4. 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
  • — Append suffix to selected columns =STATS_COLUMNS(Data!A1:T51, "x,x2", "_renamed")
  • — Use explicit names with | =STATS_COLUMNS(Data!A1:T51, "x,x2", "new_x|new_x2")
  • — Use template naming item1,item2,... =STATS_COLUMNS(Data!A1:T51, "/^q/", "item{1}")
  • — Index-based colFilter with template start index =STATS_COLUMNS(Data!A1:T51, "#2-#4", "part{5}")
  • — Short names list; remaining names use _missing fallback =STATS_COLUMNS(Data!A1:T51, "x,x1,x2", "a|b")
  • — Mixed templates + fixed name in one outputNames pattern =STATS_COLUMNS(Data!A1:T51, "/^q/", "first{1-3}|some|second{1-3}")
  • — Range templates (including reverse) mixed with fixed and auto-start templates =STATS_COLUMNS(Data!A1:T51, "/^q/", "block{4-2}|mid|tail{}")

What the result contains

A 2D array with the selected columns only, in the order of the range: the first row holds the new names, the next rows keep the original values.

Names are given in the order of colFilter: with "t,x" and "p|q", t is named p and x is named q, and x comes first because it is first in the range.

Without outputNames every selected column is named "<oldName>_missing"; a "|" list shorter than the selected columns fills the rest the same way.

Errors

If colFilter selects no columns, one cell: colFilter "/^Q/" selects no columns (columns: q1, q2, t).

A column name that does not exist: "Column nope does not exist". A repeated new name: "Duplicate column name: z".

Avoid column names starting with "#": this prefix is reserved for index-based colFilter syntax.

About STATS_COLUMNS

STATS_COLUMNS renames columns. It returns only the selected columns, in the order of the range: the first row holds the new names, the next rows keep the original values. This helps when survey questions arrive from Google Forms with long headers and you want short names such as item1, item2 for further formulas; the renamed copy updates by itself when new responses arrive.

Choose the columns with colFilter: by name ("age,score"), excluding with a minus ("-id"), by a pattern between slashes ("/^q/") or by position ("#2-#4"). The new names come from outputNames in one of three forms: a suffix ("_renamed" turns x into x_renamed), a list separated by | ("new_x|new_x2"), or a template such as "item{1}" that numbers the columns item1, item2 and so on.

Names are given in the order of colFilter. If the list is shorter than the selected columns, or outputNames is left out, the remaining columns are named <old name>_missing. New names must be different: a repeated name is an error "Duplicate column name: z".