I would appreciate insight into why this happens and how I might do this more eloquently.
When I use sapply, I would like it to return a 3x2 matrix, but it returns a 2x3 matrix. Why is this? And why is it difficult to attach this to another data frame?
a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1))
out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')])
#out is 3x2, but I would like it to be 2x3
#I then want to append t(out) (out as a 2x3 matrix) to b, a 1x3 dataframe
b <- data.frame(var3=c(0,0,0))
when I try to attach these,
b[,c('col2','col3')] <- t(out)
The error that I get is:
Warning message:
In `[<-.data.frame`(`*tmp*`, , c("col2", "col3"), value = list(1, :
provided 6 variables to replace 2 variables
although the following appears to give the desired result:
rownames(out) <- c('col1', 'col2')
b <- cbind(b, t(out))
I can not operate on the variables:
b$var1/b$var2
returns
Error in b$var1/b$var2 : non-numeric argument to binary operator
Thanks!
The real reason for this is that sapply doesn't know what your function will return without calling it. In your case the function returns a logical , but since sapply is given an empty list, the function is never called. Therefore, it has to come up with a type and it defaults to list .
To interchange rows with columns, you can use the t() function. For example, if you have the matrix (or dataframe) mat you can transpose it by typing t(mat) . This will, as previously hinted, result in a new matrix that is obtained by exchanging the rows and columns.
Rotating or transposing R objects You can rotate the data. frame so that the rows become the columns and the columns become the rows. That is, you transpose the rows and columns. You simply use the t() command.
Thus, to convert columns of an R data frame into rows we can use transpose function t. For example, if we have a data frame df with five columns and five rows then we can convert the columns of the df into rows by using as. data. frame(t(df)).
To expand on DWin's answer: it would help to look at the structure of your out
object. It explains why b$var1/b$var2
doesn't do what you expect.
> out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')])
> str(out) # this isn't a data.frame or a matrix...
List of 6
$ : num 1
$ : num 3
$ : num 2
$ : num 2
$ : num 3
$ : num 1
- attr(*, "dim")= int [1:2] 2 3
- attr(*, "dimnames")=List of 2
..$ : chr [1:2] "var1" "var2"
..$ : NULL
The apply
family of functions are designed to work on vectors and arrays, so you need to take care when using them with data.frames (which are usually lists of vectors). You can use the fact that data.frames are lists to your advantage with lapply
.
> out <- lapply(a$id, function(x) a[x, c('var1', 'var2')]) # list of data.frames
> out <- do.call(rbind, out) # data.frame
> b <- cbind(b,out)
> str(b)
'data.frame': 3 obs. of 4 variables:
$ var3: num 0 0 0
$ var1: num 1 2 3
$ var2: num 3 2 1
$ var3: num 0 0 0
> b$var1/b$var2
[1] 0.3333333 1.0000000 3.0000000
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With