user11916948
user11916948

Reputation: 954

Add a new row for each id in dataframe for ALL variables

I want to add a new row after each id. I found a solution on a stackflow page(Inserting a new row to data frame for each group id) but there is one thing I want to change and I dont know how. I want to make a new row for all variables, I don't want to write down all the variables ( the stackflow example). It doesnt matter the numbers in the row, I will change that later. If it is possible to add "base" in the new row for trt, that would be good. I want the code to work for many ids and varibles, having a lot of those in the data I'm working with. Many thanks if someone can help me with this!

The example code:

set.seed(1)
> id <- rep(1:3,each=4)
> trt <- rep(c("A","OA", "B", "OB"),3)
> pointA <- sample(1:10,12, replace=TRUE)
> pointB<- sample(1:10,12, replace=TRUE)
> pointC<- sample(1:10,12, replace=TRUE)
> df <- data.frame(id,trt,pointA, pointB,pointC)
> df
   id trt pointA pointB pointC
1   1   A      3      7      3
2   1  OA      4      4      4
3   1   B      6      8      1
4   1  OB     10      5      4
5   2   A      3      8      9
6   2  OA      9     10      4
7   2   B     10      4      5
8   2  OB      7      8      6
9   3   A      7     10      5
10  3  OA      1      3      2
11  3   B      3      7      9
12  3  OB      2      2      7

I want it to look like:

df <- rbind(df[1:4,], df1, df[5:8,], df2, df[9:12,],df3)
> df
   id  trt pointA pointB pointC
1   1    A      3      7      3
2   1   OA      4      4      4
3   1    B      6      8      1
4   1   OB     10      5      4
5   1 base                     
51  2    A      3      8      9
6   2   OA      9     10      4
7   2    B     10      4      5
8   2   OB      7      8      6
13  2 base                     
9   3    A      7     10      5
10  3   OA      1      3      2
11  3    B      3      7      9
12  3   OB      2      2      7
14  3 base                     
>  


I'm trying this code:


    df %>%
+   group_by(id) %>%
+   summarise(week = "base") %>%
+   mutate_all() %>%   #want tomutate allvariables
+   bind_rows(df, .) %>% 
+   arrange(id)

Upvotes: 1

Views: 591

Answers (2)

A. Suliman
A. Suliman

Reputation: 13125

library(dplyr)
library(purrr)
df %>% mutate_if(is.factor, as.character) %>% 
       group_split(id) %>% 
       map_dfr(~bind_rows(.x, data.frame(id=.x$id[1], trt="base", stringsAsFactors = FALSE)))

#Note that group_modify is Experimental
df %>% mutate_if(is.factor, as.character) %>% 
       group_by(id) %>% 
       group_modify(~bind_rows(.x, data.frame(trt="base", stringsAsFactors = FALSE)))

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 388982

You could bind_rows directly, it will add NAs to all other columns by default.

library(dplyr)
df %>%  group_by(id) %>% summarise(trt = 'base') %>% bind_rows(df) %>%  arrange(id)

#      id trt   pointA pointB pointC
#   <int> <chr>  <int>  <int>  <int>
# 1     1 base      NA     NA     NA
# 2     1 A          3      7      3
# 3     1 OA         4      4      4
# 4     1 B          6      8      1
# 5     1 OB        10      5      4
# 6     2 base      NA     NA     NA
# 7     2 A          3      8      9
# 8     2 OA         9     10      4
# 9     2 B         10      4      5
#10     2 OB         7      8      6
#11     3 base      NA     NA     NA
#12     3 A          7     10      5
#13     3 OA         1      3      2
#14     3 B          3      7      9
#15     3 OB         2      2      7

If you want empty strings instead of NA, we can give a range of columns in mutate_at and replace NA values with empty string.

df %>%
 group_by(id) %>%
 summarise(trt = 'base') %>%
 bind_rows(df) %>%
 mutate_at(vars(pointA:pointC), ~replace(., is.na(.) , '')) %>%
 arrange(id)

Upvotes: 2

Related Questions