D L Dahly
D L Dahly

Reputation: 560

R: referring to colnames within a function

I want to apply a function to all columns of a dataframe. Within that function, I want to use the respective colnames. However, these are lost - how do I keep them, or otherwise refer to them within the function?

data <- data.frame("A" = rnorm(500, 0, 1), 
                   "B" = rnorm(500, 0, 1))

funk <- function(x,...){
  paste(colnames(x), " & ", round(mean(x, na.rm = T), 1), sep = "")
}

lapply(data, funk)

Gives:

$A
[1] " & -0.1"

$B
[1] " & 0.1"

But I want:

$A
[1] "A & -0.1"

$B
[1] "B & 0.1"

Upvotes: 0

Views: 209

Answers (3)

Rich Scriven
Rich Scriven

Reputation: 99331

Since paste is vectorized, you can use colMeans with it and not have to loop anything.

paste(names(data), " & ", round(colMeans(data), 1))

So I'd probably write the function like this:

funk <- function(x, digits = 1L, na.rm = TRUE) {
    means <- round(colMeans(x, na.rm = na.rm), digits = digits)
    setNames(as.list(paste(names(x), " & ", means)), names(x))
}
funk(data)
# $A
# [1] "A  &  0"
#
# $B
# [1] "B  &  0"

funk(data, digits = 3)
# $A
# [1] "A  &  0.023"
#
# $B
# [1] "B  &  -0.046"

But from your comment it seems like you might be wondering how to apply the names one-to-one while you're applying a function. For that you might want to look at Map and/or mapply

Map(paste, names(data), " & ", round(colMeans(data), 3))
# $A
# [1] "A  &  0.023"
#
# $B
# [1] "B  &  -0.046"

Upvotes: 2

nicola
nicola

Reputation: 24480

You don't need a lapply if you use colMeans instead of mean:

   funk <- function(x,...){
     paste(colnames(x), " & ", round(colMeans(x, na.rm = T), 1), sep = "")
   }

And then just:

  funk(data)

Edit: the above will give you a simple character vector as output. If you want a list with names as per your desired output, just define funk as follow:

  funk <- function(x,...){
     setNames(as.list(paste(colnames(x), " & ", round(colMeans(x, na.rm = T), 1), sep = "")),names(x))
  }  

Upvotes: 3

akrun
akrun

Reputation: 887118

You can try

lapply(seq_len(ncol(data)), function(i) 
    paste(colnames(data[i]), " & " , round(mean(data[,i], 
                                      na.rm=TRUE), 1), sep=""))

Upvotes: 1

Related Questions