Reputation: 655
I'm attempting to learn how to use Rcpp in R. Can someone please point out what the problem/s are with this code. There's probably more than one issue.
When the c
object is entered into fun()
at the bottom of the code I want it to output a vector/array with the values "Home", "Elsewhere" or "Number".
I'm finding the data type slightly confusing here. My original data set is a factor. If I put this into storage.mode()
it returns integer
. I assume then that I have to assign the x
argument as IntegerVector
. This confuses me because the data contains letters, i.e "H" and "E", so how can the data be integer?
When I'm saying == "H" in the if statement i don't know if it understands what I'm saying.
library(Rcpp)
c <- factor(c("E", "H", "E", "12", "10", "60", "80", "11", "H", "H"))
class(c)
storage.mode(c)
cppFunction(' IntegerVector fun(IntegerVector x){
// creates an empty character vector the size/length of x.
CharacterVector y = x.size() ;
int n = x.size() - 1 ;
//loop
for(int i = 0; i <= n; i = i + 1){
if(x[i] == "H"){
y[i] = "Home" ;
}else if(x[i] == "E"){
y[i] = "Elsewhere" ;
}else{
y[i] = "Number" ;
} ;
}
return y ;
}')
fun(c)
Upvotes: 4
Views: 443
Reputation: 16930
Note: Throughout, I will refer to f
, not c
. It is bad practice to name variables the same name as a builtin function or constant, such as c
, T
, or F
. Therefore I change the beginning of your code as follows:
library(Rcpp)
f <- factor(c("E", "H", "E", "12", "10", "60", "80", "11", "H", "H"))
In addition to looking at class(f)
and storage.mode(f)
, it's useful to look at str(f)
:
str(f)
# Factor w/ 7 levels "10","11","12",..: 6 7 6 3 1 4 5 2 7 7
In truth, a factor is an integer vector with "levels": a character vector corresponding to each unique integer value. Luckily, you can get this from C++ using the .attr()
member function of Rcpp::IntegerVector
:
cppFunction('CharacterVector fun(IntegerVector x){
// creates an empty character vector the size/length of x.
CharacterVector y = x.size() ;
// Get the levels of x
CharacterVector levs = x.attr("levels");
int n = x.size() - 1 ;
//loop
for(int i = 0; i <= n; i = i + 1){
if(levs[x[i]-1] == "H"){
y[i] = "Home" ;
}else if(levs[x[i]-1] == "E"){
y[i] = "Elsewhere" ;
}else{
y[i] = "Number" ;
} ;
}
return y ;
}')
fun(f)
# [1] "Elsewhere" "Home" "Elsewhere" "Number" "Number" "Number"
# [7] "Number" "Number" "Home" "Home"
So, to get what you want, you had to do three things:
IntegerVector
to CharacterVector
(though you were completely right that the input should be IntegerVector
)CharacterVector levs = x.attr("levels");
levs[x[i]-1]
to "H"
, etc., rather than x[i]
-- x[i]
will always be an integer, giving the element of the vector of levels it corresponds to. We do -1
since C++ is 0-indexed and R is 1-indexed.Other notes:
It is clear, as you say, that "[you're] attempting to learn how to use Rcpp() in R." You'll definitely want to spend some time with resources such as Rcpp for Everyone (that's the chapter on factors), the Rcpp Gallery (this specific link is an article on factors), Hadley's chapter on Rcpp, and definitely the Rcpp vignettes available here.
Upvotes: 7