Una función básica de R

In reading R for programmers I saw this function

oddcount <- function(x) {
  k <- 0
  for (n in x) {
    if (n %% 2 == 1) k <- k+1
  }
  return(k)
}

I would prefer to write it in a simpler style (i.e in lisp)

(defn odd-count [xs]
  (count (filter odd? xs)))

I see the function length is equivalent to count and I can write odd? so are there built-in map/filter/remove type functions?

preguntado el 31 de julio de 12 a las 12:07

3 Respuestas

In R, when you are working with vectors, people often prefer to work on the entire vector at once instead of looping through it (see, for example, este discusión).

In a sense, R does have "built in" filter and reduce functions: the way in which you can select subsets of a vector. They are very handy in R, and there are a few ways to go about it - I'll show you a couple, but you'll pick up more if you read about R and look at other people's code on a site like this. I would also consider looking at ?which y ?'[', which has more examples than I do here.

The first way is simply to select which elements you want. You can use this if you know the indices of the elements you want:

x <- letters[1:10]
> x
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"

If we only want the first five letters, we can write:

x[1:5]
x[c(1,2,3,4,5)] # a more explicit version of the above

You can also select which elements you no want by using a minus sign, for example:

 x[-(6:10)]

Another way to select elements is by using a boolean vector:

x <- 1:5
selection <- c(FALSE, TRUE, FALSE, TRUE, FALSE)
x[selection]   # only the second and fourth elements will remain

This is important because we can create such a vector by putting a vector in a comparison function:

selection <- (x > 3)
> selection
 [1] FALSE FALSE FALSE  TRUE  TRUE

x[selection]   # select all elements of x greater than 3
x[x > 3]       # a shorthand version of the above

Once again, we can select the opposite of the comparison we use (note that since it is boolean, we use ! y no -):

x[!(x > 3)]    # select all elements less than or equal to 3

If you want to do vector comparisons, you should consider the %in% función. Por ejemplo:

x <- letters[1:10]
> x %in% c("d", "p", "e", "f", "y")
 [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE

# Select all elements of x that are also "d", "p", "e", "f", or "y"
x[x %in% c("d", "p", "e", "f", "y")]  
# And to select everything not in that vector:
x[!(x %in% c("d", "p", "e", "f", "y"))]  

The above are only a few examples; I would definitely recommend the documentation. I know this is a long post after you have already accepted an answer, but this sort of thing is very important and understanding it is going to save you a lot of time and pain in the future if you are new to R, so I thought I'd share a couple of ways of doing it with you.

contestado el 23 de mayo de 17 a las 13:05

Thanks, this is definitely helpful. - CrisR

A more R way to doing this would be to avoid the for loop, and use vectorization:

oddcount <- function(x) {
  sum(x %% 2)
}

La comparación entre x and 2 outputs a vector as x itself is a vector. Sum than calculates the sum of the vector, where TRUE es igual a 1 y FALSE equals zero. In this way the function calculates the number of odd numbers in the vector.

This already leads to more simple syntax, although for non-vectorization-oriented people the for loop tends to be easier to read. I greatly prefer the vectorized syntax as it is much shorter. I would prefer to use a more descriptive name for x aunque, por ejemplo number_vector.

respondido 14 mar '13, 22:03

In this case it could be even shorter, you don't realy need the ==1 desde %% will only be returning 0's and 1's. Use sum(x %% 2). This might also be a little bit quicker since you are not generating logicals and ther converting them back to numeric. Some may find the longer version more readable ( and if you were to expand this to looking for numbers that are or are not multiples of something other than 2 then you would need the longer version. - Greg nieve

Deberías echar un vistazo a funprog biblioteca, que incluye map, filter, reduce etc.

Respondido 31 Jul 12, 12:07

Thanks, length(Filter(odd_p, xs)) seems to do the job, it seems I was asking the wrong question based on the last answer however :) - CrisR

There is nothing wrong with use funprog, but using standard R you can get the same shortness in code. - Pablo Hiemstra

That's a good point, @Paul. Trying to force a language that uses one paradigm (vectorized) into another paradigm (functional) often results in needlessly verbose code. - Chris Taylor

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.