3

I want to append polynomial coefficient to data.frame as the example given below:

df1 <- 
  structure(list(
    Y = c(4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 16, 16, 16, 
          16, 16, 32, 32, 32, 32, 32, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 16, 
          16, 16, 16, 16, 32, 32, 32, 32, 32, 4, 4, 4, 4, 4, 8, 8, 8, 8, 
          8, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32)), 
    class = "data.frame", row.names = c(NA, -60L))

library(tidyverse)
df1 %>%
  dplyr::mutate(
    Linear    = poly(x = Y, degree = 3, raw = TRUE)[ ,1]
  , Quadratic = poly(x = Y, degree = 3, raw = TRUE)[ ,2]  
  , Cubic     = poly(x = Y, degree = 3, raw = TRUE)[ ,3]
    )

I wonder if there is a concise method like this

df1 %>%
  dplyr::mutate(poly(x = Y, degree = 3, raw = TRUE))

Thanks

MYaseen208
  • 22,666
  • 37
  • 165
  • 309

2 Answers2

8

Not exactly the way you were hoping, but close enough. I first convert the output of poly (a matrix) to a data.frame, then use !!! to splice the columns (turning each element of a list/data.frame into it's own argument). setNames is optional for renaming the columns:

library(dplyr)

df1 %>%
  mutate(!!!as.data.frame(poly(x = .$Y, degree = 3, raw = TRUE))) %>%
  setNames(c("Y", "Linear", "Quadratic", "Cubic"))

Result:

    Y Linear Quadratic Cubic
1   4      4        16    64
2   4      4        16    64
3   4      4        16    64
4   4      4        16    64
5   4      4        16    64
6   8      8        64   512
7   8      8        64   512
8   8      8        64   512
9   8      8        64   512
10  8      8        64   512
11 16     16       256  4096
12 16     16       256  4096
13 16     16       256  4096
14 16     16       256  4096
15 16     16       256  4096
16 32     32      1024 32768
17 32     32      1024 32768
18 32     32      1024 32768
19 32     32      1024 32768
20 32     32      1024 32768
...
acylam
  • 18,231
  • 5
  • 36
  • 45
  • [Info on !!! here](https://cran.r-project.org/web/packages/dplyr/vignettes/programming.html), I had never seen it before. About 2/3 of the way down the page. – zack Aug 14 '18 at 15:44
  • 2
    @zack It's part of a fairly new ecosystem of programming with dplyr that works well with other `tidyverse` functions. Also check `rlang`. – acylam Aug 14 '18 at 15:56
2

Another option, although I really like @useR's solution:

df1 %>%
  left_join(data.frame(Y = unique(.$Y), poly(unique(.$Y), degree = 3, raw = TRUE)),
            by = c('Y' = 'Y')) %>% 
  setNames(c('Y', 'Linear', 'Quadratic', 'Cubic'))

    Y Linear Quadratic Cubic
1   4      4        16    64
2   4      4        16    64
3   4      4        16    64
4   4      4        16    64
5   4      4        16    64
6   8      8        64   512
7   8      8        64   512
8   8      8        64   512
9   8      8        64   512
10  8      8        64   512
11 16     16       256  4096
12 16     16       256  4096
13 16     16       256  4096
14 16     16       256  4096
15 16     16       256  4096
16 32     32      1024 32768
17 32     32      1024 32768
18 32     32      1024 32768
19 32     32      1024 32768
20 32     32      1024 32768
zack
  • 5,205
  • 1
  • 19
  • 25
  • Don't really need `by = c('Y' = 'Y')` since it's the only mutual column – acylam Aug 14 '18 at 16:07
  • 1
    True, I've gotten into the habit of always including both sides in my code just because I've found it to make code more readable, in general. Still a good thing to point out, though. – zack Aug 14 '18 at 16:10
  • you can also just type `by = 'Y'` since they have the same name, but I get your point of keeping it consistent. – acylam Aug 14 '18 at 16:13