Reputation: 1600
I'm trying to return a list using mutate and rowwise but get the error shown in the code. These questions Q1 Q2 helped, but I'd like to keep it simple by iterating over rows using rowwise()
, and the questions are 3yr 7mth old. Thanks.
library(tidyverse)
df <- data.frame(Name=c("a","a","b","b","c"),X=c(1,2,3,4,5), Y=c(2,3,4,2,2))
TestFn <- function(X,Y){
Z <- list(X*5,Y/2,X+Y,X*2+5*Y)
return (Z)
}
#this works
SingleResult <- TestFn(5,20)
#error - Error in mutate_impl(.data, dots) : incompatible size (4), expecting 1 (the group size) or 1
dfResult <- df %>%
rowwise() %>%
mutate(R=TestFn(X,Y))
Upvotes: 2
Views: 1046
Reputation: 13591
tidyverse
lets you nest complicated data structures now
tidyverse solution
df %>%
mutate(copyX = X, copyY = Y) %>%
nest(copyX, copyY) %>%
mutate(data = map(data, ~TestFn(.x$copyX, .x$copyY)))
output
Name X Y data
<fctr> <dbl> <dbl> <list>
1 a 1 2 <list [4]>
2 a 2 3 <list [4]>
3 b 3 4 <list [4]>
4 b 4 2 <list [4]>
5 c 5 2 <list [4]>
How to convert to data frame?
Since your function returns a list, I added an additional step before unnest
ing
df %>%
mutate(copyX = X, copyY = Y) %>%
nest(copyX, copyY) %>%
mutate(data = map(data, ~TestFn(.x$copyX, .x$copyY))) %>%
mutate(data = map(data, ~unlist(.x))) %>%
unnest(data)
output
Name X Y data
<fctr> <dbl> <dbl> <dbl>
1 a 1 2 5.0
2 a 1 2 1.0
3 a 1 2 3.0
4 a 1 2 12.0
5 a 2 3 10.0
6 a 2 3 1.5
# etc
Upvotes: 3
Reputation: 215117
Your TestFn
returns a 4 elements list per row, which can't really be fit in a row; You can wrap the returned elements in a vector first so the returned list is a single element list:
TestFn <- function(X, Y) list(c(X*5, Y/2, X+Y, X*2+5*Y))
# ^
df %>% rowwise() %>% mutate(R=TestFn(X,Y)) %>% pull(R)
#[[1]]
#[1] 5 1 3 12
#[[2]]
#[1] 10.0 1.5 5.0 19.0
#[[3]]
#[1] 15 2 7 26
#[[4]]
#[1] 20 1 6 18
#[[5]]
#[1] 25 1 7 20
rowwise
is usually not as efficient, if you want to vectorize the solution, you can calculate the four expressions firstly and then transpose the result:
df$R = with(df, data.table::transpose(list(X*5, Y/2, X+Y, X*2+5*Y)))
df
# Name X Y R
#1 a 1 2 5, 1, 3, 12
#2 a 2 3 10.0, 1.5, 5.0, 19.0
#3 b 3 4 15, 2, 7, 26
#4 b 4 2 20, 1, 6, 18
#5 c 5 2 25, 1, 7, 20
Upvotes: 2