Roger
Roger

Reputation: 395

Create rows and columns for a matrix

I have a matrix. The rows are owners (a, b,c...); the columns are companies (c1, c2,...). A sample data is below:

m1 <- matrix(0.1, nrow = 3, ncol = 3, dimnames = list(c('a','b','c'), c('c1','c2','c3')))

m1 shows the owners a, b, c, each own companies c1, c2, c3 10%. I want to create a few hypothetical owners, so that each hypothetical owner own the remaining 70% of one company but do not own other companies. The desired output is as below. In the desired output, d, e, f are hypothetical owners, each owning a company 70%.

    c1  c2  c3
a   0.1 0.1 0.1
b   0.1 0.1 0.1
c   0.1 0.1 0.1
d   0.7 NA  NA
e   NA  0.7 NA
f   NA  NA  0.7

I can do it mannualy such as below, but I wonder how to do it pragmatically. Note that there are cases that the owners or companies are more than three and the ownership is different than 0.1. The number of new owners will be the same as the number of companies, because each new owners only own one company.

d <- c(0.7, NA, NA)
m2 <- rbind(m1, d)

Upvotes: 1

Views: 57

Answers (3)

acylam
acylam

Reputation: 18661

We can do set create a matrix with NA elements, and fill the diagonal with the percentage. As @Jilber Urbina noted, we can declare the row.names within matrix:

hypo_companies <- c("d", "e", "f")
percentage <- 0.7

hypo_len <- length(hypo_companies)
hypo_mat <- matrix(NA, hypo_len, hypo_len, dimnames = list(hypo_companies))
diag(hypo_mat) <- rep(percentage, hypo_len)
rbind(m1, hypo_mat)

Output:

   c1  c2  c3
a 0.1 0.1 0.1
b 0.1 0.1 0.1
c 0.1 0.1 0.1
d 0.7  NA  NA
e  NA 0.7  NA
f  NA  NA 0.7

Upvotes: 0

g_t_m
g_t_m

Reputation: 714

This should do the job.

Firstly, create a diagonal matrix m2, with each element of the diagonal being the difference between 1 and the sum of the matrix m1

m1 <- matrix(0.1, nrow = 3, ncol = 3, dimnames = list(c('a','b','c'), c('c1','c2','c3')))

m2 <- diag(1 - colSums(m1))

m2
#>      [,1] [,2] [,3]
#> [1,]  0.7  0.0  0.0
#> [2,]  0.0  0.7  0.0
#> [3,]  0.0  0.0  0.7

Then we need to add the row names to m2. We might want to allocate the first 3 letters of the alphabet not used for m1. The advantage of this is that you don't need to specify the row names of the new matrix - they will be allocated based on what has not already been used.

rownames(m2) <- letters[!letters %in% rownames(m1)][1:nrow(m2)]

rbind(m1, m2)
#>    c1  c2  c3
#> a 0.1 0.1 0.1
#> b 0.1 0.1 0.1
#> c 0.1 0.1 0.1
#> d 0.7 0.0 0.0
#> e 0.0 0.7 0.0
#> f 0.0 0.0 0.7

As you can see, this code still works with more rows/columns and different numbers in m1:

m1 <- matrix(0.11, nrow = 3, ncol = 4, dimnames = list(c('a','b','c'), c('c1','c2','c3','c4')))

m1
#>     c1   c2   c3   c4
#> a 0.11 0.11 0.11 0.11
#> b 0.11 0.11 0.11 0.11
#> c 0.11 0.11 0.11 0.11

m2 <- diag(1 - colSums(m1))

m2
#>      [,1] [,2] [,3] [,4]
#> [1,] 0.67 0.00 0.00 0.00
#> [2,] 0.00 0.67 0.00 0.00
#> [3,] 0.00 0.00 0.67 0.00
#> [4,] 0.00 0.00 0.00 0.67

rownames(m2) <- letters[!letters %in% rownames(m1)][1:nrow(m2)]

rbind(m1, m2)
#>     c1   c2   c3   c4
#> a 0.11 0.11 0.11 0.11
#> b 0.11 0.11 0.11 0.11
#> c 0.11 0.11 0.11 0.11
#> d 0.67 0.00 0.00 0.00
#> e 0.00 0.67 0.00 0.00
#> f 0.00 0.00 0.67 0.00
#> g 0.00 0.00 0.00 0.67

Created on 2019-02-20 by the reprex package (v0.2.1)

Upvotes: 2

d.b
d.b

Reputation: 32548

m2 = rbind(m1, do.call(rbind, lapply(1:NCOL(m1), function(i) replace(rep(NA, NCOL(m1)), i, 0.7))))
row.names(m2) = c(row.names(m1), c("d", "e", "f"))
m2
#   c1  c2  c3
#a 0.1 0.1 0.1
#b 0.1 0.1 0.1
#c 0.1 0.1 0.1
#d 0.7  NA  NA
#e  NA 0.7  NA
#f  NA  NA 0.7

Upvotes: 0

Related Questions