nested double loop in R - r

mat <- matrix(0,ncol=6, nrow=100)
d=c(1,2,4,8,16,32)
for(i in 1:6)
{
for(j in d)
{
mat[,i]=rep(j,100)
}
}
mat
I should get a 100 x 6 matrix with columns of 1,2,4,8,16,32. However, I simply get rows of 32 in every column. Does anyone have any idea how I can fix this. I do want to use loops, even if its one loop that's fine.

The answer from #neilfws is more elegant. If you are committed to using a loop for some reason you can do this
mat <- matrix(0,ncol=6, nrow=100)
d=c(1,2,4,8,16,32)
for(i in 1:6)
{
j <- d[i]
mat[,i]=rep(j,100)
}
mat
The issue is that you were looping through all of d for each column.

Based on your description: 100 rows x 6 columns, column 1 = value 1...column 6 = value 32, this should generate what you want.
matrix(data = rep(c(1,2,4,8,16,32), each = 100),
nrow = 100,
ncol = 6)

Related

Matrix not filling up with 1 where necessary in R

I am trying to fill a matrix with ones (1) where the index corresponds to the max of another matrix of the same dimension.
below is a reproducible example
set.seed(1)
matric <- matrix(rnorm(3000), nrow = 500, ncol = 6)
best <- matrix(0, nrow = 500, ncol = 6)
n_end <- 500
for (i in n_end) {
best[which(matric[i,] == max(matric[i,]))] <- 1
}
## the best model has the higher sum
best1 <- colSums(best)
Please Help!! :)
We can use seq_len or 1:n_end and inside the loop, as we are assigning to the same row of 'best', index that matrix as well
for(i in 1:n_end) {
best[i,][matric[i,] == max(matric[i,])] <- 1
}
Or if there is only a single max value per row, then use max.col as it is faster and vectorized
best[cbind(seq_len(nrow(best)), max.col(matric, 'first'))] <- 1
Or with rowMaxs from matrixStats
library(matrixStats)
+(matric == rowMaxs(matric))

Call a function and provide output in a matrix

I have a function in R which I call
RS1 = t(cbind(Data[,18], Data[,20]))
RS2 = t(cbind(Data[,19], Data[,21]))
p = t(Data[23:24])
rand_x <- function (p, x) {
n.goods <- dim (p)[1]
n.obs <- dim (p)[2]
xRC = NaN*matrix(1, n.goods, n.obs)
for(i in 1:n.obs) {
xRC[1,i] <- RS1[1,i] + RS1[2,i]
xRC[2,i] <- RS2[1,i] + RS2[2,i]
}
result <- xRC
return(result)
}
This function by having these two inputs generates a vector (2x50) with some random numbers. I want to call this function rand_x 1000 times and derive 1000 matrices and then bind the results in a final matrix. I have tried to create a loop to sort this problem but I am still struggling. Any help will be much appreciated.
If you intend to add each element of column 18 to 20 (that is what your code does), try using rowSums().
Try:
xRC <- rbind(
rowSums (Data [, c(18, 20)])
rowSums (Data [, c(19, 21)])
)
The output will be a matrix.
I do not see, where randomness appears in your function though. If you just want a 2x50 matrix with random numbers you may want to use:
xRC <- matrix (rnorm(50*2), 2) # for standard-normal generated numbers
xRC <- matrix (sample(1:100, replace = T, size = 100), 2) # for numbers between 1 and 100, uniformly distributed
To do this 1000 times, try:
for (i in 1:1000) {
rbind(xRC,
rowSums (Data [, c(18, 20)])
rowSums (Data [, c(19, 21)])
)
}
# or if you just want to generate random numbers, performance is way faster when you use:
xRC <- matrix(rnorm(1000 * 2 * 50), ncol = 50)

Writing a for loop with the output as a data frame in R

I am currently working my way through the book 'R for Data Science'.
I am trying to solve this exercise question (21.2.1 Q1.4) but have not been able to determine the correct output before starting the for loop.
Write a for loop to:
Generate 10 random normals for each of μ= −10, 0, 10 and 100.
Like the previous questions in the book I have been trying to insert into a vector output but for this example, it appears I need the output to be a data frame?
This is my code so far:
values <- c(-10,0,10,100)
output <- vector("double", 10)
for (i in seq_along(values)) {
output[[i]] <- rnorm(10, mean = values[[i]])
}
I know the output is wrong but am unsure how to create the format I need here. Any help much appreciated. Thanks!
There are many ways of doing this. Here is one. See inline comments.
set.seed(357) # to make things reproducible, set random seed
N <- 10 # number of loops
xy <- vector("list", N) # create an empty list into which values are to be filled
# run the loop N times and on each loop...
for (i in 1:N) {
# generate a data.frame with 4 columns, and add a random number into each one
# random number depends on the mean specified
xy[[i]] <- data.frame(um10 = rnorm(1, mean = -10),
u0 = rnorm(1, mean = 0),
u10 = rnorm(1, mean = 10),
u100 = rnorm(1, mean = 100))
}
# result is a list of data.frames with 1 row and 4 columns
# you can bind them together into one data.frame using do.call
# rbind means they will be merged row-wise
xy <- do.call(rbind, xy)
um10 u0 u10 u100
1 -11.241117 -0.5832050 10.394747 101.50421
2 -9.233200 0.3174604 9.900024 100.22703
3 -10.469015 0.4765213 9.088352 99.65822
4 -9.453259 -0.3272080 10.041090 99.72397
5 -10.593497 0.1764618 10.505760 101.00852
6 -10.935463 0.3845648 9.981747 100.05564
7 -11.447720 0.8477938 9.726617 99.12918
8 -11.373889 -0.3550321 9.806823 99.52711
9 -7.950092 0.5711058 10.162878 101.38218
10 -9.408727 0.5885065 9.471274 100.69328
Another way would be to pre-allocate a matrix, add in values and coerce it to a data.frame.
xy <- matrix(NA, nrow = N, ncol = 4)
for (i in 1:N) {
xy[i, ] <- rnorm(4, mean = c(-10, 0, 10, 100))
}
# notice that i name the column names post festum
colnames(xy) <- c("um10", "u0", "u10", "u100")
xy <- as.data.frame(xy)
As this is a learning question I will not provide the solution directly.
> values <- c(-10,0,10,100)
> for (i in seq_along(values)) {print(i)} # Checking we iterate by position
[1] 1
[1] 2
[1] 3
[1] 4
> output <- vector("double", 10)
> output # Checking the place where the output will be
[1] 0 0 0 0 0 0 0 0 0 0
> for (i in seq_along(values)) { # Testing the full code
+ output[[i]] <- rnorm(10, mean = values[[i]])
+ }
Error in output[[i]] <- rnorm(10, mean = values[[i]]) :
more elements supplied than there are to replace
As you can see the error say there are more elements to put than space (each iteration generates 10 random numbers, (in total 40) and you only have 10 spaces. Consider using a data format that allows to store several values for each iteration.
So that:
> output <- ??
> for (i in seq_along(values)) { # Testing the full code
+ output[[i]] <- rnorm(10, mean = values[[i]])
+ }
> output # Should have length 4 and each element all the 10 values you created in the loop
# set the number of rows
rows <- 10
# vector with the values
means <- c(-10,0,10,100)
# generating output matrix
output <- matrix(nrow = rows,
ncol = 4)
# setting seed and looping through the number of rows
set.seed(222)
for (i in 1:rows){
output[i,] <- rnorm(length(means),
mean=means)
}
#printing the output
output

Avoid a for loop

I am trying to optimize an algorithm and I really want to avoid all my loops. Hence I am wondering if there is a way to avoid the following simple loop:
library(FNN)
data <- cbind(1:10, 1:10)
NN.index <- get.knn(data, 5)$nn.index
bc <- matrix(0, nrow(NN.index), max(NN.index))
for(i in 1:nrow(bc)){
bc[i,NN.index[i,]] <- 1
}
were bc is a matrix of zeros.
In R, if the bracket of a matrix M take a k-by-2 matrix 'I', then each row of the k-by-2 matrix I is recognized as the row and column index of M. For example
M = matrix(1:20, nrow =4, ncol = 3)
print(M)
I = rbind(c(1,2), c(4,2), c(3,3))
print(M[I])
In this case, M[1,2], M[4,2] and M[3,3] are extracted.
In your case, we can create row_index and col_index from NN.index as below, and then assign 1 to the corresponding entries.
bc <- matrix(0, nrow(NN.index), max(NN.index))
row_index <- rep(1:nrow(NN.index), times = ncol(NN.index))
col_index <- as.vector(NN.index)
bc[cbind(row_index, col_index)] <- 1
print(bc)

Loop to select pairwise series

I have a data.frame in R with 40 series and I want to select pairwise series to apply a function, (ie serie 1 and serie 21, serie 2 and serie 22) . However I'm getting error with the following code:
for(i in 1:ncol(Date)) {
pairwise <-Date[, c(i,i+20)]
}
I want to use pairwise in other function.
Could someone please help me?
Thank in advance
It is because you are requesting columns higher than 40 when i > 20. See this example:
set.seed(1)
DF <- data.frame(matrix(rnorm(40*100), ncol = 40))
## simple function to apply/use
foo <- function(x1, x2) return(x1 - x2)
## something to hold results
res <- matrix(ncol = ncol(DF), nrow = nrow(DF))
## loop - oops error
for(i in seq_len(ncol(DF))) {
res[,i] <- foo(DF[,i], DF[,i+20])
}
You get this error:
Error in `[.data.frame`(DF, , i + 20) : undefined columns selected
That is because i takes values 1, ..., 40. As soon as i >= 21, (i + 20) > 40 and you only have 40 columns of data. A simple modification is to loop only over the first 20 columns:
## something to hold results
res <- matrix(ncol = ncol(DF) / 2, nrow = nrow(DF))
for(i in seq_len(ncol(DF)/2)) {
res[,i] <- foo(DF[,i], DF[,i+20])
}
if all you want is col 1 and col 21, col 2 and col 22 etc. If you want all pairwise comparisons then you need to try something different, as a single loop won't work.
(Before someone pulls me up for woefully inefficient use of a loop, that example was just that, an example with no imagination applied to the function foo(). In this case, DF[, 1:20] - DF[, 21:40] will give the same result as in res.)

Resources