Can someone explain what's happening in this example code? I have a function which does a calculation loop and as always, wanted to initialize my output vector instead of incrementing it each time thru the loop.
Rgames> library(Rmpfr)
Rgames> foo<-rep(NA,5)
Rgames> foo
[1] NA NA NA NA NA
Rgames> rfoo<-mpfr(rep(NA,5),20)
Rgames> rfoo
5 'mpfr' numbers of precision 20 bits
[1] NaN NaN NaN NaN NaN
Rgames> for(jj in 1:5) {
+ foo[jj]<- mpfr(jj,10)
+ rfoo[jj]<-mpfr(jj,10)
+ }
Rgames> rfoo
5 'mpfr' numbers of precision 10 bits
[1] 1 2 3 4 5
Rgames> foo
[[1]]
'mpfr1' 1
[[2]]
'mpfr1' 2
[[3]]
'mpfr1' 3
[[4]]
'mpfr1' 4
[[5]]
'mpfr1' 5
I don't understand why, apparently, the existing non-mpfr vector foo is not only coerced to a list, but then each time through the loop, the new value is inserted into foo[jj] as a list, giving me an unpleasant "list of lists" . The mpfr vector rfoo does what I expected I'd get in both cases. (I checked, and if I do not initialize, and put something inside the loop like foo<-c(foo,mpfr(jj,10)) I do get a result equivalent to rfoo)
What's happening here is the same thing that would happen if you were working with lists instead of mpfr objects. For example, as follows. I believe this makes sense because S4 objects are stored in a similar way to lists, but I'm not an S4 expert.
> foo <- rep(NA,2)
> foo
[1] NA NA
> foo[1] <- list(1)
> foo
[[1]]
[1] 1
[[2]]
[1] NA
I believe that what happens is that the original atomic vector gets coerced to a list to be able to include the object that you've asked to put there. I can't find any documentation about that right here; I think it's discussed in Chambers's book but don't have that at hand.
One can easily recreate this behavior using S3 methods as well; first the S3 methods to create a new class:
mynum <- function(x) {structure(as.list(x), class="mynum")}
print.mynum <- function(x) { cat("My numbers are:\n")
print(do.call(paste, x), quote=FALSE) }
Here's what happens if you start with an atomic vector:
> (foo <- rep(NA, 2))
[1] NA NA
> foo[1] <- mynum(1)
> foo
[[1]]
[1] 1
[[2]]
[1] NA
and here's what happens if you start with the mynum vector:
> (rfoo <- mynum(rep(NA, 2)))
My numbers are:
[1] NA NA
> rfoo[1] <- mynum(1)
> rfoo
My numbers are:
[1] 1 NA
Related
I want to sort vectors in a list. I tried the following:
test <- list(c(2,3,1), c(3,2,1), c(1,2,3))
for (i in length(test)){
test[[i]] <- sort(test[[i]])
}
test
Which returns the list unchanged (vectors not sorted):
[[1]]
[1] 2 3 1
[[2]]
[1] 3 2 1
[[3]]
[1] 1 2 3
However when I sort manually outside the loop the order is stored:
test[[1]]
[1] 2 3 1
test[[1]] <- sort(test[[1]])
test[[1]]
[1] 1 2 3
Why does the behaviour in the loop differ? I would expect the loop to store three vectors c(1,2,3) in the list. What am I missing?
I just figured the loop only loops over one element since length(test) = 3. Hence I should have used for (i in 1:length(test)).
Let's suppose I have a list:
[[1]]
[1] 0.7125856 -1.4871811 0.6230076 1.0756424 0.8172592 -0.1327926 -0.7674947 -1.0738684 1.5706677
[10] -0.6674960
[[2]]
[1] -0.5778682 -1.1186447 0.8272505 0.5123162 0.6607654 1.6559877 -0.7961859 -0.8966686
[[3]]
[1] -1.42867999 -0.21142100 -2.89762370 0.11036288 0.66846399 -0.77309213 0.35278541 -0.99579117 -0.73043142
[10] -0.01857864 -0.93654969 0.46751328
[[4]]
[1] -0.483896685 -0.207550362 -0.902920637 -0.008191134 -1.015636093
And I also have a vector with indices of so-called "central" values of vectors in this list:
[1] 2 4 5 1
What I'm trying to get is for given range (for example, 3) get subsets of vectors around those centers with the length of range in both sides. So every subset must be length of 7 and if range extends beyond length of vector there must be NAs added:
[[1]]
[1] NA NA 0.7125856 [-1.4871811] 0.6230076 1.0756424 0.8172592
[[2]]
[1] -0.5778682 -1.1186447 0.8272505 [0.5123162] 0.6607654 1.6559877 -0.7961859
[[3]]
[1] -0.2114210 -2.8976237 0.1103629 [0.6684640] -0.7730921 0.3527854 -0.9957912
[[4]]
[1] NA NA NA [-0.483896685] -0.207550362 -0.902920637 -0.008191134
I put centers in brackets, because SO doesn't allow bold text in a code. Is there a way to do something like this in R?
I think you're looking for something like this?
Data:
n <- 10
x <- list(rnorm(n),rnorm(n),rnorm(n),rnorm(n))
i <- c(2,4,5,1)
r <- 3
Possible solution:
f <- function(x) ifelse((x-r):(x+r) %in% 1:n,(x-r):(x+r),NA)
tmp <- lapply(i,f)
out <- mapply("[",x,tmp)
split(out,col(out))
$`1`
[1] NA NA 0.8120232 0.4980624 -2.9708413 0.6754918 -0.9900322
$`2`
[1] -1.0303741 -1.7432638 0.9466315 -1.3322712 -1.7281613 -0.1951453 0.3789493
$`3`
[1] -1.4120119 0.3675425 -0.8378275 -1.1080856 -0.9369994 1.0823376 1.2194782
$`4`
[1] NA NA NA 0.1757164 -1.5768032 0.3121876 0.4443616
I'm returning to R after some time, and the following has me stumped:
I'd like to build a list of the positions factor values have in the facor levels list.
Example:
> data = c("a", "b", "a","a","c")
> fdata = factor(data)
> fdata
[1] a b a a c
Levels: a b c
> fdata$lvl_idx <- ????
Such that:
> fdata$lvl_idx
[1] 1 2 1 1 3
Appreciate any hints or tips.
If you convert a factor to integer, you get the position in the levels:
as.integer(fdata)
## [1] 1 2 1 1 3
In certain situations, this is counter-intuitive:
f <- factor(2:4)
f
## [1] 2 3 4
## Levels: 2 3 4
as.integer(f)
## [1] 1 2 3
Also if you silently coerce to integer, for example by using a factor as a vector index:
LETTERS[2:4]
## [1] "B" "C" "D"
LETTERS[f]
## [1] "A" "B" "C"
Converting to character before converting to integer gives the expected values. See ?factor for details.
The solution provided years ago by Matthew Lundberg is not robust. It could be that the as.integer() function was defined for a specific S3 type of factors. Imagine someone would create a new factor class to keep operators like >=.
as.myfactor <- function(x, ...) {
structure(as.factor(x), class = c("myfactor", "factor"))
}
# and that someone would create an S3 method for integers - it should
# only remove the operators, which makes sense...
as.integer.myfactor <- function(x, ...) {
as.integer(gsub("(<|=|>)+", "", as.character(x)))
}
Now this is not working anymore, - it just removes operators:
f <- as.myfactor(">=2")
as.integer(f)
#> [1] 2
But this is robust with any factor you want to know the index of the level of, using which():
f <- factor(2:4)
which(levels(f) == 2)
#> [1] 1
I have a list, and would like to break the elements of the list into seperate objects in the global environment.
For example, I would like the list:
obj <- list(a=1:5, b=2:10, c=-5:5)
to be three seperate objects a, b, and c.
I tried to achieve this with:
lapply(obj, FUN = function(x) names(x)[1] <<- x[1])
But it failed, with Error in names(x)[1] <<- x[1] : object 'x' not found.
How might I achieve my aim?
There is special function for mapping list to environment:
> obj <- list(a=1:5, b=2:10, c=-5:5)
> ls()
[1] "obj"
> list2env(obj,globalenv())
<environment: R_GlobalEnv>
> ls()
[1] "a" "b" "c" "obj"
P. S. It is my comment provided as an answer
This also would work:
lapply(seq_along(obj), function(i) assign(names(obj)[i], obj[[i]], envir = .GlobalEnv))
In case the list isn't yet a named list, we need to set names first, e.g. with incrementing letters.
obj2 <- list(1:5, 2:10, -5:5)
list2env(setNames(obj2, letters[seq(obj2)]), envir=.GlobalEnv)
ls()
# [1] "a" "b" "c" "obj2"
I don't recommend it but you could use attach
> obj <- list(a=1:5, b=2:10, c=-5:5)
> attach(obj)
> a
[1] 1 2 3 4 5
> b
[1] 2 3 4 5 6 7 8 9 10
> c
[1] -5 -4 -3 -2 -1 0 1 2 3 4 5
I use apply to a matrix in order to apply a function row by row.
My syntax is as follows :
res = apply(X,1,MyFunc)
The above function MyFunc returns a list of two values.
But the result of this apply application is a strange structure, where R seems to add some of its own (housekeeping?) data :
res = $`81`
$`81`$a
[1] 80.8078
$`81`$b
[1] 6247
Whereas the result I am waiting for is simply :
res = $a
[1] 80.8078
$b
[1] 6247
I do not know why this strange 81 is inserted by R and how can I get rid of it.
Thanks for help
This is perfectly normal behaviour. You are applying a function over a matrix with named rows. Your function returns a list for each row, and each element in this new list of lists is named with the corresponding rowname.
Here is an example that reproduces what you describe:
x <- matrix(1:4, nrow=2)
rownames(x) <- 80:81
myFunc <- function(x)list(a=1, b=2)
xx <- apply(x, 1, myFunc)
xx
This returns:
$`80`
$`80`$a
[1] 1
$`80`$b
[1] 2
$`81`
$`81`$a
[1] 1
$`81`$b
[1] 2
Take a look at the structure of this list:
str(xx)
List of 2
$ 80:List of 2
..$ a: num 1
..$ b: num 2
$ 81:List of 2
..$ a: num 1
..$ b: num 2
To index the first element, simply use xx[[1]]:
xx[[1]]
$a
[1] 1
$b
[1] 2
Here is a guess as to what you may have intended... Rather than returning a list, if you return a vector, the result of the apply will be a matrix:
myFunc <- function(x)c(a=1, b=2)
apply(x, 1, myFunc)
80 81
a 1 1
b 2 2
And to get a specific row, without names, do:
unname(xx[2, ])
[1] 2 2
It would help to know what your matrix (X) looks like. Let's try something like this:
mf <- function(x) list(a=sum(x),b=prod(x))
mat <- matrix(1:6,nrow=2)
Then:
> apply(mat,1,mf)
[[1]]
[[1]]$a
[1] 9
[[1]]$b
[1] 15
[[2]]
[[2]]$a
[1] 12
[[2]]$b
[1] 48
You need that first subscript to differentiate between the lists that each row will generate. I suspect that your rownames are numbered, which results in the $`81` that you are seeing.