The aim is to transform all Species "setosa" rows to one row "setosa":(This is a minimal example(in real more columns and more groups):
I have this dataframe:
head(iris, 2) %>%
select(1,2,5) %>%
group_by(Species)
Sepal.Length Sepal.Width Species
<dbl> <dbl> <fct>
1 5.1 3.5 setosa
2 4.9 3 setosa
I use summarise
with toString
to get:
Species Sepal.Length Sepal.Width
<fct> <chr> <chr>
1 setosa 5.1, 4.9 3.5, 3
Expected output: I want this dataframe:
Species Sepal.Length1 Sepal.Length2 Sepal.Width1 Sepal.Width2
<fct> <dbl> <dbl> <dbl> <int>
1 setosa 5.1 4.9 3.5 3
I achieve this with this working code:
head(iris, 2) %>%
select(1,2,5) %>%
group_by(Species) %>%
summarise(across(everything(), ~toString(.))) %>%
ungroup() %>%
separate(Sepal.Length, c("Sepal.Length1", "Sepal.Length2"), sep = ", ", convert = TRUE) %>%
separate(Sepal.Width, c("Sepal.Width1", "Sepal.Width2"), sep = ", ", convert = TRUE)
However I would like to be able to use separate
after mutate
across
with anonymous function with this not working code:
head(iris, 2) %>%
select(1,2,5) %>%
group_by(Species) %>%
summarise(across(everything(), ~toString(.))) %>%
ungroup() %>%
mutate(across(-1, ~separate(., into = paste0(., 1:2), sep = ", ", convert = TRUE)))
Error: Problem with `mutate()` input `..1`.
i `..1 = across(-1, ~separate(., into = paste0(., 1:2), sep = ", ", convert = TRUE))`.
x no applicable method for 'separate' applied to an object of class "character"
I want to learn how to apply separate
function after mutate
and across
.
CodePudding user response:
Another approach, pivoting long, transforming, and pivoting wide again.
library(tidyverse)
head(iris, 2) %>%
select(1,2,5) %>%
pivot_longer(-Species) %>%
group_by(name) %>% mutate(col = paste0(name, row_number())) %>% ungroup() %>%
select(-name) %>%
arrange(col) %>% # for ordering columns like OP
pivot_wider(names_from = col, values_from = value)
# A tibble: 1 x 5
Species Sepal.Length1 Sepal.Length2 Sepal.Width1 Sepal.Width2
<fct> <dbl> <dbl> <dbl> <dbl>
1 setosa 5.1 4.9 3.5 3
CodePudding user response:
Main issue is that separate
requires input as a data.frame. We may wrap in a tibble
and then do separate
if we want this within across
and finally unnest
the list
output
library(dplyr)
library(tidyr)
library(stringr)
head(iris, 2) %>%
select(1,2,5) %>%
group_by(Species) %>%
summarise(across(everything(), ~toString(.)), .groups = 'drop') %>%
mutate(across(-1, ~ list(tibble(col1 = .) %>%
separate(col1, into = str_c(cur_column(), 1:2), sep = ",\\s ")))) %>%
unnest(cols = c(Sepal.Length, Sepal.Width))
-output
# A tibble: 1 × 5
Species Sepal.Length1 Sepal.Length2 Sepal.Width1 Sepal.Width2
<fct> <chr> <chr> <chr> <chr>
1 setosa 5.1 4.9 3.5 3
CodePudding user response:
Another solution:
library(tidyverse)
head(iris, 2) %>%
select(1,2,5) %>%
group_by(Species) %>%
summarise(across(everything(), ~toString(.))) %>%
separate(2, into = paste0("Sepal.Length",1:2), sep=", ") %>%
separate(4, into = paste0("Sepal.Width",1:2), sep=", ")
#> # A tibble: 1 × 5
#> Species Sepal.Length1 Sepal.Length2 Sepal.Width1 Sepal.Width2
#> <fct> <chr> <chr> <chr> <chr>
#> 1 setosa 5.1 4.9 3.5 3