Free demoJob-oriented courses at Debugshala, Old Palasia, Indore. Freshers, non-IT and year-gap welcome.Book a free demo +91-8982385539

R Matrices and Arrays: matrix(), Indexing, apply() and More

Lesson 6 of 7 · 10 min · Updated 13 Nov 2026

Learn R matrices and arrays with store-by-category sales: build with matrix(), name rows and columns, index with [i, j], add totals and stack months.

On the wall of Malwa Mart's head office hangs a sheet that the owner checks every month. Down the left side are the four stores: Vijay Nagar, Palasia, Rajwada and Bhawarkuan. Across the top are three categories: Grocery, Dairy and Snacks. Each cell holds that store's sales in that category, in thousands of rupees.

With one glance the owner can read across a row to see how a store did, or down a column to compare stores on dairy. When November ends, the clerk pins a new sheet of the same shape on top of October's. A stack of identical grids, one per month.

In R that single sheet is a matrix. The stores are rows, the categories are columns, and each cell is an element found by its row and column number. The stack of monthly sheets is an array with three dimensions: store, category and month.

A matrix in R is a two-dimensional data structure that holds values of a single type in rows and columns; an array extends the same idea to three or more dimensions.

A matrix is really a vector with a dim attribute that tells R how to fold it into rows and columns. That is why the one-type rule still applies. Code here targets R 4.4+.

How do you create a matrix in R?

Pass a vector to matrix() and say how many rows (or columns) you want. R then pours the values in column by column, top to bottom, which is the single most important thing to remember.

R matrix fill order: matrix() fills column by column by default, and byrow = TRUE fills row by row

The same six values poured into a 2 by 3 matrix. Default filling goes down the columns; byrow = TRUE goes across the rows.

R
matrix(1:6, nrow = 2)
matrix(1:6, nrow = 2, byrow = TRUE)
Output
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

Now the real sheet. The values are entered column by column: four grocery figures, then four dairy, then four snacks. dimnames attaches store and category labels.

R
oct <- matrix(
  c(412, 356, 298, 264,    # Grocery
    168, 141, 102,  97,    # Dairy
     95,  88, 121,  73),   # Snacks
  nrow = 4,
  dimnames = list(c("Vijay Nagar", "Palasia", "Rajwada", "Bhawarkuan"),
                  c("Grocery", "Dairy", "Snacks"))
)

oct
dim(oct)
nrow(oct)
ncol(oct)
Output
            Grocery Dairy Snacks
Vijay Nagar     412   168     95
Palasia         356   141     88
Rajwada         298   102    121
Bhawarkuan      264    97     73
[1] 4 3
[1] 4
[1] 3

You can also set labels later with rownames(oct) <- ... and colnames(oct) <- .... Named matrices are far easier to index and to read in output.

Quick check

What does matrix(1:6, nrow = 2)[1, ] return?

How do you index a matrix in R?

Matrix indexing uses two positions inside the brackets, [row, column], separated by a comma. Leave one side empty to mean "all of them". Each side accepts numbers, names, negative numbers or a logical vector, exactly as with vectors.

R
oct[1, 2]
oct["Rajwada", "Snacks"]
oct["Palasia", ]
oct[, "Dairy"]
oct[c("Vijay Nagar", "Bhawarkuan"), c("Grocery", "Snacks")]
oct[oct[, "Grocery"] > 300, ]
Output
[1] 168
[1] 121
Grocery   Dairy  Snacks 
    356     141      88 
Vijay Nagar     Palasia     Rajwada  Bhawarkuan 
        168         141         102          97 
            Grocery Snacks
Vijay Nagar     412     95
Bhawarkuan      264     73
            Grocery Dairy Snacks
Vijay Nagar     412   168     95
Palasia         356   141     88

The last line filters rows by a condition: it keeps stores whose grocery sales are above 300 thousand. Notice that taking a single row or column returns a plain named vector, not a one-row matrix. R drops the unused dimension.

Keeping the matrix shape with drop = FALSE

Dropping is usually convenient but can break code that expects a matrix. Add drop = FALSE to keep the result two-dimensional.

R
oct["Palasia", , drop = FALSE]
dim(oct["Palasia", , drop = FALSE])
Output
        Grocery Dairy Snacks
Palasia     356   141     88
[1] 1 3

Row and column summaries: rowSums, colSums and apply

Analysts rarely want single cells. They want totals per store and per category. R has fast dedicated functions for sums and means, and apply() for anything else.

R
rowSums(oct)
colSums(oct)
round(colMeans(oct), 1)
apply(oct, 1, max)
apply(oct, 2, function(col) names(which.max(col)))
Output
Vijay Nagar     Palasia     Rajwada  Bhawarkuan 
        675         585         521         434 
Grocery   Dairy  Snacks 
   1330     508     377 
Grocery   Dairy  Snacks 
  332.5   127.0    94.2 
Vijay Nagar     Palasia     Rajwada  Bhawarkuan 
        412         356         298         264 
      Grocery         Dairy        Snacks 
"Vijay Nagar" "Vijay Nagar"     "Rajwada" 

In apply(), the second argument is the margin: 1 means "for each row", 2 means "for each column". The last line asks, for each category, which store sold the most.

Rajwada leads snacks even though it ranks only third in grocery , which is a useful insight for stocking decisions. The apply() family has its own lesson, R apply, lapply and sapply.

Adding a totals row or column

cbind() binds columns and rbind() binds rows. Together they turn the sheet into a report with totals.

R
report <- cbind(oct, Total = rowSums(oct))
report <- rbind(report, All = colSums(report))
report
Output
            Grocery Dairy Snacks Total
Vijay Nagar     412   168     95   675
Palasia         356   141     88   585
Rajwada         298   102    121   521
Bhawarkuan      264    97     73   434
All            1330   508    377  2215

Quick check

In apply(m, 2, sum), what does the 2 mean?

Matrix arithmetic and multiplication

Ordinary operators work element by element, just like vectors. oct * 1.1 raises every cell by 10 percent, and oct / 100 converts thousands of rupees into lakhs. True matrix multiplication uses a different operator, %*%.

R
round(oct / rowSums(oct) * 100)

qty <- matrix(c(2, 1, 0,
                0, 3, 4),
              nrow = 2, byrow = TRUE,
              dimnames = list(c("order_1", "order_2"),
                              c("Toor Dal", "Poha", "Paneer")))
price <- c(165, 60, 90)
qty %*% price
t(qty)
Output
            Grocery Dairy Snacks
Vijay Nagar      61    25     14
Palasia          61    24     15
Rajwada          57    20     23
Bhawarkuan       61    22     17
        [,1]
order_1  390
order_2  540
         order_1 order_2
Toor Dal       2       0
Poha           1       3
Paneer         0       4

The first line gives each store's category mix as percentages of its own total, using recycling of rowSums() down each column. Vijay Nagar earns 61 percent of its sales from grocery.

qty %*% price multiplies each order's quantities by the matching prices and adds them up: order 1 is 2 × 165 + 1 × 60 = 390 rupees. That is what matrix multiplication does, and it scales to thousands of orders at once. t() transposes, swapping rows and columns.

What is an array in R?

An array is a matrix with more than two dimensions. Malwa Mart's stack of monthly sheets becomes a 4 × 3 × 2 array: 4 stores, 3 categories, 2 months.

R array as stacked matrices: stores by categories by months, with slices taken by month and by store

A three-dimensional array is a stack of matrices. The third index chooses the sheet.

R
nov <- matrix(c(430, 349, 310, 281,
                175, 150,  99, 104,
                102,  91, 130,  70), nrow = 4)

sales <- array(c(oct, nov), dim = c(4, 3, 2),
               dimnames = list(rownames(oct), colnames(oct), c("Oct", "Nov")))

dim(sales)
sales[, , "Nov"]
sales["Rajwada", "Snacks", ]
apply(sales, 3, sum)
apply(sales, c(1, 3), sum)
Output
[1] 4 3 2
            Grocery Dairy Snacks
Vijay Nagar     430   175    102
Palasia         349   150     91
Rajwada         310    99    130
Bhawarkuan      281   104     70
Oct Nov 
121 130 
 Oct  Nov 
2215 2291 
            Oct Nov
Vijay Nagar 675 707
Palasia     585 590
Rajwada     521 539
Bhawarkuan  434 455

The pattern [row, column, sheet] extends naturally. apply(sales, 3, sum) totals each month, and apply(sales, c(1, 3), sum) totals each store in each month, giving back a matrix. Total sales rose from 2,215 to 2,291 thousand rupees.

Matrix vs data frame: which should you use?

Both look like tables, so beginners often wonder when to use which. The deciding question is whether every value has the same type.

Matrix Data frame
Value types One type for all cells Each column can differ
Typical content Numbers only: sales grids, distances, correlations Real datasets with text, dates and numbers
Maths Fast, includes %*% Column by column
Typical source Built in code or from functions like cor() Read from CSV, Excel or SQL

Most data you import will become a data frame, covered next in R data frames. Matrices appear when you need fast numeric work, such as a correlation table in descriptive statistics in R.

If you use Python too, NumPy's 2-D arrays are the equivalent. This runs in the browser:

Python
import numpy as np

oct = np.array([[412, 168, 95],
                [356, 141, 88],
                [298, 102, 121],
                [264, 97, 73]])
print("Row totals:", oct.sum(axis=1))
print("Column totals:", oct.sum(axis=0))
print("Rajwada snacks:", oct[2, 2])
print(np.array([[2, 1, 0], [0, 3, 4]]) @ np.array([165, 60, 90]))

NumPy fills row by row and counts from 0, so oct[2, 2] is the third row and third column.

Common mistakes with R matrices

  • Forgetting column-wise filling. Typing values row by row without byrow = TRUE scrambles the table.
  • Mixing types. Adding a text column with cbind() turns every number into text. Use a data frame instead.
  • Using * for matrix multiplication. * multiplies cell by cell; %*% does matrix multiplication.
  • Losing the shape. m[1, ] returns a vector. Add drop = FALSE if later code needs a matrix.
  • Non-conforming dimensions. %*% needs the left matrix's column count to equal the right side's length or row count.
  • Mixing up apply margins. 1 is rows and 2 is columns. Check one result by hand the first time.

To lock in the indexing rules, solve matrix and array questions on Debugshala Test. Learners who want guided projects on grids like this can join the Indore data analytics batches run by Debugshala.

Key takeaways

  • A matrix is a two-dimensional, single-type structure; an array adds more dimensions.
  • matrix() fills by column unless byrow = TRUE.
  • Index with [row, column], leaving a side blank for "all", and use drop = FALSE to keep the shape.
  • rowSums(), colSums() and apply() summarise rows or columns quickly.
  • * is element-wise; %*% is matrix multiplication; t() transposes.
  • Use a data frame instead when columns need different types.
Take the free R Programming Basics quiz10 quick questions with explanations. No sign-up needed, and you can come back to this lesson after.

FAQ

What is the difference between a matrix and an array in R?

A matrix has exactly two dimensions, rows and columns. An array can have any number of dimensions, so a matrix is simply a two-dimensional array. Both hold one data type only. You create arrays with array(values, dim = c(...)) and index them with one position per dimension.

How do you create a matrix by row in R?

Add byrow = TRUE to matrix(), as in matrix(1:6, nrow = 2, byrow = TRUE). R then fills the first row left to right before moving to the second. Without it, R fills the first column top to bottom first, which is the default.

How do I add row and column names to a matrix in R?

Pass dimnames = list(row_names, col_names) when calling matrix(), or set them afterwards with rownames(m) <- c(...) and colnames(m) <- c(...). Names make indexing such as m["Palasia", "Dairy"] possible and keep labels attached in printed results and summaries.

What does %*% mean in R?

%*% is R's matrix multiplication operator. It multiplies rows of the left matrix by columns of the right one and sums the products, so a quantities matrix times a price vector gives each order's bill total. The ordinary * operator multiplies matching cells instead.

Can I learn R matrices as part of a data analytics course in Indore?

Yes. Debugshala teaches R and Python for analytics at its Old Palasia campus in Indore, including matrices, data frames and summary functions. Classes are in English and Hindi, there is a free demo class, and the programme accepts fresh graduates and non-IT learners.

From the team behind this site

Go further with the Data Analytics Course at Debugshala

These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.

  • Offline classes at Old Palasia, Indore
  • Free demo class before you pay
  • Non-IT, fresher and year-gap friendly
  • Placement assistance

700+ students placed · 200+ hiring partners · 4.9★ Google rating

R Lists: Create, Access and Modify with $, [[ ]] and [ ]R Data Frames: Create, Filter, Sort and Summarise Tables