I have a dataframe "df", and I would like to transform it into an array BY ROW, for example:
> df
x y
1 1 21
2 2 22
3 3 23
4 4 24
5 5 25
6 6 26
7 7 27
8 8 28
#Into this array:
> array.df
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 21 2 22
[2,] 3 23 4 24
, , 2
[,1] [,2] [,3] [,4]
[1,] 5 25 6 26
[2,] 7 27 8 28
Can anyone help me with the code? Thanks.
Quite an ugly solution, but it gets the job done. Maybe someone else has a better way of doing this. In the meantime, it should do.
install.packages("reshape2")
library("reshape2")
df
x y
1 1 21
2 2 22
3 3 23
4 4 24
5 5 25
6 6 26
7 7 27
8 8 28
myarray <- array(cbind(matrix(melt(t(df))[1:8,3],byrow = T, ncol = 4),matrix(melt(t(df))[9:16,3],byrow = T, ncol = 4)), c(2,4,2))
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 21 2 22
[2,] 3 23 4 24
, , 2
[,1] [,2] [,3] [,4]
[1,] 5 25 6 26
[2,] 7 27 8 28
I will try and explain:
The idea is to transpose the data frame with t() and then melt it using the melt() function from the reshape2 package. Upon reshaping the data, you want to grab the 3rd column and then create two matrices from it by row. Then, you will need to cbind those matrices into one matrix. And finally, use that matrix to get the array you want with dimension c(2,4,2).
I hope this makes sense.
Here is another not so elegant solution:
df <- data.frame(x=1:8, y=21:28)
vec <- as.vector(t(df)) # transpose df and then turn into a single vector
arr <- array(vec, dim=c(4,2,2)) # create array with first 2 dimensions transposed
lis <- lapply(1:2, function(x) { t(arr[,,x]) }) # transpose the first 2 dimensions
array(do.call(cbind, lis), c(2,4,2)) # convert back to array format
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 21 2 22
[2,] 3 23 4 24
, , 2
[,1] [,2] [,3] [,4]
[1,] 5 25 6 26
[2,] 7 27 8 28
Using only the base package:
df <- data.frame(x = 1:8, y = 21:28)
array.df <- array(
data = as.vector(t(df)),
dim = c(4,2,2))
array.df <- aperm(a = array.df, perm = c(2,1,3))
print(array.df)
Just thought of a simpler base R answer for this using some array manipulation:
apply(array(t(df), dim=c(4,2,2)), c(1,3), t)
#, , 1
#
# [,1] [,2] [,3] [,4]
#[1,] 1 21 2 22
#[2,] 3 23 4 24
#
#, , 2
#
# [,1] [,2] [,3] [,4]
#[1,] 5 25 6 26
#[2,] 7 27 8 28
Use some matrix trickery to fill by row and then reshape again. sapply's simplify="array" ensures the array output:
sapply(
split(df, rep(1:2,each=nrow(df)/2)),
function(x) matrix(c(matrix(unlist(x),byrow=TRUE,ncol=2)),nrow=2),
simplify="array"
)
#, , 1
#
# [,1] [,2] [,3] [,4]
#[1,] 1 21 2 22
#[2,] 3 23 4 24
#
#, , 2
#
# [,1] [,2] [,3] [,4]
#[1,] 5 25 6 26
#[2,] 7 27 8 28
Related
Good afternoon!
Assume we have a vector and a matrix :
v = c(2,3,4)
[1] 2 3 4
m=matrix(1:9,ncol=3)
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
I'm searching an efficient way ( or built-in function ) to get three matrices m1 , m2 , m3 such that :
m1=v[1]*m
m2=v[2]*m
m3=v[3]*m
We could obtain this using a 3d-array :
my_fct<-function(m,v){
f=array(data=rep(NA,nrow(m)*ncol(m)*length(v)),dim = c(nrow(m),ncol(m),length(v)))
for (j in c(1:length(v))){
f[,,j]=v[j]*m
}
return(f)
}
my_fct(m,v)
, , 1
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
, , 2
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
, , 3
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36
I hope my request is clear!
Thank you a lot for help !
As 'v' is a vector and we want each element to be multiplied by the same matrix 'm', an option is to loop over the element of 'v' and do the multiplication
lapply(v, `*`, m)
-output
[[1]]
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
[[2]]
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
[[3]]
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36
Another base R option
> Map(`*`, list(m), v)
[[1]]
[,1] [,2] [,3]
[1,] 2 8 14
[2,] 4 10 16
[3,] 6 12 18
[[2]]
[,1] [,2] [,3]
[1,] 3 12 21
[2,] 6 15 24
[3,] 9 18 27
[[3]]
[,1] [,2] [,3]
[1,] 4 16 28
[2,] 8 20 32
[3,] 12 24 36
I need to create a function, that will rearrange any square matrix based on the values in the matrix.
So if I have matrix like this:
M <- matrix(1:16, ncol = 4)
M
#> [,1] [,2] [,3] [,4]
#> [1,] 1 5 9 13
#> [2,] 2 6 10 14
#> [3,] 3 7 11 15
#> [4,] 4 8 12 16
After rearrangement it needs to look like this:
[,1] [,2] [,3] [,4]
[1,] 1 3 6 10
[2,] 2 5 9 13
[3,] 4 8 12 15
[4,] 7 11 14 16
So it is sorted from lowest (left upper corner) to highest (right lower corner), but the numbers are sorted on diagonal (is that the right word?) not in rows or columns.
I know how to to this "manually", but I can't figure out any rules that this rearrangement operates by.
1) row(m) + col(m) is constant along reverse diagonals so:
M <- replace(m, order(row(m) + col(m)), m)
gving:
> M
[,1] [,2] [,3] [,4]
[1,] 1 3 6 10
[2,] 2 5 9 13
[3,] 4 8 12 15
[4,] 7 11 14 16
It is not clear whether sorted on the diagonal means just that they are unravelled from the storage order onto the reverse diagonals or that they are actually sorted after that within each reverse diagonal. In the example in the question the two interpretations give the same answer; however, if you did wish to sort the result within reverse diagonal afterwards using different data then apply this:
ave(M, row(M) + col(M), FUN = sort)
2) A longer version:
M2 <- matrix(m[order(unlist(tapply(seq_along(m), row(m) + col(m), c)))], nrow(m))
Here's a function columns_to_diagonals in base R that ought to do what you're after. It uses split and unsplit with the appropriate factors.
columns_to_diagonals <- function(M) {
n <- ncol(M)
f <- matrix(rep(1:(2*n-1), c(1:n, (n-1):1)), ncol = n)
m <- split(M, f)
d <- row(M) + col(M)
matrix(unsplit(m, d), ncol = n)
}
First, we may test this on your original case:
M <- matrix(1:16, ncol = 4)
columns_to_diagonals(M)
#> [,1] [,2] [,3] [,4]
#> [1,] 1 3 6 10
#> [2,] 2 5 9 13
#> [3,] 4 8 12 15
#> [4,] 7 11 14 16
And then a larger, randomly permutated matrix, to check that this looks fine as well:
M <- matrix(sample(1:25), ncol = 5)
M
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4 15 12 10 21
#> [2,] 19 7 5 23 6
#> [3,] 9 17 2 8 1
#> [4,] 3 11 16 25 14
#> [5,] 22 18 20 13 24
columns_to_diagonals(M)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 4 9 15 18 20
#> [2,] 19 22 11 16 25
#> [3,] 3 17 2 8 6
#> [4,] 7 5 23 21 14
#> [5,] 12 10 13 1 24
Created on 2019-12-15 by the reprex package (v0.2.1)
I know that I can make a simple matrix (for example 1->20 numbers, 4,5 rows) using this:
x<- array(1:20, dim=c(4,5)); x
But I have no idea how to make a matrix similar to the one on the picture...
matrix(rep(1:4,4)^rep(0:3,each=4), byrow=TRUE, nrow=4)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 1 2 3 4
[3,] 1 4 9 16
[4,] 1 8 27 64
You can create a function if you want to be able to generate an analogous square matrix with an arbitrary number of rows.
power_mat = function(n) {
matrix(rep(1:n,n)^rep(1:n - 1, each=n), byrow=TRUE, nrow=n)
}
power_mat(6)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 2 3 4 5 6
[3,] 1 4 9 16 25 36
[4,] 1 8 27 64 125 216
[5,] 1 16 81 256 625 1296
[6,] 1 32 243 1024 3125 7776
Solution
t(sapply(0:3, function(x) (1:4)^x))
Result
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 1 2 3 4
[3,] 1 4 9 16
[4,] 1 8 27 64
(You can easily verify this matches your matrix)
Explanation
Each row of the matrix is the vector c(1, 2, 3, 4) raised to the power of the row index (in a 0-based indexing system). So, we just use sapply() on the vector of powers to raise 1:4 to each power which will return a matrix. Because sapply() would return the results as column vectors, we use t() to transpose the result.
n <- 4
m <- 4
t(sapply( 0:(n-1), FUN = function (i){ return(c(1:m)**i) }))
where n is the number of rows, and m is the number of columns.
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 1 2 3 4
[3,] 1 4 9 16
[4,] 1 8 27 64
n = 4
m = rbind(rep(1, n), t(replicate(n-1, 1:n)))
m ^ (row(m) - 1)
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 1
#[2,] 1 2 3 4
#[3,] 1 4 9 16
#[4,] 1 8 27 64
I have been thinking about a problem I have but I don't know how to express the problem to even search for it. I'd be very thankful if you could explain it to me.
So, I have a data set with the following format:
10 6 4 4
10 6 4 4
7 6 4 4
I want to conduct a pairwise calculation for which I need to sum each element to the other one by one. That is 1 with 2, 1 with 3, 1 with 4, 2 with 3, 2 with 4 and 3 with 4.
I thought to do a nested a loop in R which I read about it and I started like this:
for (i in 1:r-1) { ## r the number of columns
for (j in (i+1):r) {
....
}
I am stuck at this stage, I don't know how to express in codes what I need to do. I am sorry for posting a not progressed code, some advice would be very good that how I should go about it.
Thanks a lot in advance.
Use combn to create the "pairs":
(pairs <- combn(4,2))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 2 2 3
[2,] 2 3 4 3 4 4
Then apply across the rows of your data by summing these subsets by applying across the columns of the pairs:
dat <- matrix(c(10,10,7,6,6,6,4,4,4,4,4,4),ncol=4)
t(apply(dat, 1, function(x) apply(combn(4,2),2,function(y) sum(x[y]))))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 16 14 14 10 10 8
[2,] 16 14 14 10 10 8
[3,] 13 11 11 10 10 8
You could slightly modify your loop:
d <- read.table(text='
10 6 4 4
10 6 4 4
7 6 4 4')
nc <- ncol(d)
r <- NULL
for (i in 1:nc) {
for (j in 1:nc) {
if (i < j) { # crucial condition
r <- cbind(r, d[, i] + d[, j]) # calculate new column and bind to calculated ones
}
}
}
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 16 14 14 10 10 8
[2,] 16 14 14 10 10 8
[3,] 13 11 11 10 10 8
Another application of combn but perhaps easier to understand:
apply(combn(ncol(dat),2), 2, function(x) rowSums(dat[,x]))
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 16 14 14 10 10 8
## [2,] 16 14 14 10 10 8
## [3,] 13 11 11 10 10 8
Here, the matrix dat is indexed by each column of the result of combn giving a matrix of two columns (the two columns to be summed). rowSums then does the arithmetic.
Because I really like package functional, here is a slight variation on the above:
apply(combn(ncol(dat),2), 2, Compose(Curry(`[`, dat, i=seq(nrow(dat))), rowSums))
It should be noted that a combn approach is more flexible than using nested for loops for this sort of computation. In particular, it is easily adapted to any number of columns to sum:
f <- function(dat, num=2)
{
apply(combn(ncol(dat),num), 2, function(x) rowSums(dat[,x,drop=FALSE]))
}
This will give all combinations of num columns, and sum them:
f(dat, 1)
## [,1] [,2] [,3] [,4]
## [1,] 10 6 4 4
## [2,] 10 6 4 4
## [3,] 7 6 4 4
f(dat, 2)
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 16 14 14 10 10 8
## [2,] 16 14 14 10 10 8
## [3,] 13 11 11 10 10 8
f(dat, 3)
## [,1] [,2] [,3] [,4]
## [1,] 20 20 18 14
## [2,] 20 20 18 14
## [3,] 17 17 15 14
f(dat, 4)
## [,1]
## [1,] 24
## [2,] 24
## [3,] 21
Hi everyone who loves while hates R:
Let's say you want to turn matrix M
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
to N
[,1] [,2] [,3]
[1,] 3 2 1
[2,] 6 5 4
[3,] 9 8 7
All you need to do is
N<-M[,c(3:1)]
And N's structure is still a matrix
However, when you want to turn matrix M
[,1] [,2] [,3]
[1,] 1 2 3
to N
[,1] [,2] [,3]
[1,] 3 2 1
if you do
N<-M[,c(3:1)]
R will give you
N
[1] 3 2 1
N now is a vector! Not a matrix!
My solution is
N<-M%*%diag(3)[,c(3:1)]
which needs big space to store the identity matrix however.
Any better idea?
You're looking for this:
N<-M[,c(3:1),drop = FALSE]
Read ?Extract for more information. This is also a FAQ. This behavior is one of the most common debates folks have about the way things "should" be in R. My general impression is that many people agree that drop = FALSE might be a more sensible default, but that behavior is so old that changing it would be enormously disruptive to vast swaths of existing code.
A=t(matrix(1:25,5,5))
B=matrix(0,5,5)
for(i in 1:5){
B[i,(nrow(A)+1-i)]=1
}
A
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 2 3 4 5
# [2,] 6 7 8 9 10
# [3,] 11 12 13 14 15
# [4,] 16 17 18 19 20
# [5,] 21 22 23 24 25
A%*%B
# [,1] [,2] [,3] [,4] [,5]
# [1,] 5 4 3 2 1
# [2,] 10 9 8 7 6
# [3,] 15 14 13 12 11
# [4,] 20 19 18 17 16
# [5,] 25 24 23 22 21