Error in Bind_Rows_(X, .Id):Argument 1 Must Have Names

Error in bind_rows_(x, .id) : Argument 1 must have names

From the documentation of bind_rows:

Note that for historical reasons, lists containg vectors are always
treated as data frames. Thus their vectors are treated as columns
rather than rows, and their inner names are ignored

Here, your y as constructed has only inner names - it is two unnamed list elements, each containing a length-one vector with the vector element named a. So this error seems to be expected.

If you name the list elements, you can see that it behaves as described, with the vectors treated as columns:

library(tidyverse)
y <- map(1:2, ~ c(a=.x)) %>%
set_names(c("a", "b"))
bind_rows(y)
#> # A tibble: 1 x 2
#> a b
#> <int> <int>
#> 1 1 2

The difference with supplying y as arguments via do.call is that it's more like writing bind_rows(c(a = 1), c(a = 2)). This is not a list containing vectors, but separate vectors, so it binds by row as expected.

Bind_rows() error: Argument 1 must have names // Occurs after tidyverse update

The first part of your attempt gives you a list for every column irrespective of it's length.

x <- data.frame((sapply(x, c)))
str(x)

#'data.frame': 4 obs. of 3 variables:
# $ col1:List of 4
# ..$ : chr "a"
# ..$ : chr "b"
# ..$ : chr "c"
# ..$ : logi NA
# $ col2:List of 4
# ..$ : num 1
# ..$ : num 2
# ..$ : num 3
# ..$ : num 4
# $ col3:List of 4
# ..$ : chr "value1"
# ..$ : chr "value2"
# ..$ : chr "value1"
# ..$ : chr "value1" "value2"

You can unlist the above for columns with only 1 element.

x[] <- lapply(x, function(p) if(max(lengths(p)) == 1) unlist(p) else p)
x
# col1 col2 col3
#1 a 1 value1
#2 b 2 value2
#3 c 3 value1
#4 <NA> 4 value1, value2

str(x)
#'data.frame': 4 obs. of 3 variables:
# $ col1: chr "a" "b" "c" NA
# $ col2: num 1 2 3 4
# $ col3:List of 4
# ..$ : chr "value1"
# ..$ : chr "value2"
# ..$ : chr "value1"
# ..$ : chr "value1" "value2"

R bind_rows() error: Argument 1 must have names

Is this the result you want?

First, I load the libraries and create the data, as per your question.

library(tibble)
library(purrr)
library(dplyr)
library(matrixTests)

df1 <- tibble(
var1A= rnorm(1:10) +1,
var1B= rnorm(1:10) +1,
var2A= rnorm(1:10) +2,
var2B= rnorm(1:10) +2,
var3A= rnorm(1:10) +3,
var3B= rnorm(1:10) +3)

df2 <- tibble(
var1A= rnorm(1:10) +1,
var1B= rnorm(1:10) +1,
var2A= rnorm(1:10) +2,
var2B= rnorm(1:10) +2,
var3A= rnorm(1:10) +3,
var3B= rnorm(1:10) +3)

df3 <- tibble(
var1A= rnorm(1:10) +1,
var1B= rnorm(1:10) +1,
var2A= rnorm(1:10) +2,
var2B= rnorm(1:10) +2,
var3A= rnorm(1:10) +3,
var3B= rnorm(1:10) +3)

thresholds = c(1, 2, 3)
list_dfs = c('df1','df2','df3')

Here, I unlist the results before binding.

map(list_dfs,
function(df_name){
x <- get(df_name)
lapply(thresholds, function(i){

col_t_welch(x %>%
pull(paste0("var",i,"A")),
x %>%
pull(paste0("var",i,"B")))

})
}) %>%
unlist(recursive = FALSE) %>%
bind_rows()

which gives,

#>   obs.x obs.y obs.tot    mean.x    mean.y   mean.diff     var.x     var.y
#> 1 10 10 20 0.4123358 0.9386079 -0.52627205 1.2887733 1.4188697
#> 2 10 10 20 1.4848642 1.8852731 -0.40040891 0.7594906 1.9971866
#> 3 10 10 20 2.9905342 3.1454473 -0.15491307 0.9501264 0.6863846
#> 4 10 10 20 1.2409187 0.9453490 0.29556964 1.8969049 0.5213807
#> 5 10 10 20 2.0823664 2.3150223 -0.23265591 0.5171046 0.6771720
#> 6 10 10 20 3.0354769 2.2958400 0.73963696 0.8915344 1.1509940
#> 7 10 10 20 0.5546491 0.8868825 -0.33223340 0.6404670 0.4313640
#> 8 10 10 20 2.9031533 2.5956085 0.30754479 1.1602239 1.6080605
#> 9 10 10 20 3.1435888 3.1988889 -0.05530018 1.7926813 0.4374122
#> stderr df statistic pvalue conf.low conf.high alternative
#> 1 0.5203502 17.95854 -1.0113806 0.3252679 -1.6196681 0.5671240 two.sided
#> 2 0.5250407 14.98023 -0.7626246 0.4575287 -1.5196353 0.7188175 two.sided
#> 3 0.4045381 17.54432 -0.3829381 0.7063657 -1.0064012 0.6965751 two.sided
#> 4 0.4917607 13.59994 0.6010437 0.5576963 -0.7620703 1.3532096 two.sided
#> 5 0.3455831 17.68236 -0.6732272 0.5095070 -0.9596350 0.4943232 two.sided
#> 6 0.4519434 17.71416 1.6365699 0.1193625 -0.2109603 1.6902343 two.sided
#> 7 0.3273883 17.34004 -1.0147992 0.3241530 -1.0219320 0.3574652 two.sided
#> 8 0.5261449 17.54094 0.5845249 0.5663102 -0.7999219 1.4150114 two.sided
#> 9 0.4722387 13.14519 -0.1171022 0.9085494 -1.0743655 0.9637651 two.sided
#> mean.null conf.level
#> 1 0 0.95
#> 2 0 0.95
#> 3 0 0.95
#> 4 0 0.95
#> 5 0 0.95
#> 6 0 0.95
#> 7 0 0.95
#> 8 0 0.95
#> 9 0 0.95

Created on 2019-03-21 by the reprex package (v0.2.1)

Error in bind_rows_(x, .id) : Argument 1 must have names using map_df in purrr

The problem is that when it binds the rows, it cannot bind with NA. To fix this just use data.frame() rather than NA.

Here's a simpler example of the problem.

library('dplyr')
library('purrr')

try_filter <- function(df) {
tryCatch(
df %>%
filter(Sepal.Length == 4.6),
error = function(e) NA)
}

map_df(
list(iris, NA, iris),
try_filter)
#> Error in bind_rows_(x, .id) : Argument 1 must have names

The solution is to replace NA with data.frame().

try_filter <- function(df) {
tryCatch(
df %>%
filter(Sepal.Length == 4.6),
error = function(e) data.frame())
}

map_df(
list(iris, NA, iris),
try_filter)
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 4.6 3.1 1.5 0.2 setosa
#> 2 4.6 3.4 1.4 0.3 setosa
#> 3 4.6 3.6 1.0 0.2 setosa
#> 4 4.6 3.2 1.4 0.2 setosa
#> 5 4.6 3.1 1.5 0.2 setosa
#> 6 4.6 3.4 1.4 0.3 setosa
#> 7 4.6 3.6 1.0 0.2 setosa
#> 8 4.6 3.2 1.4 0.2 setosa

pmap purrr error: Argument 1 must have names

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.

How to resolve error: Argument 1 must have names when using map( ) pluck( ) in R to list( )?

To bind_rows(), you just need to convert the list of vectors into a list of dataframe beforehand. So, you could do:

Reprex

  • Code
library(purrr)
library(dplyr)

list(list(result="0001"),list(result="0002")) %>%
purrr::map(pluck, 'result') %>%
purrr::map(., ~ data.frame(results = .)) %>%
bind_rows()
  • Output
#>   results
#> 1 0001
#> 2 0002

Created on 2022-03-04 by the reprex package (v2.0.1)



Related Topics



Leave a reply



Submit