1

This is an example of what I want to do:

df <- data.frame(x=1:100,y=1:100)
empty_row_ids <- c(5,10)

This is the final output:

results <- rbind(data.frame(x=1:4,y=1:4),c(0,0),data.frame(x=5:8,y=5:8),c(0,0).data.frame(x=9:100,y=9:100)) 

Essentially, I want to insert some empty rows at some given numbers.

Leonhardt Guass
  • 773
  • 7
  • 24
  • It's very unusual to add empty rows to a data.frame. What exactly are you trying to accomplish? Also are you sure you want to add zeros rather than NA values? Do you only have numeric columns? – MrFlick Sep 25 '20 at 02:25
  • I am generating publication-quality regression tables. The results are stored in a data frame, and I need a few spaces between the different categories. I used zeros just for the example, in reality, it will be blank rows. – Leonhardt Guass Sep 25 '20 at 02:29
  • 2
    "I am generating publication-quality regression tables." Ideally, this table formatting is something you'd do as a layer on top of your data, not with a manipulation of your data itself. If you provide an image of the kind of table look you want, it's possible someone can help you find a formatting solution instead of a data manipulation. – andrew_reece Sep 25 '20 at 02:33
  • 1
    It looks like `kable` has a linespacing option that can be set, see discussion [here](https://stackoverflow.com/questions/49015578/space-after-every-five-rows-in-kable-output-with-booktabs-option-in-r-markdown) – andrew_reece Sep 25 '20 at 03:10

4 Answers4

2

I'd recommend looking for a formatting solution, rather than one that changes your data. But you can use add_row() to do what you're asking.

library(dplyr)

n <- 2 # number of spacing rows to insert at each point
spacer <- rep("", n)

df %>%
  mutate(across(.fns = as.character)) %>%
  add_row(x = spacer, y = spacer, .before = 6) %>%
  add_row(x = spacer, y = spacer, .before = 11) 

Output:

      x   y
1     1   1
2     2   2
3     3   3
4     4   4
5          
6          
7     5   5
8     6   6
9     7   7
10         
11         
12    8   8
13    9   9
14   10  10
...

Insert as many spacing rows n as you desire with rep("", n) at the target indices.

andrew_reece
  • 20,390
  • 3
  • 33
  • 58
1

A way to do what you want would be formating the empty_rows_id inside a dataframe with the zeroes and then use bind_rows() in a dplyr pipeline to add the data. Here the code:

library(dplyr)
#Data
df <- data.frame(x=1:100,y=1:100)
empty_row_ids <- c(5,10)
#Create data for rows
dfindex <- data.frame(id=empty_row_ids,x=0,y=0)
#Now bind
df2 <- df %>% mutate(id=1:n()) %>%
  bind_rows(dfindex) %>%
  arrange(id) %>% select(-id)

Output (some rows):

      x   y
1     1   1
2     2   2
3     3   3
4     4   4
5     5   5
6     0   0
7     6   6
8     7   7
9     8   8
10    9   9
11   10  10
12    0   0
13   11  11
14   12  12
15   13  13

If you want to export to other source to format your tables, it would be better to use NA instead of zero as @MrFlick said.

Duck
  • 39,058
  • 13
  • 42
  • 84
1

Here's a base R solution

add_empty_rows <- function(df, at) {
  new_len <- nrow(df) + length(at)
  result <- as.data.frame(lapply(df, function(x) vector(class(x), new_len)))
  result[(1:new_len)[-at],] <- df
  result
}
newdf <- add_empty_rows(df, empty_row_ids)

Basically we just make a new data.frame with all blank rows, then put the values we want to keep in the slots we don't want to keep empty

MrFlick
  • 195,160
  • 17
  • 277
  • 295
1

Here is one way manipulating row index :

inds <- seq(nrow(df))
df1 <- df[c(inds  - cumsum(inds %in% empty_row_ids), 
            tail(inds, length(empty_row_ids))), ]

row.names(df1) <- NULL
df1[empty_row_ids, ] <- 0
df1

#      x   y
#1     1   1
#2     2   2
#3     3   3
#4     4   4
#5     0   0
#6     5   5
#7     6   6
#8     7   7
#9     8   8
#10    0   0
#11    9   9
#12   10  10
#13   11  11
#..
#..
#99   97  97
#100  98  98
#101  99  99
#102 100 100
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213