#r #tidyverse
Вопрос:
Это похоже на вопрос, который я задавал ранее, но я упустил пару важных деталей: столбец идентификаторов и переменные XYZ.
У меня есть набор данных со следующей компоновкой (странные названия столбцов, я знаю):
ID <- c(1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0)
XYZ1_a <- c(1, 2, 1, 2, 1, 2, 4, 2, 5, 1)
XYZ1_b <- c(2, 1, 1, 1, 2, 2, 4, 2, 1, 5)
ABC1a_1 <- c(1, 5, 3, 4, 3, 4, 5, 2, 2, 1)
ABC1b_1 <- c(4, 2, 1, 1, 5, 3, 2, 1, 1, 5)
ABC1a_2 <- c(4, 5, 5, 4, 2, 5, 5, 1, 2, 4)
ABC1b_2 <- c(2, 3, 3, 2, 2, 3, 2, 1, 4, 2)
ABC2a_1 <- c(2, 5, 3, 5, 3, 4, 5, 3, 2, 3)
ABC2b_1 <- c(1, 2, 2, 4, 5, 3, 2, 4, 1, 4)
ABC2a_2 <- c(2, 5, 5, 1, 2, 1, 5, 1, 3, 4)
ABC2b_2 <- c(2, 3, 3, 2, 1, 3, 1, 1, 2, 2)
df <- data.frame(ID, XYZ1_a, XYZ1_b, ABC1a_1, ABC1b_1, ABC1a_2, ABC1b_2, ABC2a_1, ABC2b_1, ABC2a_2, ABC2b_2)
Я хочу свернуть все ABC[N][x]_[n]
переменные в одну ABC[N]_[n]
переменную, как показано ниже, но мне также нужно сделать то же самое для столбцов с соглашением об XYZ
именовании:
ID <- c(1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0)
XYZ1 <- c(1, 2, 1, 2, 1, 2, 4, 2, 5, 1, 2, 1, 1, 1, 2, 2, 4, 2, 1, 5)
ABC1_1 <- c(1, 5, 3, 4, 3, 4, 5, 2, 2, 1, 4, 2, 1, 1, 5, 3, 2, 1, 1, 5)
ABC1_2 <- c(4, 5, 5, 4, 2, 5, 5, 1, 2, 4, 2, 3, 3, 2, 2, 3, 2, 1, 4, 2)
ABC2_1 <- c(2, 5, 3, 5, 3, 4, 5, 3, 2, 3, 1, 2, 2, 4, 5, 3, 2, 4, 1, 4)
ABC2_2 <- c(2, 5, 5, 1, 2, 1, 5, 1, 3, 4, 2, 3, 3, 2, 1, 3, 1, 1, 2, 2)
df2 <- data.frame(ID, XYZ1, ABC1_1, ABC1_2, ABC2_1, ABC2_2)
Каков наилучший способ достичь этого, в идеале с tidyverse
помощью решения?
Ответ №1:
Мы можем использовать перестановку подстрок в тех именах столбцов, которые starts_with
«ABC», записав букву в группу, за которой следует подчеркивание, и одну или несколько цифр ( \d
) в качестве второй группы, при замене укажите обратную ссылку в обратном порядке при добавлении новой _
. В pivot_longer
, укажите sep
, чтобы соответствовать _
тому, что предшествует букве
library(dplyr)
library(stringr)
library(tidyr)
df %>%
rename_with(~ str_replace(., "([a-z])_(\d )$", "_\2_\1"),
starts_with('AB')) %>%
pivot_longer(cols = -ID, names_to = c(".value", "grp"),
names_sep = "_(?=[a-z])", values_drop_na = TRUE) %>%
select(-grp)
-выход
# A tibble: 20 x 6
ID XYZ1 ABC1_1 ABC1_2 ABC2_1 ABC2_2
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1.1 1 1 4 2 2
2 1.1 2 4 2 1 2
3 1.2 2 5 5 5 5
4 1.2 1 2 3 2 3
5 1.3 1 3 5 3 5
6 1.3 1 1 3 2 3
7 1.4 2 4 4 5 1
8 1.4 1 1 2 4 2
9 1.5 1 3 2 3 2
10 1.5 2 5 2 5 1
11 1.6 2 4 5 4 1
12 1.6 2 3 3 3 3
13 1.7 4 5 5 5 5
14 1.7 4 2 2 2 1
15 1.8 2 2 1 3 1
16 1.8 2 1 1 4 1
17 1.9 5 2 2 2 3
18 1.9 1 1 4 1 2
19 2 1 1 4 3 4
20 2 5 5 2 4 2
В более старой версии используйте rename_at
df %>%
rename_at(vars(starts_with('AB')),
~ str_replace(., "([a-z])_(\d )$", "_\2_\1")) %>%
pivot_longer(cols = -ID, names_to = c(".value", "grp"),
names_sep = "_(?=[a-z])", values_drop_na = TRUE) %>%
select(-grp)
-выход
# A tibble: 20 x 6
ID XYZ1 ABC1_1 ABC1_2 ABC2_1 ABC2_2
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1.1 1 1 4 2 2
2 1.1 2 4 2 1 2
3 1.2 2 5 5 5 5
4 1.2 1 2 3 2 3
5 1.3 1 3 5 3 5
6 1.3 1 1 3 2 3
7 1.4 2 4 4 5 1
8 1.4 1 1 2 4 2
9 1.5 1 3 2 3 2
10 1.5 2 5 2 5 1
11 1.6 2 4 5 4 1
12 1.6 2 3 3 3 3
13 1.7 4 5 5 5 5
14 1.7 4 2 2 2 1
15 1.8 2 2 1 3 1
16 1.8 2 1 1 4 1
17 1.9 5 2 2 2 3
18 1.9 1 1 4 1 2
19 2 1 1 4 3 4
20 2 5 5 2 4 2
Комментарии:
1. Это здорово. Есть ли альтернатива, которая не использует rename_with? Я ограничен более старой версией dplyr.
2. Я получаю сообщение об ошибке, что функция starts_with() должна использоваться в функции выбора .
3. @R. Баратеон, с которым я
vars
работал, и, похоже, он работает с моей текущей версией. Возможно, в более старых версиях есть какая-то ошибка4. Не волнуйтесь, я позвонил в dplyr::vars, и это все решило. Спасибо.
5. @R. Баратеон, вероятно, какая-то маскировка функций