3

How can I rename a column within a grouped dplyr tibble, depending on a certain row value? The following graphic shows how my tibble looks before and how it should be looking after the manipulation.

enter image description here

I have tried the following code, but did not manage to write a column rename function that is able to state the new column name flexibly from the "name" column.

library(dplyr)

df <- data.frame(
 "splitvar"=c(1,1,1,2,2,3,3,3,3),
 "value"=c(1,4,2,5,6,9,11,13,12),
 "name"=c("Harold","Harold","Harold","Jane","Jane","George","George","George","George"),
 stringsAsFactors=F
)

grouped_tbl <- df %>%
  group_by( splitvar ) %>%
  eval(parse(
    paste0("rename(",unique(name)," = value)")
  ))

Related: Replacement for "rename" in dplyr

nilsole
  • 1,423
  • 2
  • 9
  • 23
  • 2
    You may need to `split` into a `list` of 3 data.frames because a column can have only a single name – akrun Dec 15 '17 at 16:01
  • I see your point. You are saying that grouped tibbles must have identical column names at all times. – nilsole Dec 15 '17 at 16:04
  • @akrun How can I then add a new column without changing the old ones? Having difficulties writing a flexible function here, something like: `grouped_tbl % group_by( splitvar ) %>% mutate( unique( name ) = value )`; but that gives me `Error: unexpected '=' in: " group_by( splitvar ) %>% mutate( unique( name ) ="` Thanks for help. – nilsole Dec 15 '17 at 16:07
  • 1
    Could this be a reshaping problem, where you use `name` as the new column names and fill the new columns with `value`? – aosmith Dec 15 '17 at 16:18
  • @aosmith Yes exactly. I was trying eval, parse and paste, but was wondering about a better dplyr way (maybe a custom function?). – nilsole Dec 15 '17 at 16:20
  • If you think your question has been answered, will you then consider marking the best answer? – Peter H. Dec 15 '17 at 18:47

2 Answers2

3

Like this:

library(tidyverse)

df %>% 
  split(.$splitvar) %>% 
  map(~rename(., !!unique(.$name) := "value"))

It took some time getting my head around the quosure-thing, but try and take a look at programming with dplyr

The output of the code is:

$`1`
  splitvar Harold   name
1        1      1 Harold
2        1      4 Harold
3        1      2 Harold

$`2`
  splitvar Jane name
4        2    5 Jane
5        2    6 Jane

$`3`
  splitvar George   name
6        3      9 George
7        3     11 George
8        3     13 George
9        3     12 George
Peter H.
  • 1,060
  • 4
  • 18
  • You can use `map_dfr` (based on `bind_rows`) if these need to be collapsed back into a single dataset. – aosmith Dec 15 '17 at 16:44
1

You could split apart, make the new columns, and bind back together.

Here's an option via nest/unnest (tidyr) and map (purrr)

library(tidyr)
library(purrr)

I use rename_at as alternative to tidyeval.

df %>%
    group_by(splitvar) %>%
    nest() %>%
    mutate(data = map(data, function(x) rename_at(x, "value", funs( unique(x$name) ) ) ) ) %>%
    unnest()

# A tibble: 9 x 5
  splitvar Harold   name  Jane George
     <dbl>  <dbl>  <chr> <dbl>  <dbl>
1        1      1 Harold    NA     NA
2        1      4 Harold    NA     NA
3        1      2 Harold    NA     NA
4        2     NA   Jane     5     NA
5        2     NA   Jane     6     NA
6        3     NA George    NA      9
7        3     NA George    NA     11
8        3     NA George    NA     13
9        3     NA George    NA     12

This could be a "reshaping" problem, which I do via tidyr. This doesn't keep the name column, though.

df %>%
    group_by(splitvar) %>%
    mutate(row = row_number() ) %>%
    spread(name, value)

# A tibble: 9 x 5
# Groups:   splitvar [3]
  splitvar   row George Harold  Jane
*    <dbl> <int>  <dbl>  <dbl> <dbl>
1        1     1     NA      1    NA
2        1     2     NA      4    NA
3        1     3     NA      2    NA
4        2     1     NA     NA     5
5        2     2     NA     NA     6
6        3     1      9     NA    NA
7        3     2     11     NA    NA
8        3     3     13     NA    NA
9        3     4     12     NA    NA
aosmith
  • 30,000
  • 7
  • 69
  • 102