Milaa
Milaa

Reputation: 419

I want to apply two functions one function on the block diagonal and the second function on the off-diagonal elements in the data frame

df<- data.frame(a=c(1:10), b=c(21:30),c=c(1:10), d=c(14:23),e=c(11:20),f=c(-6:-15),g=c(11:20),h=c(-14:-23),i=c(4:13),j=c(1:10))

In this data frame, I have three block-diagonal matrices which are as shown in the image below enter image description here

I want to apply two functions, one is the sine function for block diagonal and the second is cosine function for the other elements and generates the same structure of the data frame.

sin(df[1:2,1:2])
sin(df[3:5,3:5])
sin(df[6:10,6:10])
cos(the rest of the elements)

Upvotes: 8

Views: 133

Answers (2)

G. Grothendieck
G. Grothendieck

Reputation: 269854

1) outer/arithmetic Create a logical block diagonal matrix indicating whether the current cell is on the block diagonal or not and then use that to take a convex combination of the sin and cos values giving a data.frame as follows:

v <- rep(1:3, c(2, 3, 5))
ind <- outer(v, v, `==`)
ind * sin(df) + (!ind) * cos(df)

2) ifelse Alternately, this gives a matrix result (or use as.matrix on the above). ind is from above.

m <- as.matrix(df)
ifelse(ind, sin(m), cos(m))

3) Matrix::bdiag Another approach is to use bdiag in the Matrix package (which comes with R -- no need to install it).

library(Matrix)

ones <- function(n) matrix(1, n, n)
ind <- bdiag(ones(2), ones(3), ones(5)) == 1

Now proceed as in the last line of (1) or as in (2).

Upvotes: 7

Jan
Jan

Reputation: 5254

If it's okay for you that the result is stored in a new data frame you could change the order of your instructions and do it like that:

ndf <- cos(df)
ndf[1:2,1:2] <- sin(df[1:2,1:2])
ndf[3:5,3:5] <- sin(df[3:5,3:5])
ndf[6:10,6:10] <- sin(df[6:10,6:10])

Upvotes: 2

Related Questions