Find unique elements in a matrix other than 0 - r

I have a matrix of the following form
b < -matrix(c(1, 0.0000000, 0.0000000, 0.0000000,
0, 0.1266234, 0.1590909, 0.7142857,
0, 0.1266234, 0.1590909, 0.7142857,
0, 0.1266234, 0.1590909, 0.7142857),
nrow = 4, ncol = 4, byrow = TRUE)
I want to get all the unique element in each column of b other than 0. And it should be returned as a vector of the following form:-
qq <- c(1, 0.1266234, 0.1590909, 0.7142857)
Thanks in advance!!

select items that are non-zero and find unique ones:
qq <- unique(b[b != 0])
qq
[1] 1.0000000 0.1266234 0.1590909 0.7142857

uniqueValues <- apply(b, 2, function(x) setdiff(unique(x), 0))
Keep in mind, that calculating unique values on numeric vectors has a bias due to accuracy. E.g. 0.99999 and 0.99998 are treated as different elements.

Related

R: Randomly switch signs of the off-diagonals in a matrix

Assume I generate the following matrix
Sigma <- diag(x = 1, 100, 100)
Sigma[Sigma == 0] <- 0.25
so having "1" on the diagonals and "0.25" on the off-diagonals. How can I randomly change some of the signs on the off diagonals to have -0.25 and 0.25 ?
Of course, one can loop over the elements but I think that is not an elegant solution there
One way would be to generate 1 and -1 randomly for length of the matrix, multiply it by the matrix and turn the diagonal to 1.
Sigma <- Sigma * sample(c(1, -1), length(Sigma), replace = TRUE)
diag(Sigma) <- 1
Sigma

R solver optimization

I am new to R solver and I want to have a simple example in R for the below problem:
I have four columns which I calculate the individual sums as the illustrated sample example below:
The problem I want to solve in R:
Find the optimal lines that satisfies, simultaneously, the below statements:
For the first two columns (a, b) the individual summations to be more close to 0
The sums of (c, d) to be more close to 5
I do not have restrictions of which package solver to use. It could be helpful to have an example of R code for this!
EDIT
For the same solution I would like to apply some rules:
I want the sum(c) > sum(d) AND sum(d) < (static number, like 5)
Also, if I want the sums to fall into a range of numbers and not just static numbers, how the solution could it be written?
Using M defined reproducibly in the Note at the end we find the b which minimizes the following objective where b is a 0/1 vector:
sum((b %*% M - c(0, 0, 5, 5))^2)
1) CVXR Using the CVXR package we get a solution c(1, 0, 0, 1, 1) which means choose rows 1, 4 and 5.
library(CVXR)
n <- nrow(M)
b <- Variable(n, boolean = TRUE)
pred <- t(b) %*% M
y <- c(0, 0, 5, 5)
objective <- Minimize(sum((t(y) - pred)^2))
problem <- Problem(objective)
soln <- solve(problem)
bval <- soln$getValue(b)
zapsmall(c(bval))
## [1] 1 0 0 1 1
2) Brute Force Alternately since there are only 5 rows there are only 2^5 possible solutions so we can try them all and pick the one which minimizes the objective. First we compute a matrix solns with 2^5 columns such that each column is one possible solution. Then we compute the objective function for each column and take the one which minimizes it.
n <- nrow(M)
inverse.which <- function(ix, n) replace(integer(n), ix, 1)
L <- lapply(0:n, function(i) apply(combn(n, i), 2, inverse.which, n))
solns <- do.call(cbind, L)
pred <- t(t(solns) %*% M)
obj <- colSums((pred - c(0, 0, 5, 5))^2)
solns[, which.min(obj)]
## [1] 1 0 0 1 1
Note
M <- matrix(c(.38, -.25, .78, .83, -.65,
.24, -.35, .44, -.88, .15,
3, 5, 13, -15, 18,
18, -7, 23, -19, 7), 5)

How to make a generalized function update the value of a vector?

I have been trying to write a generalized function that multiplies each value in each row of a matrix by the corresponding value of a vector in terms of their position (i.e. matrix[1,1]*vector[1], matrix[1,2]*vector[2], etc) and then sum them together. It is important to note that the lengths of the vector and the rows of the matrix are always the same, which means that in each row the first value of the vector is multiplied with the first value of the matrix row. Also important to note, I think, is that the rows and columns of the matrix are of equal length. The end sum for each row should be assigned to different existing vector, the length of which is equal to the number of rows.
This is the matrix and vector:
a <- c(4, -9, 2, -1)
b <- c(-1, 3, -8, 2)
c <- c(5, 2, 6, 3)
d <- c(7, 9, -2, 5)
matrix <- cbind(a,b,c,d)
a b c d
[1,] 4 -1 5 7
[2,] -9 3 2 9
[3,] 2 -8 6 -2
[4,] -1 2 3 5
vector <- c(1, 2, 3, 4)
These are the basic functions that I have to generalize for the rows and columns of matrix and a vector of lenghts "n":
f.1 <- function() {
(matrix[1,1]*vector[1]
+ matrix[1,2]*vector[2]
+ matrix[1,3]*vector[3]
+ matrix[1,4]*vector[4])
}
f.2 <- function() {
(matrix[2,1]*vector[1]
+ matrix[2,2]*vector[2]
+ matrix[2,3]*vector[3]
+ matrix[2,4]*vector[4])
}
and so on...
This is the function I have written:
ncells = 4
f = function(x) {
i = x
result = 0
for(j in 1:ncells) {
result = result + vector[j] * matrix[i][j]
}
return(result)
}
Calling the function:
result.cell = function() {
for(i in 1:ncells) {
new.vector[i] = f(i)
}
}
The vector to which this result should be assigned (i.e. new.vector) has been defined beforehand:
new.vector <- c()
I expected that the end sum for each row will be assigned to the vector in a corresponding manner (e.g. if the sums for all rows were 1, 2, 3, 4, etc. then new.vector(1, 2, 3, 4, etc) but it did not happen.
(Edit) When I do this with the basic functions, the assignment works:
new.vector[1] <- f.1()
new.vector[2] <- f.2()
This does not however work with the generalized function:
new.vector[1:ncells] <- result cell[1:ncells]
(End Edit)
I have also tried setting the length for the the new.vector to be equal to ncells but I don't think it did any good:
length(new.vector) = ncells
My question is how can I make the new vector take the resulting sums of the multiplied elements of a row of a matrix by the corresponding value of a vector.
I hope I have been clear and thanks in advance!
There is no need for a loop here, we can use R's power of matrix multiplication and then sum the rows with rowSums. Note that m and v are used as names for matrix and vector to avoid conflict with those function names.
nr <- nrow(m)
rowSums(m * matrix(rep(v, nr), nr, byrow = TRUE))
# [1] 45 39 -4 32
However, if the vector v is always going to be the column number, we can simply use the col function as our multiplier.
rowSums(m * col(m))
# [1] 45 39 -4 32
Data:
a <- c(4, -9, 2, -1)
b <- c(-1, 3, -8, 2)
c <- c(5, 2, 6, 3)
d <- c(7, 9, -2, 5)
m <- cbind(a, b, c, d)
v <- 1:4

Linear programming in R using lpsolve

I'm trying to solve a linear programming problem in R using lpsolve package.
Here is the problem:
Here is the sample in R for reproducible example:
library("lpSolve")
a <- matrix(c(1,2,5,
1/2,1,3,
1/5,1/3,1),nrow=3,byrow=T)
#
f.obj <- c(1,0,0,0)
f.con <- matrix (c(
1,1,-a[1,2],0, #Contraint 1 for a12
1,-1,a[1,2],0, #Contraint 2 for a12
1,1,0,-a[1,3], #Contraint 1 for a13
1,-1,0,a[1,3], #Contraint 2 for a13
1,0,1,-a[2,3], #Contraint 1 for a23
1,0,-1,a[2,3], #Contraint 2 for a23
0,1,1,1, #Contraint 3
0,1,0,0, #Constraint 4
0,0,1,0, #Constraint 4
0,0,0,1 #Constraint 4
), nrow=10, byrow=TRUE)
f.dir <- c(rep("<=",6), "=",rep(">",3))
f.rhs <- c(rep(1,6),1,rep(0,3))
g <- lp ("max", f.obj, f.con, f.dir, f.rhs)
g$solution
I'm able to solve this manually for a small problem, what if I had a 7 X 7 or a n x n matrix a. How would I specify the constraint 1 and 2, especially I'm struggling to define the constraint as it relates to a[i,j]?
a = matrix(
c(1,4,9,6,6,5,5,
1/4,1,7,5,5,3,4,
1/9,1/7,1,1/5,1/5,1/7,1/5,
1/6,1/5,5,1,1,1/3,1/3,
1/6,1/5,5,1,1,1/3,1/3,
1/5,1/3,7,3,3,1,2,
1/5,1/4,5,3,3,1/2,1
),nrow = 7,byrow =T)
the solution to the above matrix is 0.986 0.501 0.160 0.043 0.060 0.060 0.1 0.075 Any help would be greatly appreciated.
Have updated to incorporate revised constraint 4 and have made some minor code improvements.
Assuming the constraint matrix in the question is correct, this uses combn to iterate over all i < j setting the appropriate elements. Note that x[1] is the value of i and x[2] is the value of j in f. make_cons returns the constraint matrix in the same order as shown in the question but the rbind line in make_cons could be simplified to rbind(cons1, cons2, cons3, cons4) if it were OK to use such order.
make_cons <- function(a) {
n <- nrow(a)
f <- function(x) replace(numeric(n), x, c(1, -a[x[1], x[2]]))
cons1 <- cbind(1, t(combn(1:n, 2, f)))
cons2 <- cbind(1, -cons1[, -1])
cons3 <- c(0, rep(1, n))
cons4 <- cbind(0, diag(n))
rbind(t(matrix(rbind(t(cons1), t(cons2)), ncol(cons1))), cons3, cons4)
}
# test
# a and f.con from question
a <- matrix(c(1, 0.5, 0.2, 2, 1, 0.333333333333333, 5, 3, 1), 3)
f.con <- matrix(c(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, -1, 1, -1, 0, 0,
1, 1, 0, 0, -2, 2, 0, 0, 1, -1, 1, 0, 1, 0, 0, 0, -5, 5, -3,
3, 1, 0, 0, 1), 10)
all.equal(f.con, make_cons(a), check.attributes = FALSE)
## [1] TRUE
here is one possibility which uses for loops.
As I mentioned in the commenst, I think that you got condition (4) wrong. Here is my suggestion.
My idea is to first set up a matrix for constraints (4), then for constraint (3)
and then add constraints (2) and (1) in a loop. Note that, in the beginning, I do not consider the column corresponding to \mu. I will add this column in the end.
n<- nrow(a)
f.cons<- diag(n)
f.cons<- rbind(f.cons, rep(1,n))
This sets up a matrix corresponding to constraints (4) (first n rows) and constraint (3). Now I add rows to this matrix, using loops and the command rbind.
for(i in 1:(n-1)){
for(j in (i+1): n){
x<- rep(0, n)
x[i]<- 1 #x corresponds to (1)
x[j]<- -a[i,j]
y<- -x #y corresponds to (2)
f.cons<- rbind(f.cons, rbind(x, y))
}
}
So far, I have ignored the first column, which corresponds to \mu.
I add it with these two simple lines:
f.cons<- cbind(rep(1, nrow(f.cons)), f.cons)
f.cons[1:(n+1), 1]=0
Note that in my matrix f.cond the first n+1 lines correspond to constraints (3) and (4)!

R: selecting items matching criteria from a vector

I have a numeric vector in R, which consists of both negative and positive numbers. I want to separate the numbers in the list based on sign (ignoring zero for now), into two seperate lists:
a new vector containing only the negative numbers
another vector containing only the positive numbers
The documentation shows how to do this for selecting rows/columns/cells in a dataframe - but this dosen't work with vectors AFAICT.
How can it be done (without a for loop)?
It is done very easily (added check for NaN):
d <- c(1, -1, 3, -2, 0, NaN)
positives <- d[d>0 & !is.nan(d)]
negatives <- d[d<0 & !is.nan(d)]
If you want exclude both NA and NaN, is.na() returns true for both:
d <- c(1, -1, 3, -2, 0, NaN, NA)
positives <- d[d>0 & !is.na(d)]
negatives <- d[d<0 & !is.na(d)]
It can be done by using "square brackets".
A new vector is created which contains those values which are greater than zero. Since a comparison operator is used, it will denote values in Boolean. Hence square brackets are used to get the exact numeric value.
d_vector<-(1,2,3,-1,-2,-3)
new_vector<-d_vector>0
pos_vector<-d_vector[new_vector]
new1_vector<-d_vector<0
neg_vector<-d_vector[new1_vector]
purrrpackage includes some useful functions for filtering vectors:
library(purrr)
test_vector <- c(-5, 7, 0, 5, -8, 12, 1, 2, 3, -1, -2, -3, NA, Inf, -Inf, NaN)
positive_vector <- keep(test_vector, function(x) x > 0)
positive_vector
# [1] 7 5 12 1 2 3 Inf
negative_vector <- keep(test_vector, function(x) x < 0)
negative_vector
# [1] -5 -8 -1 -2 -3 -Inf
You can use also discard function

Resources