Memra

df[rows, cols], subset(), and the trailing comma

◈ 11 cards

orders[rows, cols]: blank rows means all rows, blank cols all columns. orders[orders$amount > 500, ] keeps 5 rows; orders[, c("order_id", "amount")] keeps two columns; subset(orders, amount > 500, select = c(order_id, amount)) does both. Forget the comma and R says "undefined columns selected".

One bracket, two slots

A data frame is indexed with two positions inside the square brackets, separated by a comma: orders[rows, cols]. Leave a slot blank and it means all of them. That comma is the whole lesson — the final's most-asked R syntax item, and the most common error in student scripts.

Worked example — columns, then rows, then both

Columns — a vector of names after the comma:

> orders[, c("order_id", "amount")]
   order_id amount
1      1001    420
2      1002    180
3      1003    760

(twelve rows; three shown). This is hiding columns in Sheets. A single name, orders[, "amount"], drops to a vector — like $.

Rows — a condition before the comma, blank after it:

> orders[orders$amount > 500, ]
   order_id prov channel amount units order_date
3      1003   ON   Store    760     5 2025-01-15
5      1005   AB  Online   1320     8 2025-02-03
6      1006   ON  Online    510     4 2025-02-10
8      1008   BC   Store    640     4 2025-02-27
10     1010   AB   Store    980     6 2025-03-11

Five rows, all columns — the AutoFilter on amount > 500, with the row names saying which rows survived. A number works in either slot: orders[2, ] is the second record, orders[2, "amount"] is 180.

Bothsubset() reads like a sentence and needs no orders$ prefix inside:

> subset(orders, amount > 500, select = c(order_id, amount))
   order_id amount
3      1003    760
5      1005   1320
6      1006    510
8      1008    640
10     1010    980

subset(orders, amount > 500) alone keeps every column; nrow() of it is 5.

The error the comma prevents

> orders[orders$amount > 500]
Error in `[.data.frame`(orders, orders$amount > 500) : 
  undefined columns selected

With one thing in the bracket, R reads it as a column selection — a data frame is a list of columns, so orders[x] means "these columns". Twelve TRUE/FALSE values against six columns is nonsense, and the message says so in its own words. The fix is the comma: orders[orders$amount > 500, ]. Read "undefined columns selected" as "you forgot the comma" until proven otherwise.

subset() and [ ] disagree about NA

With one amount missing — ona is orders with order 1003's amount set to NA, the frame Lesson 11.1 summarised — the condition amount > 500 is NA for that row. [ ] keeps it, as a row of NAs with the row name NA, in front of the four genuine matches:

> ona[ona$amount > 500, ]
   order_id prov channel amount units order_date
NA       NA <NA>    <NA>     NA    NA       <NA>
5      1005   AB  Online   1320     8 2025-02-03
6      1006   ON  Online    510     4 2025-02-10
8      1008   BC   Store    640     4 2025-02-27
10     1010   AB   Store    980     6 2025-03-11

subset() drops it: nrow(ona[ona$amount > 500, ]) is 5, nrow(subset(ona, amount > 500)) is 4. A ghost row of NAs in a filter result is this, and the cure is subset() or which() inside the bracket.

Type the three selections, then read the count

CRISP-DM: filtering rows and choosing columns is data preparation → select data.

in the slotrows (before the comma)cols (after the comma)blankall 12 rowsall 6 columnsa conditionorders$amount > 500 → 5rowsa name vectorc("order_id", "amount")a number2 → the second row4 → the fourth columnNo comma at all → column selection → "undefined columns selected".
The comma rule. Two slots, rows then columns; a blank slot means all. orders[orders$amount > 500, ] and orders[, c("order_id", "amount")] fill one slot each; subset() fills both by name.
NORMAL ~/memra/learn/afm-112/rows-and-columns-the-comma-rule utf-8 LF