Repeating sequences in R - r

I want to generate a vector of the the numbers (1:5), (1:5)+45 and so on
nums <- seq(1,22500,45)
rws <- c(1:5)
nums2 <- nums - 1
for (i in nums2[2:500]){
rwsx <- append(rws, rws+i)
rwsx}
But the loop just stores the most recent append and I get:
1 2 3 4 5 22456 22457 22458 22459 22460

It sounds like you're looking for outer. Try:
> nums <- seq(1, 22500, 45)
> out <- outer(nums, 0:4, "+")
> head(out)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 46 47 48 49 50
[3,] 91 92 93 94 95
[4,] 136 137 138 139 140
[5,] 181 182 183 184 185
[6,] 226 227 228 229 230
> tail(out)
[,1] [,2] [,3] [,4] [,5]
[495,] 22231 22232 22233 22234 22235
[496,] 22276 22277 22278 22279 22280
[497,] 22321 22322 22323 22324 22325
[498,] 22366 22367 22368 22369 22370
[499,] 22411 22412 22413 22414 22415
[500,] 22456 22457 22458 22459 22460
As mentioned in the comments, a matrix is a vector with dimensional attributes. Matrices in R a generally constructed by column, so if you want to remove the dimensions and get a single vector in the row-wise order, then you need to transpose the matrix first.
> head(as.vector(t(out)), 16)
[1] 1 2 3 4 5 46 47 48 49 50 91 92 93 94 95 136

We can try
rwsx <- matrix(nums,500) %*% matrix(rws,1)
head(rwsx)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 46 92 138 184 230
[3,] 91 182 273 364 455
[4,] 136 272 408 544 680
[5,] 181 362 543 724 905
[6,] 226 452 678 904 1130

r <- 22500%/%45
m <- matrix(45*0:(r-1), r, 5)
m <- m+ col(m)
rwsx <- c(t(m))
or
r <- 22500%/%45
m <- matrix(45*0:(r-1), 5, r, byrow=TRUE)
m <- m+ row(m)
rwsx <- c(m)

As oneliner:
as.vector(sapply(seq(by = 45, length.out = 10), function(x) x + 0:4))

Related

Extract each RGB layers from raster and paste into matrix in R

I would like to store a raster image into an empty matrix. I load my image and I create an empty matrix of same dimension.
setwd("C:/Users/Desktop/image/")
img_path <- "image.jpeg"
raster <- brick(img_path, package="raster")
nrow <- dim(raster)[1]
ncol <- dim(raster)[2]
img_matrix <- matrix(, nrow = nrow, ncol = ncol)
dim(raster)
[1] 896 1408 3
dim(img_matrix)
[1] 896 1408
When I try to load the raster into the matrix I got this error:
img_matrix[1, 1] <- raster
Error in img_matrix[1, 1] <- raster :
number of items to replace is not a multiple of replacement length
I think the problem is there are 3 layers in the raster and the matrix is just 1. So I think I create 3 matrix and paste each R, G, B layer of the raster into the associated matrix. Finally, assemble the 3 matrix to create the image.
How to do it?
There is an as.array method for objects of class raster.
library(raster)
raster <- brick("3.jpg", package="raster")
dim(raster)
#[1] 665 800 3
array <- as.array(raster)
dim(array)
#[1] 665 800 3
array[201:205,401:405,1]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 244 244 244 244 244
#[2,] 244 244 244 244 244
#[3,] 244 244 244 244 244
#[4,] 244 244 244 244 244
#[5,] 244 244 244 244 244
array[201:205,401:405,2]
# [,1] [,2] [,3] [,4] [,5]
#[1,] 202 202 202 202 202
#[2,] 202 202 202 202 202
#[3,] 202 202 202 202 202
#[4,] 202 202 202 202 202
#[5,] 202 202 202 202 202
As you can see, this will coerce the raster object into a three dimensional array.

R: how do apply the sum function in a list?

I am having a problem with summing the rows of my matrices. I have a list formed by 30 matrices
Matrix<-matrix(1:45, ncol=9)
List<-list(lapply(seq_len(30), function(X) Matrix))
The idea is to create 30 matrices size 5*3. Firstly, I need to sum some columns, 1:3 4:6 7:9, such that the result will be the following:
[,1] [,2] [,3]
[1,] 18 63 108
[2,] 21 66 111
[3,] 34 69 114
[4,] 47 72 117
[5,] 30 75 120
I am trying to get this matrix using this code:
Y<-lapply(List, function(x) rowSums(x[, 1:3]))
But, it only allows me to sum the 3 firsts columns.
After this, I need to sum the list and obtain only one matrix(5*3). I think that the command final<-reduce(Y,+) could help.
540 1890 3240
630 1980 3330
1020 2070 3420
1410 2160 3510
900 2250 3600
Thank you for your help
You need to find someway to group your columns by threes, for example:
grp = (1:ncol(Matrix) -1) %/% 3
or if you know the dimensions:
grp = rep(0:2,each=3)
To do rowSums in columns of threes, we can do this with a function:
SumCols = function(M,col_grp){
sapply(unique(col_grp),function(i)rowSums(M[,col_grp==i]))
}
SumCols(Matrix,grp)
[,1] [,2] [,3]
[1,] 18 63 108
[2,] 21 66 111
[3,] 24 69 114
[4,] 27 72 117
[5,] 30 75 120
So put this inside your List of matrices,
Reduce("+",lapply(List[[1]],SumCols,grp))
[,1] [,2] [,3]
[1,] 540 1890 3240
[2,] 630 1980 3330
[3,] 720 2070 3420
[4,] 810 2160 3510
[5,] 900 2250 3600
Here is another base R solution
out <- Reduce(`+`,Map(function(x) do.call(cbind,Map(rowSums, split.default(data.frame(x),ceiling(seq(ncol(x))/3)))),List[[1]]))
such that
> out
0 1 2
[1,] 540 1890 3240
[2,] 630 1980 3330
[3,] 720 2070 3420
[4,] 810 2160 3510
[5,] 900 2250 3600

How can I use a loop in R to create new, labeled variables and write them into a .csv?

I have a table with eighty columns and I want to create columns by multiplying var1*var41 var1*var42....var1*var80. var2*var41 var2*var42...var2*var80. How could I write a loop to multiply the columns and write the labeled product into a .csv? The result should have 1600 additional columns.
I took a stab at this with some fake data:
# Fake data (arbitraty 5 rows)
mtx <- sample(1:100, 5 * 80, replace = T)
dim(mtx) <- c(5,80)
colnames(mtx) <- paste0("V", 1:ncol(mtx)) # Name the original columns
mtx[1:5,1:5]
# V1 V2 V3 V4 V5
#[1,] 8 10 69 84 92
#[2,] 59 34 36 96 86
#[3,] 51 26 78 63 8
#[4,] 74 93 73 70 49
#[5,] 62 30 20 43 9
Using a for loop, one might try something like this:
v <- expand.grid(1:40,41:80) # all combos
v[c(1:3,1598:1600),]
# Var1 Var2
#1 1 41
#2 2 41
#3 3 41
#1598 38 80
#1599 39 80
#1600 40 80
# Initialize matrix for multiplication results
newcols <- matrix(NA, nrow = nrow(mtx), ncol = nrow(v))
# Run the for loop
for(i in 1:nrow(v)) newcols[,i] <- mtx[,v[i,1]] * mtx[,v[i,2]]
# save the names as "V1xV41" format with apply over rows (Margin = 1)
# meaning, for each row in v, paste "V" in front and "x" between
colnames(newcols) <- apply(v, MARGIN = 1, function(eachv) paste0("V", eachv, collapse="x"))
# combine the additional 1600 columns
tocsv <- cbind(mtx, newcols)
tocsv[,78:83] # just to view old and new columns
# V78 V79 V80 V1xV41 V2xV41 V3xV41
#[1,] 17 92 13 429 741 1079
#[2,] 70 94 1 4836 4464 5115
#[3,] 6 77 93 3740 1020 3468
#[4,] 88 34 26 486 258 66
#[5,] 48 77 61 873 4365 970
# Write it
write.csv(tocsv, "C:/Users/Evan Friedland/Documents/NEWFILENAME.csv")

How do I sum over specific number of columns in dataframe in R?

I have a dataframe (cenMca) with 1020 rows and 800 columns.
Each 4 columns, I have a set of data I call "cen". So, from column 1 to 4, I have cen 1, from 5 to 8, I have cen2 and so on.
I wanted to split cenMca into 200 hundred smaller dataframes of dimensions equal to 1020 lines by 4 columns and sum the values per row. For this I'd apply a function sum to each row, however, I searched for ways to split my dataframe in the way I wanted, but failed in doing so. Also, I have no idea how I would iterate through these smaller dataframes to save each with a different name.
So I thought that instead of breaking cenMca into smaller dataframes, I'd sum the values from cenMca and assign them to a single dataframe I called sumvec. So, for every 4 columns in cenMca, I'd have one corresponding column in sumvec. This gives sumvec dimensions equal to 1020 rows and 200 columns.
To accomplish this, I tried:
sumvec = matrix(NA,1020,200)
for (i in 1:1020 ){
for (j in seq(1,800,4)){
sumvec[i,(j+3)/4] = cenMca[i,j]+cenMca[i,j+1]+cenMca[i,j+2]+cenMca[i,j+3]
}
}
The first for runs through rows, and the second for runs through the columns. My increment is 4 for the second for because then I'd get all four values I wanted in a cycle.
I know this is far from efficient, but I thought it'd work.
After I ran the script, I got this:
I tried warnings() but nothing came up. All I have in sumvec is "NA"
How could I fix this?
Other techniques on how to get this done will be appreciated. Thank you.
This seems like a good application for rowSums. You could use lapply to run it over the grouped columns like you're trying to do.
I'll use similar data setup as #R.Schifini:
set.seed(1)
z <- matrix( rnorm( 1020*800 ), ncol = 800 )
Make it a data frame, like your data.
z <- as.data.frame(z)
Now group the data frame into groups of 4 columns, running rowSums on each group.
x <- lapply( seq.int( 1, ncol(z), 4 ),
function(i) {
rowSums( z[ , i:(i+3) ] )
} )
Bind it together as a single data frame, with the column names you need.
x <- as.data.frame( x, col.names = paste0( "cen", seq_along( x ) ) )
Here's a small sample of the output.
> head( x[1:6] )
cen1 cen2 cen3 cen4 cen5 cen6
1 -0.8027240 -0.7437158 -1.5305678 -0.7055544 2.0122082 0.7851487
2 0.0854064 0.2422316 -2.5071390 1.7854231 -3.5219698 -0.7699433
3 1.2738387 1.7360087 1.4317099 -3.3501584 -1.8412381 -2.1396324
4 -0.5864149 -0.5648199 -0.3099392 -1.9144969 0.7874474 -2.4840934
5 -0.3887289 -1.0745042 -1.9729363 1.8971846 -4.3374676 2.5744197
6 0.9104741 -0.7546090 4.2516971 1.0335885 2.6814576 -0.2548666
Is this what you are trying to achieve?
I'll create a sample matrix (also works if it is a data frame)
z = matrix(floor(runif(120, 0, 100)), ncol = 12)
> z
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 37 50 37 0 71 84 29 65 0 34 33 65
[2,] 53 60 17 44 39 94 16 66 72 12 27 32
[3,] 10 26 5 26 11 58 39 47 71 38 11 19
[4,] 80 42 65 93 24 50 45 96 18 92 4 11
[5,] 73 36 57 71 86 18 43 40 64 80 37 99
[6,] 5 94 98 16 43 0 51 84 54 75 33 37
[7,] 48 12 60 47 49 87 84 75 33 95 17 56
[8,] 92 7 6 69 69 13 5 53 63 99 62 73
[9,] 4 96 16 46 76 2 55 87 82 60 39 87
[10,] 29 44 47 95 15 93 68 46 70 2 95 57
Then add columns in groups of four:
result = z[,seq(1,12,by = 4)]+z[,seq(2,12,by = 4)]+z[,seq(3,12,by = 4)]+z[,seq(4,12,by = 4)]
> result
[,1] [,2] [,3]
[1,] 124 249 132
[2,] 174 215 143
[3,] 67 155 139
[4,] 280 215 125
[5,] 237 187 280
[6,] 213 178 199
[7,] 167 295 201
[8,] 174 140 297
[9,] 162 220 268
[10,] 215 222 224
First of all, you don't need to loop over rows. R works well with vectors.
Secondly, NAs in sumvec might be results of NAs in cenMca. If you have NAs in cenMca, use sum instead of +.
for (j in seq(1,800,4)) sumvec[,(j+3)/4] <- apply(cenMca[,j:(j+3)],1,sum, na.rm=T)
Hope, this helps.

Calculating ratios and put them into a matrix in R

I have a table similar to this one, and want to calculate the ratio between column A and B. For example:
A B C D E F
[1,] 187 174 183 115 101 104
[2,] 451 166 177 842 101 133
[3,] 727 171 187 12803 98 134
[4,] 1532 181 196 730 98 108
[5,] 4139 188 214 20358 105 159
[6,] 689 185 211 1633 110 162
[7,] 1625 184 195 2283 109 114
[8,] 771 181 190 904 105 110
[9,] 950 177 190 1033 106 112
[10,] 703 180 191 463 106 110
[11,] 2052 178 188 2585 100 105
[12,] 1161 178 187 2874 99 110
[13,] 214 175 184 173 98 110
[14,] 473 184 191 971 104 111
[15,] 756 185 193 14743 107 114
I want to create a new matrix that has all of those previous rows as new rows and columns (15 rows and 15 columns) like so (values in parentheses are placeholders for the calculated ratios):
[,1] [,2] [,3] [,4]
[1,] (A1:B1) (A1:B2) (A1:B3) (A1:B4) ...
[2,]
[3,]
[4,]
...
That is maybe not the best example, but I hope it is not too confusing.
To calculate the ratios A1:B1, A2:B2, A3:B3 I could do something like:
data.matrix(data["A"]/data["B"])
And to do it for all, I would do something like:
data.matrix(data[1,]/data[1,1])
data.matrix(data[1,]/data[1,2])
...
and so on.
This seems to be a lot of work and maybe someone knows a quicker and more efficient method.
EDIT
I thought the combn function would work, but then I figured out it doesn't. When I have a 2 column matrix, such as:
A B
[1,] 187 115
[2,] 451 842
[3,] 727 12803
[4,] 1532 730
[5,] 4139 20358
[6,] 689 1633
[7,] 1625 2283
[8,] 771 904
[9,] 950 1033
[10,] 703 463
[11,] 2052 2585
[12,] 1161 2874
[13,] 214 173
[14,] 473 971
[15,] 756 14743
And I use the combn function to calculate all possible ratios (A1:B1, A1:B2, ... A2:B1, A2:B2...) I get just the result for A1 vs all values of B.
> combn(ncol(data), 2, function(x) data[,x[1]]/data[,x[2]])
[,1]
[1,] 1.62608696
[2,] 0.53562945
[3,] 0.05678357
[4,] 2.09863014
[5,] 0.20331074
[6,] 0.42192284
[7,] 0.71178274
[8,] 0.85287611
[9,] 0.91965150
[10,] 1.51835853
[11,] 0.79381044
[12,] 0.40396660
[13,] 1.23699422
[14,] 0.48712667
[15,] 0.05127857
Or maybe I just don't understand the combn function and I am doing something wrong here.
You can achieve what you want by using expand.grid, apply and matrix functions as below
I am assuming what you want is matrix like
A1/B1 A1/B2 A1/B3 ...
A2/B1 A2/B2 A2/B3 ...
... ... ... ...
... ... ... ...
Here is the code to do that. Explanation in comments
txt <- "A B C D E F\n187 174 183 115 101 104\n451 166 177 842 101 133\n727 171 187 12803 98 134\n1532 181 196 730 98 108\n4139 188 214 20358 105 159\n689 185 211 1633 110 162\n1625 184 195 2283 109 114\n771 181 190 904 105 110\n950 177 190 1033 106 112\n703 180 191 463 106 110\n2052 178 188 2585 100 105\n1161 178 187 2874 99 110\n214 175 184 173 98 110\n473 184 191 971 104 111\n756 185 193 14743 107 114"
data <- as.matrix(read.table(textConnection(txt), header = TRUE))
# expand.grid : creates every combination of one element each from column A and
# B with elements of B repeated first
# apply : calls function(x) { x[1]/x[2]) } for every combination outputted by
# expand.grid
# matrix : converts the result of apply into matrix. dimnames arguments sets
# rownames and colnames for easy verification for us
result <- matrix(apply(expand.grid(data[, "A"], data[, "B"]), 1, function(x) x[1]/x[2]),
nrow = nrow(data), dimnames = list(data[, "A"], data[, "B"]))
# note that we have set rownames for result to be values of A and colnames for
# result to be value of B
result
## 174 166 171 181 188 185 184
## 187 1.074713 1.126506 1.093567 1.033149 0.9946809 1.010811 1.016304
## 451 2.591954 2.716867 2.637427 2.491713 2.3989362 2.437838 2.451087
## 727 4.178161 4.379518 4.251462 4.016575 3.8670213 3.929730 3.951087
## 1532 8.804598 9.228916 8.959064 8.464088 8.1489362 8.281081 8.326087
## 4139 23.787356 24.933735 24.204678 22.867403 22.0159574 22.372973 22.494565
## 689 3.959770 4.150602 4.029240 3.806630 3.6648936 3.724324 3.744565
## 1625 9.339080 9.789157 9.502924 8.977901 8.6436170 8.783784 8.831522
## 771 4.431034 4.644578 4.508772 4.259669 4.1010638 4.167568 4.190217
## 950 5.459770 5.722892 5.555556 5.248619 5.0531915 5.135135 5.163043
## 703 4.040230 4.234940 4.111111 3.883978 3.7393617 3.800000 3.820652
## 2052 11.793103 12.361446 12.000000 11.337017 10.9148936 11.091892 11.152174
## 1161 6.672414 6.993976 6.789474 6.414365 6.1755319 6.275676 6.309783
## 214 1.229885 1.289157 1.251462 1.182320 1.1382979 1.156757 1.163043
## 473 2.718391 2.849398 2.766082 2.613260 2.5159574 2.556757 2.570652
## 756 4.344828 4.554217 4.421053 4.176796 4.0212766 4.086486 4.108696
## 181 177 180 178 178 175 184
## 187 1.033149 1.056497 1.038889 1.050562 1.050562 1.068571 1.016304
## 451 2.491713 2.548023 2.505556 2.533708 2.533708 2.577143 2.451087
## 727 4.016575 4.107345 4.038889 4.084270 4.084270 4.154286 3.951087
## 1532 8.464088 8.655367 8.511111 8.606742 8.606742 8.754286 8.326087
## 4139 22.867403 23.384181 22.994444 23.252809 23.252809 23.651429 22.494565
## 689 3.806630 3.892655 3.827778 3.870787 3.870787 3.937143 3.744565
## 1625 8.977901 9.180791 9.027778 9.129213 9.129213 9.285714 8.831522
## 771 4.259669 4.355932 4.283333 4.331461 4.331461 4.405714 4.190217
## 950 5.248619 5.367232 5.277778 5.337079 5.337079 5.428571 5.163043
## 703 3.883978 3.971751 3.905556 3.949438 3.949438 4.017143 3.820652
## 2052 11.337017 11.593220 11.400000 11.528090 11.528090 11.725714 11.152174
## 1161 6.414365 6.559322 6.450000 6.522472 6.522472 6.634286 6.309783
## 214 1.182320 1.209040 1.188889 1.202247 1.202247 1.222857 1.163043
## 473 2.613260 2.672316 2.627778 2.657303 2.657303 2.702857 2.570652
## 756 4.176796 4.271186 4.200000 4.247191 4.247191 4.320000 4.108696
## 185
## 187 1.010811
## 451 2.437838
## 727 3.929730
## 1532 8.281081
## 4139 22.372973
## 689 3.724324
## 1625 8.783784
## 771 4.167568
## 950 5.135135
## 703 3.800000
## 2052 11.091892
## 1161 6.275676
## 214 1.156757
## 473 2.556757
## 756 4.086486
Edit: I seem to have misunderstood the question. The answer is even more simpler using outer:
# gives the same 15*15 matrix as geektrader's
outer(mm[,1], mm[,2], '/')
Old answer (not correct):
You should use combn:
# combn(ncol(mm), 2) gives you all possible combinations
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15]
# [1,] 1 1 1 1 1 2 2 2 2 3 3 3 4 4 5
# [2,] 2 3 4 5 6 3 4 5 6 4 5 6 5 6 6
# it also accepts a function argument. we can use it to divide
# respective columns
mm.div <- combn(ncol(mm), 2, function(x) mm[,x[1]]/mm[,x[2]])
# set column names the matrix
colnames(mm.div) <- combn(colnames(mm), 2, paste, collapse="")
I might be completely missing the point here, but why not just use a couple for loops? I wrote a quick function, then you could pass the pairs to.
For example:
A <- rnorm(15)
B <- rnorm(15)
data <- data.frame(A,B)
ratio <- function(input1, input2){
out <- matrix(0, nrow=length(input1), ncol=length(input1))
k <- 1
for (i in 1:length(input1)){
for (j in 1:length(input1)){
out[k, j] <- input1[k] / input2[j]
}
k <- k + 1
}
return(out)
}
ratio(data$A, data$B)
EDIT
Another thought. To then use the function to do all possible pairs of ratios, you could simply add another for loop, like this:
combs <- combn(1:4, 2)
out <- list()
for (i in 1:(length(combs)/2)){
out[[i]] <- ratio(data[,combs[1,i]], data[,combs[2,i]])
}
Hope that helps!

Resources