Этот вопрос возникает часто ... как преобразовать набор данных, который имеет несколько ссылок / ребер, определенных в каждой строке в нескольких столбцах. Вот как я конвертирую это в тип набора данных, который sankeyNetwork
(и многие другие пакеты, работающие с ребрами / связями / сетевыми данными) используют ... набор данных с одним ребром / ссылкой на строку.
начиная с примера набора данных ...
df <- read.csv(header = TRUE, as.is = TRUE, text = '
name,year1,year2,year3,year4
Bob,Hilton,Sheraton,Westin,Hyatt
John,Four Seasons,Ritz-Carlton,Westin,Sheraton
Tom,Ritz-Carlton,Westin,Sheraton,Hyatt
Mary,Westin,Sheraton,Four Seasons,Ritz-Carlton
Sue,Hyatt,Ritz-Carlton,Hilton,Sheraton
Barb,Hilton,Sheraton,Ritz-Carlton,Four Seasons
')
# name year1 year2 year3 year4
# 1 Bob Hilton Sheraton Westin Hyatt
# 2 John Four Seasons Ritz-Carlton Westin Sheraton
# 3 Tom Ritz-Carlton Westin Sheraton Hyatt
# 4 Mary Westin Sheraton Four Seasons Ritz-Carlton
# 5 Sue Hyatt Ritz-Carlton Hilton Sheraton
# 6 Barb Hilton Sheraton Ritz-Carlton Four Seasons
- создайте номер строки, чтобы вы по-прежнему могли определять, из какой строки / наблюдения пришла каждая отдельная ссылка, когда вы конвертируете данные в длинный формат
- используйте функцию
gather()
tidyr
для преобразования набора данных в длинный формат
- преобразовать переменную имени столбца в индекс / номер столбца в исходном наборе данных
- сгруппированные по строкам (каждое наблюдение в исходном наборе данных), упорядочить каждый узел по столбцу, в котором он находился, и создать переменную для его «цели», установив ее на узел из столбца после него
- отфильтровать любые строки, которые имеют
NA
для «цели» (узлы в последнем столбце исходного набора данных не будут иметь «цель», и поэтому в этих строках не указывается ссылка)
library(dplyr)
library(tidyr)
links <-
df %>%
mutate(row = row_number()) %>%
gather('column', 'source', -row) %>%
mutate(column = match(column, names(df))) %>%
group_by(row) %>%
arrange(column) %>%
mutate(target = lead(source)) %>%
ungroup() %>%
filter(!is.na(target))
# # A tibble: 24 x 4
# row column source target
# <int> <int> <chr> <chr>
# 1 1 1 Bob Hilton
# 2 2 1 John Four Seasons
# 3 3 1 Tom Ritz-Carlton
# 4 4 1 Mary Westin
# 5 5 1 Sue Hyatt
# 6 6 1 Barb Hilton
# 7 1 2 Hilton Sheraton
# 8 2 2 Four Seasons Ritz-Carlton
# 9 3 2 Ritz-Carlton Westin
# 10 4 2 Westin Sheraton
# # ... with 14 more rows
Теперь данные уже находятся в типичном формате сетевых данных - одна ссылка на строку, определенную столбцами «источник» и «цель», и их можно использовать с sankeyNetwork()
. Однако вы, вероятно, захотите, чтобы узлы, относящиеся к одному и тому же объекту, появлялись несколько раз в вашем графике ... если кто-то посетил Hilton в год 1, а затем снова посетил Hilton в год 3, вам, вероятно, понадобятся 2 отдельных узла, оба названные Хилтон, но появляясь в разных частях сюжета. Для этого вам нужно будет указать каждый узел в столбцах «источник» и «цель» с указанием года, в котором они были посещены. Вот где пригодятся переменные "строка" и "столбец".
Добавьте индекс столбца к имени «источника» и добавьте индекс столбца + 1 к имени «целевого», и теперь вы сможете различать, например, узел для Hilton, который был посещен в год 1, и узел для Hilton, который был посещен в течение 3-го года
links <-
links %>%
mutate(source = paste0(source, '_', column)) %>%
mutate(target = paste0(target, '_', column + 1)) %>%
select(source, target)
# # A tibble: 24 x 2
# source target
# <chr> <chr>
# 1 Bob_1 Hilton_2
# 2 John_1 Four Seasons_2
# 3 Tom_1 Ritz-Carlton_2
# 4 Mary_1 Westin_2
# 5 Sue_1 Hyatt_2
# 6 Barb_1 Hilton_2
# 7 Hilton_2 Sheraton_3
# 8 Four Seasons_2 Ritz-Carlton_3
# 9 Ritz-Carlton_2 Westin_3
# 10 Westin_2 Sheraton_3
# # ... with 14 more rows
Теперь вы можете следовать довольно стандартной процедуре использования списка ссылок источник-цель для создания необходимых фреймов данных для sankeyNetwork()
. Создайте nodes
фрейм данных со всеми уникальными узлами, найденными в "исходном" и "целевом" векторах. Преобразуйте "исходный" и "целевой" векторы в кадре данных links
в индекс узла в кадре данных nodes
с отсчетом от 0. Добавьте произвольное значение для каждой ссылки во фрейме данных links
, поскольку это требуется sankeyNetwork()
. Теперь вы можете удалить добавленный индекс столбца из имен узлов в nodes
фрейме данных, потому что они будут использоваться только для маркировки узлов в результирующем графике (поэтому больше не имеет значения, являются ли они уникальными). Затем начертите это с помощью sankeyNetwork()
!
nodes <- data.frame(name = unique(c(links$source, links$target)))
links$source <- match(links$source, nodes$name) - 1
links$target <- match(links$target, nodes$name) - 1
links$value <- 1
nodes$name <- sub('_[0-9]+$', '', nodes$name)
library(networkD3)
library(htmlwidgets)
sankeyNetwork(Links = links, Nodes = nodes, Source = 'source',
Target = 'target', Value = 'value', NodeID = 'name')
person
CJ Yetman
schedule
08.09.2018