Read the columns name and getting subscript out of bounds - R - r

I have a matrix (RR) that the column names are integer. When I refer to the elements of the marix like RR[x, c("5")] it works fine but when I put change it to
Myindex <-5
RR[x, c("Myindex")]
I get the error subscript out of bounds. I could not understand it so far.
BTW, 5 is just an example.
Any idea?
Thanks

Even though you name the column names as numbers it is taken as character column names.
rr <- matrix(1:15,3,5)
colnames(rr) <- c(21:25)
rr
# 21 22 23 24 25
# [1,] 1 4 7 10 13
# [2,] 2 5 8 11 14
# [3,] 3 6 9 12 15
rr[1,"23"]
# 23 ## column name is 23
# 7
my_index <- 4
rr[3,my_index]
# 24 ## column name is 24
# 12
my_index <- "25"
rr[3,my_index]
# 25 ## column name is 25
# 15
colnames(rr) <- as.integer(c(21:25))
rr
# 21 22 23 24 25
# [1,] 1 4 7 10 13
# [2,] 2 5 8 11 14
# [3,] 3 6 9 12 15
class(colnames(rr))
# [1] "character"

Related

How to split integer vector in R

I have a vector of integers that I want to split by 3, then I have to order the splitted parts and put bac into integer vector.
as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
First step - split like this:
16,9,2
17,10,3
18,11,4
19,12,5
20,13,6
21,14,7
22,15,8
Second step - order:
2,9,16
3,10,17
4,11,18
5,12,19
6,13,20
7,14,21
8,15,22
Third step - put back into integer vector:
2,9,16,3,10,17,4,11,18,5,12,19,6,13,20,7,14,21,8,15,22
With matrix + sort:
x <- as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
c(apply(matrix(x, ncol = 3, byrow = T), 1, sort))
#[1] 2 9 16 3 10 17 4 11 18 5 12 19 6 13 20 7 14 21 8 15 22
Or with split + gl:
unlist(lapply(split(x, gl(length(x) / 3, 3)), sort))
Another shorter approach with split + rev (only works if rev and sort are the same):
c(do.call(rbind, rev(split(x, 1:3))))
#[1] 2 9 16 3 10 17 4 11 18 5 12 19 6 13 20 7 14 21 8 15 22
No {dplyr} required here.
x <- as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
spl.x <- split(x, ceiling(seq_along(x)/3)) # split the vector
spl.x <- lapply(spl.x, sort) # sort each element of the list
Reduce(c, spl.x) # Reduce list to vector
Second line (splitting) is from this answer: https://stackoverflow.com/a/3321659/2433233
This also works if the length of your original vector is no multiple of 3. The last list element is shorter in this case.
Here is one way to do steps in order:
vector=as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
chunk <- 3
n <- length(vector)
r <- rep(1:ceiling(n/chunk),each=chunk)[1:n]
list_of3 <- split(vector,r)
# > list_of3
# $`1`
# [1] 16 9 2
#
# $`2`
# [1] 17 10 3
#
# $`3`
# [1] 18 11 4
#
# $`4`
# [1] 19 12 5
#
# $`5`
# [1] 20 13 6
#
# $`6`
# [1] 21 14 7
#
# $`7`
# [1] 22 15 8
sorted_list<- lapply(list_of3, function(x)sort(x))
final_vector <- unname(unlist(sorted_list))
final_vector
# > final_vector
# [1] 2 9 16 3 10 17 4 11 18 5 12 19 6 13 20 7 14 21 8 15 22```
Here is one way to do it:
v <- as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
res <- split(v, 0:(length(v)-1) %/%3)
unlist(lapply(res, sort), use.names = FALSE)
You can put your data into a 3 column matrix by row, sort rowwise, transpose and convert back to vector:
v <- as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
m <- matrix(v, ncol = 3, byrow = TRUE)
c(t(matrix(m[order(row(m), m)], nrow(m), byrow = TRUE)))
[1] 2 9 16 3 10 17 4 11 18 5 12 19 6 13 20 7 14 21 8 15 22
Something like this goes through every step:
v = as.integer(c(16,9,2,17,10,3,18,11,4,19,12,5,20,13,6,21,14,7,22,15,8))
v2 = v %>% matrix(ncol= 3, byrow = T)
# [,1] [,2] [,3]
# [1,] 16 9 2
# [2,] 17 10 3
# [3,] 18 11 4
# [4,] 19 12 5
# [5,] 20 13 6
# [6,] 21 14 7
# [7,] 22 15 8
v3 = v2[, rev(seq_len(ncol(v2)))]
# [,1] [,2] [,3]
# [1,] 2 9 16
# [2,] 3 10 17
# [3,] 4 11 18
# [4,] 5 12 19
# [5,] 6 13 20
# [6,] 7 14 21
# [7,] 8 15 22
v4 = v3 %>% as.vector
# [1] 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

How do you fill in an empty data frame based on an index in R?

I'm trying to create an empty data frame then have it filled in based on this for loop.
I want to have a data frame by the dimensions 5x10, which contains the result of the multiplication of the each number in the vectors A and B.
This what I want the end data frame to look like.
So far I'm using a for loop to calculate the product of the 2 vectors but I am not able to insert the result I want into the data frame.
Where am I going wrong?
My Code:
a <- c(1:10)
b <- c(1:5)
#Make a dummy dataframe filled with zeros, thats length(a) long and length(b) high
dummy <- as.data.frame(matrix(0, ncol=5, nrow=10))
heatmap_prep <- function(vector_a,vector_b){
for (i in 1:length(a)){
first_number <- a[i]
for(j in 1:length(b)){
second_number <- b[j]
result <- first_number*second_number
dummy [i,j] <- result
print(result)
}
}
}
Thanks!
Functions don't modify things outside of the function. You should create dummy inside the function, and return the final modified version at the end of your function:
heatmap_prep <- function(vector_a,vector_b){
dummy <- as.data.frame(matrix(0, ncol=length(vector_b), nrow=length(vector_a)))
for (i in 1:length(a)){
first_number <- a[i]
for(j in 1:length(b)){
second_number <- b[j]
result <- first_number*second_number
dummy [i,j] <- result
print(result)
}
}
return(dummy)
}
heatmap_prep(a, b)
# V1 V2 V3 V4 V5
# 1 1 2 3 4 5
# 2 2 4 6 8 10
# 3 3 6 9 12 15
# 4 4 8 12 16 20
# 5 5 10 15 20 25
# 6 6 12 18 24 30
# 7 7 14 21 28 35
# 8 8 16 24 32 40
# 9 9 18 27 36 45
# 10 10 20 30 40 50
However, in this case the built-in outer function is much more succinct. The output is a matrix, but you can easily coerce it to a data.frame.
outer(a, b)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 2 3 4 5
# [2,] 2 4 6 8 10
# [3,] 3 6 9 12 15
# [4,] 4 8 12 16 20
# [5,] 5 10 15 20 25
# [6,] 6 12 18 24 30
# [7,] 7 14 21 28 35
# [8,] 8 16 24 32 40
# [9,] 9 18 27 36 45
# [10,] 10 20 30 40 50
You can also think of this problem as matrix multiplication. This will give the same result.
a %*% t(b)

R Append a list wih assign

I want to define a list that will depend on the loop sequence and append this list with another list
for (i in 4:4) {
nam <- paste0("estim",i)
assign(nam, list(1:10))
assign(paste0(nam,"[2]"),list(11:40))
}
##estim4
##[[1]]
##[1] 1 2 3 4 5 6 7 8 9 10
desired output
## estim4
## [[1]]
## [1] 1 2 3 4 5 6 7 8 9 10
## [[2]]
## [1] 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
## [26] 36 37 38 39 40
any help please?
update
As mentioned by #nicola below this method is difficult to implement and granted the desired output is not exactly what I was asking for. Sorry for the imprecise question.
l <- list()
for (i in 1:1) {
l[i] <- list(list(1:10));
l[[i]][2] <- list(list(letters[1:4]))
}
## l
## [[1]]
## [[1]][[1]]
## [1] 1 2 3 4 5 6 7 8 9 10
## [[1]][[2]]
## [[1]][[2]][[1]]
## [1] "a" "b" "c" "d"
Is there a simpler way to carry variable around?

Converting a two-mode edge list to a one-mode edge list in R

I have a data set that looks like this:
Person Team
10 100
11 100
12 100
10 200
11 200
14 200
15 200
I want to infer who knew one another, based on what teams they were on together. In other words, I want to create a data set that looks like this:
Person1 Person2 Count
10 11 2
10 12 1
11 12 1
10 14 1
10 15 1
11 14 1
11 15 1
The resulting data set captures the dyadic relationships that can be inferred based on the teams that were outlined in the original data set. The "Count" variable reflects the number of instances that a dyad was on a team together. Also, it doesn't matter which ID is listed as Person1 versus Person2, since the relationships are undirected.
One option:
do.call(rbind,tapply(dat$Person,dat$Team,function(x)t(combn(x,2))))
# [,1] [,2]
# [1,] 10 11
# [2,] 10 12
# [3,] 11 12
# [4,] 11 13
# [5,] 11 14
# [6,] 11 15
# [7,] 13 14
# [8,] 13 15
# [9,] 14 15
edit after Op edit :
personaly I would use a specified package like igraph package to do this but here you can do it in 2 steps.
res <-
setNames(do.call(rbind.data.frame,
tapply(dat$Person,dat$Team,
function(x)t(combn(x,2)))),
c('Person1','Person2'))
## compute frequencies of each pair and add it to unique version of res
cbind(unique(res),
Count=as.vector(table(paste(res[,'Person1'],res[,'Person2']))))
# Person1 Person2 Count
# 100.1 10 11 2
# 100.2 10 12 1
# 100.3 11 12 1
# 200.2 10 14 1
# 200.3 10 15 1
# 200.4 11 14 1
# 200.5 11 15 1
# 200.6 14 15 1

get pairwise sums of multiple columns in dataframe

I have a dataframe that looks like this:
x<-data.frame(a=6, b=5:1, c=7, d=10:6)
> x
a b c d
1 6 5 7 10
2 6 4 7 9
3 6 3 7 8
4 6 2 7 7
5 6 1 7 6
I am trying to get the sums of columns a & b and c&d in another data frame that should look like:
> new
ab cd
1 11 17
2 10 16
3 9 15
4 8 14
5 7 13
I've tried the rowSums() function but it returns the sum of ALL the columns per row, and I tried rowSums(x[c(1,2), c(3,4)]) but nothing works. Please help!!
You can use rowSums on a column subset.
As a data frame:
data.frame(ab = rowSums(x[c("a", "b")]), cd = rowSums(x[c("c", "d")]))
# ab cd
# 1 11 17
# 2 10 16
# 3 9 15
# 4 8 14
# 5 7 13
As a matrix:
cbind(ab = rowSums(x[1:2]), cd = rowSums(x[3:4]))
For a wider data frame, you can also use sapply over a list of column subsets.
sapply(list(1:2, 3:4), function(y) rowSums(x[y]))
For all pairwise column combinations:
y <- combn(ncol(x), 2L, function(y) rowSums(x[y]))
colnames(y) <- combn(names(x), 2L, paste, collapse = "")
y
# ab ac ad bc bd cd
# [1,] 11 13 16 12 15 17
# [2,] 10 13 15 11 13 16
# [3,] 9 13 14 10 11 15
# [4,] 8 13 13 9 9 14
# [5,] 7 13 12 8 7 13
Here's another option:
> sapply(split.default(x, 0:(length(x)-1) %/% 2), rowSums)
0 1
[1,] 11 17
[2,] 10 16
[3,] 9 15
[4,] 8 14
[5,] 7 13
The 0:(length(x)-1) %/% 2 step creates a sequence of groups of 2 that can be used with split. It will also handle odd numbers of columns (treating the final column as a group of its own). Since there's a different default split "method" for data.frames that splits by rows, you need to specify split.default to split the columns into groups.

Resources