3

I plan to sum a data.table row-wise and add a constant to it. What is wrong with this code. I am specifically looking for pmap_dfr solution:

library(data.table)
library(tidyverse)
temp.dt <- data.table(a = 1:3, b = 1:3, c = 1:3)
d <- 10
temp.dt %>% pmap_dfr(., sum, d)   # add columns a b and c and add variable d to it

The output expected is a single column tibble with the following rows:

13 16 19

Error thrown: Argument 1 must have names.

I have been able to get it to work with pmap and pmap_dbl but it fails when using pmap_dfr. Additionally, the example I have provided is a toy example. I want the d variable as an input argument to the sum function instead of adding d later to the row-wise sum.

Example I know the below would work:

temp.dt %>% pmap_dbl(., sum) + d
aajkaltak
  • 1,437
  • 4
  • 20
  • 28

2 Answers2

5

The problem occurs for regular data frames too so to reduce this to the essentials start a new R session, get rid of the data.table part and use the input shown where we have a 3x4 data.frame so that we don't confuse rows and columns. Also note that pmap_dfr(sum, d) is the same as pmap(sum, d) %>% bind_rows and it is in the bind_rows step that the problem occurs.

library(dplyr)
library(purrr)

# test input
temp.df <- data.frame(a = 1:3, b = 1:3, c = 1:3, z = 1:3)
rownames(temp.df) <- LETTERS[1:3]
d <- 10

out <- temp.df %>% pmap(sum, d)     # this works
out %>% bind_rows
## Error: Argument 1 must have names

The problem, as the error states, is that out has no names and it seems it will not provide default names for the result. For example, this will work -- I am not suggesting that you necessarily do this but just trying to illustrate why it does not work by showing minimal changes that make it work:

temp.df %>% pmap(sum, d) %>% set_names(rownames(temp.df)) %>% bind_rows

## # A tibble: 1 x 3
##       A     B     C
##   <dbl> <dbl> <dbl>
## 1    14    18    22

or this could be written like this to avoid writing temp.df twice:

temp.df %>% { set_names(pmap(., sum, d), rownames(.)) } %>% bind_rows

I think we can conclude that pmap_dfr is just not the right function to use here.

Base R

Of course, this is all trivial in base R as you can do this:

rowSums(temp.df) + d
##  A  B  C 
## 14 18 22 

or more generally:

as.data.frame.list(apply(temp.df, 1, sum, d))
##  A  B  C 
## 14 18 22 

or

as.data.frame.list(Reduce("+", temp.df) + d)
##   X14 X18 X22
##1  14  18  22

data.table

In data.table we can write:

library(data.table)

DT <- as.data.table(temp.df)

DT[, as.list(rowSums(.SD) + d)]
##    V1 V2 V3
## 1: 14 18 22

DT[, as.list(apply(.SD, 1, sum, d))]
##    V1 V2 V3
## 1: 14 18 22

Also note that using data.table directly tends to be faster than sticking another level on top of it so if you thought you were getting the benefit of data.table's speed by using it with dplyr and purrr you likely aren't.

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
2

A pmap_dfr solution is to first transpose the dataset. We can later rename the columns as desired:

temp.dt %>% 
 t() %>% 
   as.data.frame()-> tmp_dt
   pmap_dfr(list(tmp_dt, 10),sum)
# A tibble: 1 x 3
     V1    V2    V3
  <dbl> <dbl> <dbl>
1    13    16    19

A possible dplyr-base alternative:

temp.dt %>% 
   mutate(Sum = rowSums(.) + d) %>% 
  pull(Sum)
[1] 13 16 19

Or using pmap_dbl:

temp.dt %>% 
   pmap_dbl(.,sum) + d
[1] 13 16 19
NelsonGon
  • 13,015
  • 7
  • 27
  • 57
  • 1
    I was trying to learn to use pmap. Would you know how to do it using pmap_dfr ? – aajkaltak Sep 07 '19 at 13:39
  • I've added a `pmap` alternative. You might be better off with `map2` or `imap` though. – NelsonGon Sep 07 '19 at 13:45
  • 1
    Sorry I am looking for pmap_dfr . I have been able to get it to work with pmap and pmap_dbl but it fails when using pmap_dfr. Additionally, the example I have provided is a toy example. I want the d variable as an input argument to the sum function instead of adding d later to the row-wise sum. – aajkaltak Sep 07 '19 at 13:52
  • Check the edit. You can rename the result as necessary. – NelsonGon Sep 07 '19 at 13:57