Create a Random Matrix With Constant Row Sums in R

In this article, we will see how to create a matrix with randomly chosen non-negative values in each row such that the sum is constant for all rows.

For simplicity, we will take the case where all rows sum to 1. The row vectors can be multiplied by any number to get that number as the row sum.

How To Sum Values In Rows & Col...
How To Sum Values In Rows & Columns - MS Excel

Create a Random Matrix With Constant Row Sums in R

Assume we want each row to have 4 elements. This can be any positive integer greater than 1.

We will start with the range 0 to 100, representing the percentiles. We will divide this range into 4 parts using 3 randomly chosen cut points.

To do this, we randomly chose 3 points in the said range. For simplicity, we will choose 3 separate numbers.

We will sort the chosen cut points in descending order. These are the percentiles at which we will cut the range.

We will divide the cut points by 100. This gives us the cut points as decimals from 0 to 1.

We get our four sections of 1 as follows:

  1. We get the first element by subtracting the first (largest) cut point from 1.
  2. We get the second element by subtracting the second cut point from the first cut point.
  3. We get the third element by subtracting the third (smallest) cut point from the second cut point.
  4. We get the fourth element by subtracting 0 from the third cut point.

These numbers constitute one row; they add up to 1. We must repeat this process as many times as the number of rows needed.

Code for the Matrix

We will now look at the code to get a random matrix with 5 rows and 4 columns where each row sum is 1.

Example Code:

# The final matrix.
# It begins as an empty matrix. It has 4 columns in our example.
Mx = matrix(byrow= TRUE, ncol = 4, nrow = 0)

# The number of rows. 5 rows in our example.
# We will repeat the code as many times as the number of rows we need.
for(RowNum in 1:5) {
  # Cut points. With 3 cuts, we will get 4 elements.
  # Randomly choose 3 different integers from the sequence 0 to 100.
  cuts = sample(0:100, 3, replace = FALSE)
  # Sort the cut points in descending order.
  cuts.sort = sort(cuts, decreasing = TRUE)

  # Convert the sorted cut points to decimals from 0 to 1.
  cuts.dec = cuts.sort/100

  # An empty vector to hold the current row that we will build.
  Elements = c()
  # The starting point for each cut.
  # The first cut starts at 1. Then resets this to its value.
  ElementStart = 1

  # Create each element.
  for(Cut in cuts.dec){
    Elements = c(Elements, (ElementStart-Cut))
    ElementStart = Cut
  }

  # Append the last element to get the full row.
  # This is from the last (smallest) cut value to 0.
  # (This vector can be multiplied by any number to get that number as the row sum.)
  Elements = c(Elements, cuts.dec[3])

  # Add the row to the matrix.
  Mx = rbind(Mx, Elements)
  rownames(Mx) = NULL
}

# Print the matrix.
print(Mx)

# Check that all 5 rows sum to 1.
table(apply(Mx, 1, sum))

Output:

> # Print the matrix.
> print(Mx)
     [,1] [,2] [,3] [,4]
[1,] 0.38 0.36 0.16 0.10
[2,] 0.41 0.15 0.03 0.41
[3,] 0.08 0.50 0.35 0.07
[4,] 0.17 0.15 0.06 0.62
[5,] 0.07 0.09 0.23 0.61
>
> # Check that all 5 rows sum to 1.
> table(apply(Mx, 1, sum))

1
5

Related Article - R Matrix

  • Use the %*% Operator in R
  • Matrix Multiplication in R
  • Create Empty Matrix in R