Это простое преобразование длинных в широкие ;поворот заключается в том, что нам нужно сгенерировать ключевую переменную из имен строк, соответствующим образом разделив строку.
В данных, которые вы предоставляете, имя строки состоит из конкатенации «позиции» (т. е. «first»,'second') и идентификатор (то есть. 'a', 'b'), который застрял в конце.Структура этого делает его разделение сложным: в идеале, вы бы использовали разделитель (т.е. first_a
, first_b
), чтобы сделать разделение однозначным.Без разделителя наш единственный вариант - разделить по позиции, но для этого необходимо, чтобы позиция разделения была фиксированным расстоянием от начала или конца строки.
В вашем примере, идентификатор всегда является последнимсимвол, поэтому мы можем передать -1
аргументу sep
в separate
, чтобы отделить последний символ в качестве столбца идентификатора.Если это не всегда так, вам понадобится более сложное решение для разрешения имен строк.
После преобразования имен строк в столбцы "position" и "id" это простоважно использовать spread
для расширения столбца позиции в широкоформатный формат:
library(tidyverse)
df %>%
rownames_to_column('row') %>%
separate(row, into = c('num', 'id'), sep = -1) %>%
spread(num, data)
id first second
1 a 1 5
2 b 2 6
3 c 3 7
4 d 4 8
Если бы идентификаторы строк могли иметь переменную длину, вышеприведенное решение не сработало бы.Если у вас есть известное и ограниченное количество значений «position», вы можете использовать решение регулярных выражений для разделения имени строки:
Здесь мы извлекаем значение позиции, сопоставляя регулярное выражение, содержащее все возможные значения (|
является оператором ИЛИ.
Мы сопоставляем значение "id", помещая это же регулярное выражение в оператор положительного просмотра .Это регулярное выражение будет соответствовать 1 или более строчных букв, которые приходят сразу после совпадения со значением позиции.Недостатком этого подхода является то, что вам необходимо указать все возможные значения «позиции» в регулярном выражении - если есть много опций, это может быстро стать слишком длинным и трудным для поддержки:
df2
data
firsta 1
firstb 2
firstc 3
firstd 4
seconda 5
secondb 6
secondc 7
secondd 8
secondee 9
df2 %>%
rownames_to_column('row') %>%
mutate(num = str_extract(row, 'first|second'),
id = str_match(row, '(?<=first|second)[a-z]+')) %>%
select(-row) %>%
spread(num, data)
id first second
1 a 1 5
2 b 2 6
3 c 3 7
4 d 4 8
5 ee NA 9