If I have two vectors of the same length A<-c(5,10) and B<-c(7,13) how can I easily turn these two vectors into a single tuple vector i. e. c((5,7),(7,13))?
Others have mentioned lists. I see other possibilities:
cbind(A, B) # makes a column-major 2x2-"vector"
rbind(A, B) # an row major 2x2-"vector" which could also be added to an array with `abind`
It is also possible to preserve their "origins"
AB <- cbind(A=A, B=B)
array(c(AB,AB+10), c(2,2,2) )
, , 1
[,1] [,2]
[1,] 5 7
[2,] 10 13
, , 2
[,1] [,2]
[1,] 15 17
[2,] 20 23
> abind( array(c(AB,AB+10), c(2,2,2) ), AB+20)
, , 1
A B
[1,] 5 7
[2,] 10 13
, , 2
A B
[1,] 15 17
[2,] 20 23
, , 3
A B
[1,] 25 27
[2,] 30 33
Your tuple vector c((5,7),(7,13)) is not valid syntax. However, your phrasing makes me think you are thinking of something like python's zip. How do you want your tuples represented in R? R has a heterogeneous (recursive) type list and a homogenous type vector; there are no scalar types (that is, types that just hold a single value), just vectors of length 1 (somewhat an oversimplification).
If you want your tuples to be rows of a matrix (all the same type, which they are here):
rbind(A,B)
If you want a list of vectors
mapply(c, A, B, SIMPLIFY=FALSE)
If you want a list of lists (which is what you would need if A and B are not the same type)
mapply(list, A, B, SIMPLIFY=FALSE)
Putting this all together:
> A<-c(5,10)
> B<-c(7,13)
>
> cbind(A,B)
A B
[1,] 5 7
[2,] 10 13
> mapply(c, A, B, SIMPLIFY=FALSE)
[[1]]
[1] 5 7
[[2]]
[1] 10 13
> mapply(list, A, B, SIMPLIFY=FALSE)
[[1]]
[[1]][[1]]
[1] 5
[[1]][[2]]
[1] 7
[[2]]
[[2]][[1]]
[1] 10
[[2]][[2]]
[1] 13
I'm not certain this is exactly what you're looking for, but:
list(A, B)
which gives you a structure like this:
> str(list(A, B))
List of 2
$ : num [1:2] 5 10
$ : num [1:2] 7 13
and is literally represented like this:
dput(list(A, B))
list(c(5, 10), c(7, 13))
... which is about as close to the suggested end result as you can get, I think.
A list in R is essentially a vector of whatever you want it to be.
If that isn't what you're looking for, it might be helpful if you could expand on what exactly you'd like to do with this vector.
I see what you want to accomplish (because I had the same problem)!
Why not use complex numbers because they are basically nothing else but two dimensional numbers and they are an official data type in R with all the necessary methods available:
A <- complex(real=5,imaginary=10)
B <- complex(real=7,imaginary=13)
c(A,B)
## [1] 5+10i 7+13i
matrix(c(A,B),ncol=1)
## [,1]
## [1,] 5+10i
## [2,] 7+13i
Related
I would like to find a way to create a data.frame by using cbind() to join together many separate objects. For example, if A, B, C & D are all vectors of equal length, one can create data.frame ABCD with
ABCD <- cbind(A,B,C,D)
However, when the number of objects to be combined gets large, it becomes tedious to type out all of their names. Furthermore, Is there a way to call cbind() on a vector of object names, e.g.
objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)
or on a list containing all the objects to be combined, e.g.
obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)
Currently, the only workaround I can think of is to use paste(), cat(), write.table(), and source() to construct the arguments to cbind(), write it as a script and source it. This seems like a very nasty kludge. Also, I have looked into do.call() but can't seem to find a way to accomplish what I want with it.
The do.call function is very useful here:
A <- 1:10
B <- 11:20
C <- 20:11
> do.call(cbind, list(A,B,C))
[,1] [,2] [,3]
[1,] 1 11 20
[2,] 2 12 19
[3,] 3 13 18
[4,] 4 14 17
[5,] 5 15 16
[6,] 6 16 15
[7,] 7 17 14
[8,] 8 18 13
[9,] 9 19 12
[10,] 10 20 11
First you need to get the objects you want and store them together as a list; if you can construct their names as strings, you use the get function. Here I create two variables, A and B:
> A <- 1:4
> B <- rep(LETTERS[1:2],2)
I then construct a character vector containing their names (stored as ns) and get these variables using lapply. I then set the names of the list to be the same as their original names.
> (ns <- LETTERS[1:2])
[1] "A" "B"
> obj.list <- lapply(ns, get)
> names(obj.list) <- ns
> obj.list
$A
[1] 1 2 3 4
$B
[1] "A" "B" "A" "B"
Then you can use do.call; the first argument is the function you want and the second is a list with the arguments you want to pass to it.
> do.call(cbind, obj.list)
A B
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"
However, as aL3xa correctly notes, this makes a matrix, not a data frame, which may not be what you want if the variables are different classes; here my A has been coerced to a character vector instead of a numeric vector. To make a data frame from a list, you just call data.frame on it; then the classes of the variables are retained.
> (AB <- data.frame(obj.list))
A B
1 1 A
2 2 B
3 3 A
4 4 B
> sapply(AB, class)
A B
"integer" "factor"
> str(AB)
'data.frame': 4 obs. of 2 variables:
$ A: int 1 2 3 4
$ B: Factor w/ 2 levels "A","B": 1 2 1 2
You should bare in mind, though, that cbind will return an atomic vector (matrix) when applied solely on atomic vectors (double in this case). As you can see in #prasad's and #Aaron's answers, resulting object is a matrix. If you specify other atomic vectors (integer, double, logical, complex) along with character vector, they will get coerced to character. And then you have a problem - you have to convert them to desired classes. So,
if A, B, C & D are all vectors of
equal length, one can create
data.frame ABCD with
ABCD <- data.frame(A, B, C, D)
Perhaps you should ask "how can I easily gather various vectors of equal length and put them in a data.frame"? cbind is great, but sometimes it's not what you're looking for...
You can put all vectors in environment into list using eapply.
obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]
I would like to find a way to create a data.frame by using cbind() to join together many separate objects. For example, if A, B, C & D are all vectors of equal length, one can create data.frame ABCD with
ABCD <- cbind(A,B,C,D)
However, when the number of objects to be combined gets large, it becomes tedious to type out all of their names. Furthermore, Is there a way to call cbind() on a vector of object names, e.g.
objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)
or on a list containing all the objects to be combined, e.g.
obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)
Currently, the only workaround I can think of is to use paste(), cat(), write.table(), and source() to construct the arguments to cbind(), write it as a script and source it. This seems like a very nasty kludge. Also, I have looked into do.call() but can't seem to find a way to accomplish what I want with it.
The do.call function is very useful here:
A <- 1:10
B <- 11:20
C <- 20:11
> do.call(cbind, list(A,B,C))
[,1] [,2] [,3]
[1,] 1 11 20
[2,] 2 12 19
[3,] 3 13 18
[4,] 4 14 17
[5,] 5 15 16
[6,] 6 16 15
[7,] 7 17 14
[8,] 8 18 13
[9,] 9 19 12
[10,] 10 20 11
First you need to get the objects you want and store them together as a list; if you can construct their names as strings, you use the get function. Here I create two variables, A and B:
> A <- 1:4
> B <- rep(LETTERS[1:2],2)
I then construct a character vector containing their names (stored as ns) and get these variables using lapply. I then set the names of the list to be the same as their original names.
> (ns <- LETTERS[1:2])
[1] "A" "B"
> obj.list <- lapply(ns, get)
> names(obj.list) <- ns
> obj.list
$A
[1] 1 2 3 4
$B
[1] "A" "B" "A" "B"
Then you can use do.call; the first argument is the function you want and the second is a list with the arguments you want to pass to it.
> do.call(cbind, obj.list)
A B
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"
However, as aL3xa correctly notes, this makes a matrix, not a data frame, which may not be what you want if the variables are different classes; here my A has been coerced to a character vector instead of a numeric vector. To make a data frame from a list, you just call data.frame on it; then the classes of the variables are retained.
> (AB <- data.frame(obj.list))
A B
1 1 A
2 2 B
3 3 A
4 4 B
> sapply(AB, class)
A B
"integer" "factor"
> str(AB)
'data.frame': 4 obs. of 2 variables:
$ A: int 1 2 3 4
$ B: Factor w/ 2 levels "A","B": 1 2 1 2
You should bare in mind, though, that cbind will return an atomic vector (matrix) when applied solely on atomic vectors (double in this case). As you can see in #prasad's and #Aaron's answers, resulting object is a matrix. If you specify other atomic vectors (integer, double, logical, complex) along with character vector, they will get coerced to character. And then you have a problem - you have to convert them to desired classes. So,
if A, B, C & D are all vectors of
equal length, one can create
data.frame ABCD with
ABCD <- data.frame(A, B, C, D)
Perhaps you should ask "how can I easily gather various vectors of equal length and put them in a data.frame"? cbind is great, but sometimes it's not what you're looking for...
You can put all vectors in environment into list using eapply.
obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]
I would like to find a way to create a data.frame by using cbind() to join together many separate objects. For example, if A, B, C & D are all vectors of equal length, one can create data.frame ABCD with
ABCD <- cbind(A,B,C,D)
However, when the number of objects to be combined gets large, it becomes tedious to type out all of their names. Furthermore, Is there a way to call cbind() on a vector of object names, e.g.
objs <- c("A", "B", "C", "D")
ABCD <- cbind(objs)
or on a list containing all the objects to be combined, e.g.
obj.list <- list(A,B,C,D)
ABCD <- cbind(obj.list)
Currently, the only workaround I can think of is to use paste(), cat(), write.table(), and source() to construct the arguments to cbind(), write it as a script and source it. This seems like a very nasty kludge. Also, I have looked into do.call() but can't seem to find a way to accomplish what I want with it.
The do.call function is very useful here:
A <- 1:10
B <- 11:20
C <- 20:11
> do.call(cbind, list(A,B,C))
[,1] [,2] [,3]
[1,] 1 11 20
[2,] 2 12 19
[3,] 3 13 18
[4,] 4 14 17
[5,] 5 15 16
[6,] 6 16 15
[7,] 7 17 14
[8,] 8 18 13
[9,] 9 19 12
[10,] 10 20 11
First you need to get the objects you want and store them together as a list; if you can construct their names as strings, you use the get function. Here I create two variables, A and B:
> A <- 1:4
> B <- rep(LETTERS[1:2],2)
I then construct a character vector containing their names (stored as ns) and get these variables using lapply. I then set the names of the list to be the same as their original names.
> (ns <- LETTERS[1:2])
[1] "A" "B"
> obj.list <- lapply(ns, get)
> names(obj.list) <- ns
> obj.list
$A
[1] 1 2 3 4
$B
[1] "A" "B" "A" "B"
Then you can use do.call; the first argument is the function you want and the second is a list with the arguments you want to pass to it.
> do.call(cbind, obj.list)
A B
[1,] "1" "A"
[2,] "2" "B"
[3,] "3" "A"
[4,] "4" "B"
However, as aL3xa correctly notes, this makes a matrix, not a data frame, which may not be what you want if the variables are different classes; here my A has been coerced to a character vector instead of a numeric vector. To make a data frame from a list, you just call data.frame on it; then the classes of the variables are retained.
> (AB <- data.frame(obj.list))
A B
1 1 A
2 2 B
3 3 A
4 4 B
> sapply(AB, class)
A B
"integer" "factor"
> str(AB)
'data.frame': 4 obs. of 2 variables:
$ A: int 1 2 3 4
$ B: Factor w/ 2 levels "A","B": 1 2 1 2
You should bare in mind, though, that cbind will return an atomic vector (matrix) when applied solely on atomic vectors (double in this case). As you can see in #prasad's and #Aaron's answers, resulting object is a matrix. If you specify other atomic vectors (integer, double, logical, complex) along with character vector, they will get coerced to character. And then you have a problem - you have to convert them to desired classes. So,
if A, B, C & D are all vectors of
equal length, one can create
data.frame ABCD with
ABCD <- data.frame(A, B, C, D)
Perhaps you should ask "how can I easily gather various vectors of equal length and put them in a data.frame"? cbind is great, but sometimes it's not what you're looking for...
You can put all vectors in environment into list using eapply.
obj.list <- eapply(.GlobalEnv,function(x) if(is.vector(x)) x)
obj.list <- obj.list[names(obj.list) %in% LETTERS]
I have a list object in R that contains further lists, of three vectors each. What is the quickest way to generate three matrices, the first of which has all of the first vectors as rows, the second has all of the second vectors as rows, and the third has all of the third? For example, given:
metalist <- list(list(c(1,1),c(11,11),c("a","a")),
list(c(2,2),c(22,22),c("b","b")),
list(c(3,3),c(33,33),c("c","c")))
I would like to get to three matrices (or data.frames), the first consisting of:
1 1
2 2
3 3
The second consisting of
11 11
22 22
33 33
And the third consisting of
a a
b b
c c
Given that in reality the metalist has 50,000 list objects, a for loop that extracts the vector elements and progressively assembles the matrices takes forever, so I would be looking for something quicker. I'm guessing there may be some clever use of unlist() but I can't figure it out.
The pattern do.call(Map,c(f=___,...)) is a useful one to have in your toolbox. Using list in the blank "transposes" the structure, using rbind will produce your desired matrices:
do.call(Map,c(f=rbind,metalist))
[[1]]
[,1] [,2]
[1,] 1 1
[2,] 2 2
[3,] 3 3
[[2]]
[,1] [,2]
[1,] 11 11
[2,] 22 22
[3,] 33 33
[[3]]
[,1] [,2]
[1,] "a" "a"
[2,] "b" "b"
[3,] "c" "c"
The following will create a list of three matrices:
my_outcome <- list()
for (i in 1:3)
{
my_outcome[[i]] <- t(as.data.frame(lapply(metalist, `[[`, i)))
}
It does use a loop, but only over the number of matrices, so it should work in your case.
If you would like to completely ignore for loops, the following also gets the job done:
lapply(1:3, function(y) {
do.call(rbind,lapply(metalist, function(x) x[[y]]))
})
i'm developing a function to perform operations between two vectors (dataframes, for example), using the function "for":
> A <- c(1,2,3)
> B <- c(2)
> result <- c()
> for (i in 1:length(A))
+ {
+ for (j in 1:length(B))
+ {
+ result <- (A*B)
+ }
+ }
> result
[1] 2 4 6
However, when I increase the vector "B" to 2 values:
> A <- c(1,2,3)
> B <- c(2,4)
the function generates
Warning messages lost:
"Major object length is not a multiple of the length of a lower one."
> result
[1] 2 8 6
So, how i can create a loop that performs the operation against "A" for each row "B"?
Thnaks so much!
In your loop, you don't use the variables i and j but calculate the product A * B instead.
You can produce the desired result using sapply:
A=c(1,2,3); B=c(2,4)
sapply(A, "*", B)
# [,1] [,2] [,3]
# [1,] 2 4 6
# [2,] 4 8 12
or matrix multiplication:
A %*% t(B)
# [,1] [,2]
# [1,] 2 4
# [2,] 4 8
# [3,] 6 12
As the error says, A's length has to be a multiple of B's one : if they have the same length, A*Bwill return a vector of same length whose terms will the multiplications of corresponding elements of A and B (A[1]*B[1],...A[n]*B[n]).
If length(A)=k*length(B), k>1, you will get a vector with same length as A with (A[1]*B[1]...A[l]*B[l],A[l+1]*B[1],A[l+2]*B[2]...A[kl]*B[l]), where l is B length and therefore kl is A length.
Here, 3 is a multiple of 1 but not of 2, hence the error you get.
In general, you can use outer:
outer(A, B, FUN='*')
# [,1] [,2]
# [1,] 2 4
# [2,] 4 8
# [3,] 6 12