Reputation: 395
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
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
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
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