4

I have a tibble with very many columns. I need to add a row to it at a specific location (e.g. before row 2). How can I do this without typing column names before the values?

E.g. this is what I must do (imagine more columns, V1, V2, V3, ...):

library(tidyverse)
tbl1 = tibble(V1=c(1,2), V2=c(3,4))
tbl1 %>% add_row(V1=1.5, V2=2.5, .before = 2)

This is what I wish I could do (returns error, since column names not specified):

library(tidyverse)
tbl1 = tibble(V1=c(1,2), V2=c(3,4))
tbl1 %>% add_row(c(1.5,3.5), .before = 2)

I can create another tibble based on the first one and append it to the old one using bind_rows, but that adds it at the end, i.e. I can't specify the location before row 2:

library(tidyverse)
tbl1 = tibble(V1=c(1,2), V2=c(3,4))
tbl2 = tbl1 %>% summarise_all(mean)
bind_rows(tbl1, tbl2)

(The goal is to interpolate between the two values in tbl1.) Method must be efficient, i.e. can't copy tbl1.

PaulG
  • 276
  • 2
  • 11
  • Are you hoping to do this interpolation between rows for many rows? If so, something using `?approx` could be good. – thelatemail Jan 03 '21 at 21:25

3 Answers3

3

Here is an option with setNames

library(tibble)
tbl1 %>% 
     add_row(!!! setNames(list(1.5, 3.5), names(.)), .before = 2)

-output

# A tibble: 3 x 2
#     V1    V2
#  <dbl> <dbl>
#1   1     3  
#2   1.5   3.5
#3   2     4  
akrun
  • 874,273
  • 37
  • 540
  • 662
1

With the addition of purrr, you could do:

map2_dfc(.x = c(1.5, 2.5),
         .y = names(tbl1),
         ~ tbl1 %>%
          select(.y) %>%
          add_row(!!.y := .x, .before = 2))

     V1    V2
  <dbl> <dbl>
1   1     3  
2   1.5   2.5
3   2     4  
tmfmnk
  • 38,881
  • 4
  • 47
  • 67
1

In base R you can add a row at any arbitrary position by doing :

#get mean of all columns
vals <- colMeans(tbl1)
#Assign position where you want to add the new row
before <- 2
#Create row index for the new dataframe
inds <- sort(c(seq(nrow(tbl1)), before))
#Add last row at before position
inds[before] <- length(inds)
#combine the two output and arrange them based on `inds`
result <- rbind(tbl1, vals)[inds, ]
result

#   V1    V2
#  <dbl> <dbl>
#1   1     3  
#2   1.5   3.5
#3   2     4  
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213