For loop in matrix or similar structure for solving large matrix [duplicate] - r

This question already has answers here:
R Sum every k columns in matrix
(5 answers)
Closed 4 years ago.
[Can we have a for loop or other thing for solving the following matrix?
Matrix A (given 6 x 16)
a 1 5 6 9 5 8 5 6 7 9 4 6 2 5 4 6
b 8 6 2 4 7 9 2 3 4 8 6 2 1 6 8 2
c 9 5 1 7 5 3 7 5 3 9 5 1 2 6 9 3
d 2 5 6 3 4 1 8 4 2 6 9 5 1 3 7 1
e 7 4 2 3 6 5 7 4 1 2 3 6 9 8 5 2
f 1 5 3 7 8 9 4 6 3 1 5 2 8 9 5 4
Output (6 x 4)
a 1+5+6+9 5+8+5+6 7+9+4+6 2+5+4+6
b 8+6+2+4 7+9+2+3 4+8+6+2 1+6+8+2
c 9+5+1+7 5+3+7+5 3+9+5+1 2+6+9+3
d 2+5+6+3 4+1+8+4 2+6+9+5 1+3+7+1
e 7+4+2+3 6+5+7+4 1+2+3+6 9+8+5+2
f 1+5+3+7 8+9+4+6 3+1+5+2 8+9+5+4
I have a large maxtrix of 4519 x 4519, therefore looking for a for loop.]
matb <- matrix(data = 0, nrow =6 ,ncol = 6)
for (a in 1: nrow (data)) {
for (b in 1:seq (1,5,by=2)) {
c <- b+1
matb [a,1:3] <- rbind (sum(data[a,b:c]))
}
}
I tried using above syntax, but it did not work. Therefore, looking for help on for loop or function to solve this problem.

We can use recycling to select alternating columns, then add:
# example matrix
m <- matrix(1:12, ncol = 4)
# [,1] [,2] [,3] [,4]
# [1,] 1 4 7 10
# [2,] 2 5 8 11
# [3,] 3 6 9 12
m[, c(TRUE, FALSE)] + m[, c(FALSE, TRUE)]
# [,1] [,2]
# [1,] 5 17
# [2,] 7 19
# [3,] 9 21

Related

Generating an vector with rep and seq but without the c() function [duplicate]

This question already has answers here:
R repeating sequence add 1 each repeat
(2 answers)
Closed 5 months ago.
Suppose that I am not allowed to use the c() function.
My target is to generate the vector
"1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9"
Here is my attempt:
rep(seq(1, 5, 1), 5)
# [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
rep(0:4,rep(5,5))
# [1] 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4
So basically I am sum them up. But I wonder if there is a better way to use rep and seq functions ONLY.
Like so:
1:5 + rep(0:4, each = 5)
# [1] 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9
I like the sequence option as well:
sequence(rep(5, 5), 1:5)
You could do
rep(1:5, each=5) + rep.int(0:4, 5)
# [1] 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9
Just to be precise and use seq as well:
rep(seq.int(1:5), each=5) + rep.int(0:4, 5)
(PS: You can remove the .ints, but it's slower.)
One possible way:
as.vector(sapply(1:5, `+`, 0:4))
[1] 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9
I would also propose the outer() function as well:
library(dplyr)
outer(1:5, 0:4, "+") %>%
array()
Or without magrittr %>% function in newer R versions:
outer(1:5, 0:4, "+") |>
array()
Explanation.
The first function will create an array of 1:5 by 0:4 sequencies and fill the intersections with sums of these values:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 3 4 5 6
[3,] 3 4 5 6 7
[4,] 4 5 6 7 8
[5,] 5 6 7 8 9
The second will pull the vector from the array and return the required vector:
[1] 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9

sort matrix elements based on diagonal position in R [duplicate]

This question already has answers here:
Get all diagonal vectors from matrix
(3 answers)
Closed 5 years ago.
Before I attempt writing a custom function; is there an elegant/native method to achieve this?
m<-matrix(1:9,ncol = 3)
m
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
By column:
as.vector(m)
[1] 1 2 3 4 5 6 7 8 9
By row:
as.vector(t(m))
[1] 1 4 7 2 5 8 3 6 9
By diagonal (I would like a function output):
some.function(m)
[1] 1 2 4 3 5 7 6 8 9
And the perpendicular diagonal:
some.other.function(m)
[1] 7 8 4 9 5 1 6 2 3
ind = expand.grid(1:3, 1:3)
ind[,3] = rowSums(ind)
ind = ind[order(ind[,3], ind[,2], ind[,1]),]
m[as.matrix(ind[,1:2])]
#[1] 1 2 4 3 5 7 6 8 9
m[,3:1][as.matrix(ind[,1:2])]
#[1] 7 8 4 9 5 1 6 2 3

How to replace the NA values after merge two data.frame? [duplicate]

This question already has answers here:
Replacing NAs with latest non-NA value
(21 answers)
Closed 7 years ago.
I have two data.frame as the following:
> a <- data.frame(x=c(1,2,3,4,5,6,7,8), y=c(1,3,5,7,9,11,13,15))
> a
x y
1 1 1
2 2 3
3 3 5
4 4 7
5 5 9
6 6 11
7 7 13
8 8 15
> b <- data.frame(x=c(1,5,7), z=c(2, 4, 6))
> b
x z
1 1 2
2 5 4
3 7 6
Then I use "join" for two data.frames:
> c <- join(a, b, by="x", type="left")
> c
x y z
1 1 1 2
2 2 3 NA
3 3 5 NA
4 4 7 NA
5 5 9 4
6 6 11 NA
7 7 13 6
8 8 15 NA
My requirement is to replace the NAs in the Z column by the last None-Na value before the current place. I want the result like this:
> c
x y z
1 1 1 2
2 2 3 2
3 3 5 2
4 4 7 2
5 5 9 4
6 6 11 4
7 7 13 6
8 8 15 6
This time (if your data is not too large) a loop is an elegant option:
for(i in which(is.na(c$z))){
c$z[i] = c$z[i-1]
}
gives:
> c
x y z
1 1 1 2
2 2 3 2
3 3 5 2
4 4 7 2
5 5 9 4
6 6 11 4
7 7 13 6
8 8 15 6
data:
library(plyr)
a <- data.frame(x=c(1,2,3,4,5,6,7,8), y=c(1,3,5,7,9,11,13,15))
b <- data.frame(x=c(1,5,7), z=c(2, 4, 6))
c <- join(a, b, by="x", type="left")
You might also want to check na.locf in the zoo package.

Rearranging the columns of a data frame [duplicate]

This question already has answers here:
Splitting triplicates into duplicates
(3 answers)
Closed 8 years ago.
Given a data frame, I'd like to rearrange it and return another data frame of 2 columns. The 2 columns of this data frame are made up of any 2 elements of a row in the original data frame. So we will have C(ncol,2) * nrow number of rows in the second data frame. Here's an example. Given the data frame z, I'd like to return x. How can I do this?
> z = data.frame(A = c(1,2,3), B = c(4,5,6), C = c(7,8,9))
> z
A B C
1 1 4 7
2 2 5 8
3 3 6 9
> x
A B
1 1 4
2 1 7
3 4 7
4 2 5
5 2 8
6 5 8
7 3 6
8 3 9
9 6 9
Or, you could try:
matrix(apply(z, 1, combn,2), ncol=2, byrow=TRUE)
# [,1] [,2]
#[1,] 1 4
#[2,] 1 7
#[3,] 4 7
#[4,] 2 5
#[5,] 2 8
#[6,] 5 8
#[7,] 3 6
#[8,] 3 9
#[9,] 6 9
To get data.frame as output
setNames(as.data.frame(matrix(apply(z, 1, combn,2), ncol=2, byrow=TRUE)), LETTERS[1:2])
Something like this would work
newz <- setNames(do.call(rbind.data.frame, lapply(split(z, 1:nrow(z)), function(x)
t(combn(x,2)))),
c("A","B"))
newz
# A B
# 1.1 1 4
# 1.2 1 7
# 1.3 4 7
# 2.1 2 5
# 2.2 2 8
# 2.3 5 8
# 3.1 3 6
# 3.2 3 9
# 3.3 6 9
This generates the new rows using all combinations if the columns via combn(). If you hate the default rownames, you can get rid of them with
rownames(newz)<-NULL
newz
# A B
# 1 1 4
# 2 1 7
# 3 4 7
# 4 2 5
# 5 2 8
# 6 5 8
# 7 3 6
# 8 3 9
# 9 6 9

convert rows after column

I have csv file which reads like this
1 5
2 3
3 2
4 6
5 3
6 7
7 2
8 1
9 1
What I want to do is to this:
1 5 4 6 7 2
2 3 5 3 8 1
3 2 6 7 9 1
i.e after every third row, I want a different column of the values side by side. Any advise?
Thanks a lot
Here's a way to do this with matrix indexing. It's a bit strange, but I find it interesting so I will post it.
You want an index matrix, with indices as follows. This gives the order of your data as a matrix (column-major order):
1, 1
2, 1
3, 1
1, 2
2, 2
3, 2
4, 1
...
8, 2
9, 2
This gives the pattern that you need to select the elements. Here's one approach to building such a matrix. Say that your data is in the object dat, a data frame or matrix:
m <- matrix(
c(
outer(rep(1:3, 2), seq(0,nrow(dat)-1,by=3), FUN='+'),
rep(rep(1:2, each=3), nrow(dat)/3)
),
ncol=2
)
The outer expression is the first column of the desired index matrix, and the rep expression is the second column. Now just index dat with this index matrix, and build a result matrix with three rows:
matrix(dat[m], nrow=3)
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 5 4 6 7 2
## [2,] 2 3 5 3 8 1
## [3,] 3 2 6 7 9 1
a <- read.table(text = "1 5
2 3
3 2
4 6
5 3
6 7
7 2
8 1
9 1")
(seq_len(nrow(a))-1) %/% 3
# [1] 0 0 0 1 1 1 2 2 2
split(a, (seq_len(nrow(a))-1) %/% 3)
# $`0`
# V1 V2
# 1 1 5
# 2 2 3
# 3 3 2
# $`1`
# V1 V2
# 4 4 6
# 5 5 3
# 6 6 7
# $`2`
# V1 V2
# 7 7 2
# 8 8 1
# 9 9 1
do.call(cbind,split(a, (seq_len(nrow(a))-1) %/% 3))
# 0.V1 0.V2 1.V1 1.V2 2.V1 2.V2
# 1 1 5 4 6 7 2
# 2 2 3 5 3 8 1
# 3 3 2 6 7 9 1

Resources