2

I am applying a function onto a dataframe.

But unlike sapply and its friends, apply hasn't got any USE.NAME argument to get a named list as returned object.

In this example, I'd like the C column to be the names of the returned list :

df = data.frame(A=c(1,2,3), B=c(9,5,7), C=c("A", "Z", "E"))
apply(df, 1, function(x){
  data.frame(xxx=as.numeric(x[1]) * as.numeric(x[2]))
})
# [[1]]
# xxx
# 1   9
# 
# [[2]]
# xxx
# 1  10
# 
# [[3]]
# xxx
# 1  21

How can I achieve this ?

Dan Chaltiel
  • 7,811
  • 5
  • 47
  • 92

4 Answers4

3

You could do:

apply(data.frame(df, row.names = df$C), 1, function(x){
  data.frame(xxx=as.numeric(x[1]) * as.numeric(x[2]))
})
#$A
#  xxx
#1   9
#
#$Z
#  xxx
#1  10
#
#$E
#  xxx
#1  21

Explanation: apply picks up list names from the dimnames of your corresponding MARGIN of your data.frame (in your case MARGIN=1, so list names will correspond to rownames).

Maurits Evers
  • 49,617
  • 4
  • 47
  • 68
2

or use setNames() after you call apply:

 setNames(apply(df, 1, function(x) {
                         data.frame(xxx=as.numeric(x[1]) * as.numeric(x[2])) 
                       }), df$C)
Nate
  • 10,361
  • 3
  • 33
  • 40
1

If the output should be the product of two columns in a list, then it can be done with Reduce

lst <- as.list(Reduce(`*`, df[-3]))
names(lst) <- df[,3]

Or with tidyverse

library(tidyverse)
df %>% 
   transmute(xxx = A * B, C) %>% 
   split(.$C) %>% 
   map(~.x %>% 
      select(xxx))

Or with nest

df %>% 
   transmute(xxx = A * B, C) %>%
   nest(xxx)  %>% 
   mutate(data = set_names(data, C)) %>% 
   pull(data)
#$A
#   xxx
#1   9

#$Z
#   xxx
#2  10

#$E
#   xxx
#3  21
akrun
  • 874,273
  • 37
  • 540
  • 662
  • I wanted to know how to set names to a `apply` output, and I gave a reproducible example for testing. Your answer would be correct if my question was "how to multiply 2 columns and get the result as a named list". Still interesting though, thanks for answering. – Dan Chaltiel Apr 01 '18 at 16:23
0

You don't need the apply-function for this. You can just do:

 setNames(as.list(df[[1]] * df[[2]]), df[[3]])

The result:

$A
[1] 9

$Z
[1] 10

$E
[1] 21
h3rm4n
  • 4,126
  • 15
  • 21
  • Same comment as for Akrun, this is right about my example, but quite off-topic about my question. Thanks for answering though. – Dan Chaltiel Apr 01 '18 at 16:22