R language iteratively input a matrix - r

I'm trying to figure out how to iteratively load a matrix (this form part of a bigger function I can't reproduce here).
Let's suppose that I create a matrix:
m <- matrix(c(1:9), nrow = 3, ncol = 3)
m
This matrix can be named "m", "x" or whatsoever. Then, I need to load iteratively the matrix in the function:
if (interactive() ) { mat <-
readline("Your matrix, please: ")
}
So far, the function "knows" the name of the matrix, since mat returns [1] "m", and is a object listed in ls(). But when I try to get the matrix values, for example through x <- get(mat) I keep getting an error
Error in get(mat) : unused argument (mat)
Can anybody be so kind as to tell me what I'm doing wrong here?

1) Assuming you mean interactive, not iterative,
get_matrix <- function() {
nr <- as.numeric(readline("how many rows? "))
cat("Enter space separated data row by row. Enter empty row when finished.\n")
nums <- scan(stdin())
matrix(nums, nr, byrow = TRUE)
}
m <- get_matrix()
Here is a test:
> m <- get_matrix()
how many rows? 3
Enter space separated data row by row. Enter empty row when finished.
1: 1 2
3: 3 4
5: 5 6
7:
Read 6 items
> m
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
>
2) Another possibility is to require that the user create a matrix using R and then just give the name of the matrix:
get_matrix2 <- function(envir = parent.frame()) {
m <- readline("Enter name of matrix: ")
get(m, envir)
}
Test it:
> m <- matrix(1:6, 3)
> mat <- get_matrix2()
Enter name of matrix: m
> mat
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6

Related

Change length of an object using the get() function R

I'm writing a function to analyse .csv files in a directory on my hard drive, using a series of for and while loops (I know for loops are unpopular in R, but they're good for what I need).
The function creates a number of data-frames, and performs actions on each one in turn before overwriting them and moving on to the next file in the directory to repeat the action.
The part of the code that does not work so far is the creation of a matrix from vectors taken from the data files being analysed. A simplified version of the code is shown below:
data1 <- seq(1, 10, 1)
data2 <- seq(1, 7, 1)
data3 <- seq(1, 5, 1)
n <- max(length(data1), length(data2), length(data3))
k <- c(1, 2, 3)
for(a in k){
if(a == 1){
length(get(paste("data", a, sep = ""))) <- n
data_matrix <- get(paste("data", a, sep = ""))
}else{
while(exists(paste("data", a, sep = ""))){
length(get(paste("data", a, sep = ""))) <- n
data_matrix <- cbind(data_matrix, get(paste("data", a, sep = "")))
}
}
}
The nature of my data is that the length of the columns in my datasets vary with each data collection, so I've adapted a technique found in this post that deals with using cbind to bind objects of a different length without replication of the data within the smaller objects.
The issue I have when trying to implement this code is I get the error message:
Error in length(get(paste("data", a, sep = ""))) <- n :
target of assignment expands to non-language object
I'm guessing the issue is that the function get() cannot be used to select items in the Global Environment and to modify them in this way.
You could use:
get("x")[1:n]
to get a vector called "x" padded with NA to length n.
That is:
> x=1:3
> n=10
> get("x")[1:n]
[1] 1 2 3 NA NA NA NA NA NA NA
Having said that, this is a neater way to get the matrix you want (hopefully you can adapt to your scenario):
> datalist <- list(data1, data2, data3)
> maxlength <- max(lengths(datalist))
> sapply(datalist, function(x) x[1:maxlength] )
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
[4,] 4 4 4
[5,] 5 5 5
[6,] 6 6 NA
[7,] 7 7 NA
[8,] 8 NA NA
[9,] 9 NA NA
[10,] 10 NA NA
For those who want to see how the solution proposed by #GeorgeSavva looks using the loop method that I am employing (my loop contained additional errors):
data1 <- seq(1, 10, 1)
data2 <- seq(1, 7, 1)
data3 <- seq(1, 5, 1)
n <- max(length(data1), length(data2), length(data3))
k <- c(1, 2, 3)
for(a in k){
if(a == 1){
data_matrix <- get(paste("data", a, sep = ""))[1:n]
}else{
data_matrix <- cbind(data_matrix, get(paste("data", a, sep = ""))[1:n])
}
}
While loop was unnecessary. I have written my code this way so that I can make it as versatile as possible as I obtain on a daily basis a varying number of datasets, with a varying size in each dataset.
I can use common operations on each dataset, so I can write a function that will tidy the data, construct charts and compare the datasets automatically without having to write new commands for each analysis.

How to append the last row of a matrix to an empty matrix in R?

Suppose I generate a matrix with random numbers which contains 500 rows and 3 columns. If the last row of the first matrix is different for each loop. How can I append the last row of this matrix to append on the empty matrix for 1000 times?
Suppose the first matrix called mat1 and the second matrix called mat2.
I tried the following code:
for (i in 1:1000) { mat2 <- rbind(mat2,as.vector(mat1[500,])) }
But it keeps pop up number of items to replace is not a multiple of replacement length.
Does anyone know how to fix it? Many thanks.
I'm not sure I follow you. But if you have 500 x 3 matrix m and you want the last row then:
nrows <- nrow(m)
lrow <- m[nrows, ]
If you want fill an empty matrix m2 with 1000 copies of lrow then simply:
m2 <- matrix(lrow, nrow = 1000, ncol = 3, byrow = TRUE)
Note that R replicates data if it can to meet the declared dimensioning.
The for loop iteration seems to be only on the last row or 1000
for(i in 1:1000)
instead of
for(i in 1000)
Using a small reproducible example
mat1 <- matrix(1:9, 3, 3)
mat2 <- mat1[0,]
for(i in 1:5) {mat2 <- rbind(mat2, mat1[nrow(mat1),])}
mat2
# [,1] [,2] [,3]
#[1,] 3 6 9
#[2,] 3 6 9
#[3,] 3 6 9
#[4,] 3 6 9
#[5,] 3 6 9
Or using replicate
t( replicate(1000, mat1[nrow(mat1),]))
or use rep
mat1[rep(nrow(mat1), 1000),]

Multiply a matrix' columns by its columns

I have a 4x100 matrix where I would like to multiply column 1 with row 1 in its transpose etc and store these matrices somewhere to be able to take the sum of these new matrices lateron.
I really don't know where to start due to the fact that I get 4x4 matrices after the column-row-multiplication. Due to this fact I cannot store them in a matrix
data:
mm num[1:4,1:100]
mm_t num[1:100,1:4]
I'm thinking of creating a list in some way
list1=list()
for(i in 1:100){
list1[i] <- mm[,i]%*%mm_t[i,]
}
but I need some more indices i think because this just leaves me with a number in each argument..
First, your call for data is not clear. Second, are you tryign to multiply each value by itself, or do matrix multiplication
We create a 4x100 matrix and its transpose:
mm <- matrix(1:400, nrow = 4, ncol = 100)
mm.t <- t(mm)
Then we can do the matrix multiplication (which is what you did, and you get a 4 x 4 matrix from the definition of matrix multiplication https://www.wikiwand.com/en/Matrix_multiplication)
If we want to multiply each index by itself (so mm[1,1] by mm [1,1]) then:
mm * mm
This will result in 4x100 matrix where each value is the square of the original value.
If we want the matrix multiplication of each column with itself, then:
sapply(1:100, function(x) {
mm[, x] %*% mm[, x]
})
This results in 100 values: each one is the matrix product of a 4x1 vector with itself.
Let's start with some sample data. Please get in the habit of including things like this in your question:
nr = 4
nc = 100
set.seed(47)
mm = matrix(runif(nr * nc), nrow = nr)
Here's a working answer, very similar to your attempt:
result = list()
for (i in 1:ncol(mm)) result[[i]] = mm[, i] %*% t(mm[, i])
result[1:2]
# [[1]]
# [,1] [,2] [,3] [,4]
# [1,] 0.9544547 0.3653018 0.7439585 0.8035430
# [2,] 0.3653018 0.1398132 0.2847378 0.3075428
# [3,] 0.7439585 0.2847378 0.5798853 0.6263290
# [4,] 0.8035430 0.3075428 0.6263290 0.6764924
#
# [[2]]
# [,1] [,2] [,3] [,4]
# [1,] 0.3289532 0.3965557 0.2231443 0.2689613
# [2,] 0.3965557 0.4780511 0.2690022 0.3242351
# [3,] 0.2231443 0.2690022 0.1513691 0.1824490
# [4,] 0.2689613 0.3242351 0.1824490 0.2199103
As to why yours didn't work, we can experiment and see that indeed we get a number rather than a matrix. The reason is that when you subset a single row or column of a matrix, the dimensions are "dropped" and it is coerced to a plain vector. And when you matrix multiply two vectors, you get their dot product.
mmt = t(mm)
mm[, 1] %*% mmt[1, ]
# [,1]
# [1,] 2.350646
dim(mm[, 1])
# NULL
dim(mmt[1, ])
# NULL
We can avoid this by specifying drop = FALSE in the subset code
dim(mmt[1, , drop = FALSE])
# [1] 1 4
And thus slightly modify your attempt, just adding drop = FALSE will make it work.
res2 = list()
for (i in 1:ncol(mm)) res2[[i]] = mm[, i] %*% mmt[i, , drop = FALSE]
identical(result, res2)
# [1] TRUE

How to copy a row from a data frame to a matrix in R?

In Microsoft Open R 3.3, how can I copy a row from a database query (returns a data frame) into a row of a matrix? I know I could do it element-by-element, but I should be able to copy a row at a time. I can't, though:
> m = matrix(0, nrow=2, ncol=3)
> dim(m)
[1] 2 3
> dim(m[1,])
NULL
> f = dbGetQuery("SELECT id, name, age FROM users")
> dim(f)
[1] 300 3
> dim(f[1,])
[1] 1 3
> m[1,] = f[1,]
> m[1,]
Error in m[1, ] : incorrect number of dimensions
> dim(m)
NULL
> m[1,] = f[1,]
Error in m[1, ] = f[1, ] :
incorrect number of subscripts on matrix
Converting f to as.matrix(f) doesn't help.
Why is dim(m[1,]) "NULL" instead of "1 3"?
Why does m[1,] = f[1,] wreck the data structure of m the first time (changes dim(m) to NULL), but not report an error until the second time I do it?
I suspect this has to do with the fact that a data frame row can contain different types, while a matrix row can't. One column of the frame is character data, while the others are integers.
You should be able to assign the values after unlisting f[1,], since f[1,] returns a one row data frame which is a list, m[1,] returns an atomic vector and this answers the question Why is dim(m[1,]) "NULL" instead of "1 3"? because a 1D atomic vector doesn't have the dimension attribute. Trying to assign a list to an atomic vector causes problem:
m = matrix(0, nrow=2, ncol=3)
f = data.frame(x = 1:3, y = 2:4, z = 3:5)
m
# [,1] [,2] [,3]
#[1,] 0 0 0
#[2,] 0 0 0
m[1,] = unlist(f[1,])
m
# [,1] [,2] [,3]
#[1,] 1 2 3
#[2,] 0 0 0
class(m[1,])
#[1] "numeric"
class(f[1,])
#[1] "data.frame"

Replacing every row in a matrix

I've got a matrix (mat1), say 100 rows and 100 columns; I want to create another matrix where every row is the same as the 1st row in mat1 (except that I want to keep the 1st col as the original values)
I've managed to do this using a loop:
mat2 <- mat1
for(i in 1:nrow(mat1))
{
mat2[i,2:ncol(mat2)] <- mat1[1,2:ncol(mat1)]
}
this works and produces the result I expect; however, I'd have thought there should be a way to do it without a loop; I've tried:
mat2 <- mat1
mat2[c(2:100),2:ncol(mat2)] <- mat1[1,2:ncol(mat1)]
Can someone point out my error?!
Thanks,
Chris
The problem is the way R fills matrices, by columns. Here is a simple example that illustrates this:
mat1 <- matrix(1:9, ncol = 3)
mat2 <- matrix(1:9, ncol = 3)
mat2[-1, -1] <- mat1[1, -1]
mat2
> mat2
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 4 4
[3,] 3 7 7
mat1[1, -1] is the vector 4,7, which you can see that R has used to fill the bit of mat2 column-wise. You wanted a row-wise operation.
One solution is to replicate the replacement vector as many times as is required:
> mat2[-1, -1] <- rep(mat1[1, -1], each = nrow(mat1)-1)
> mat2
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 4 7
[3,] 3 4 7
This works because the rep() call replicates each value in the vector when we use the "each" argument, instead of replicating (repeating) the vector:
> rep(mat1[1, -1], each = nrow(mat1)-1)
[1] 4 4 7 7
The default behaviour would also give the wrong answer:
> rep(mat1[1, -1], nrow(mat1)-1)
[1] 4 7 4 7
In part, the problem you are seeing is also the way R extends arguments to the appropriate length for the replacement. R actually, and silently, extended the replacement vector exactly in the way rep(mat1[1, -1], nrow(mat1)-1) does, which when coupled with the fill-by-column principle gave the behaviour you saw.
Try
mat2[c(2:nrow(mat2)), 2:ncol(mat2)] <- mat1[rep.int(1,nrow(mat1)-1),2:ncol(mat1)]
Another option...
n = 5
mat1 = matrix(sample(n^2, n^2), n, n)
# use matrix with byrow to copy 1st row n times
mat2 = matrix(rep(mat1[1, ], n), n, n, byrow = TRUE)
# copy 1st column
mat2[ , 1] = mat1[ , 1]
mat1
mat2

Resources