диаграмма санки в R - подготовка данных - PullRequest
1 голос
/ 05 июня 2019

У меня есть следующий фрейм данных, где каждый пациент представляет собой строку (я показываю только ее образец):

df = structure(list(firstY = c("N/A", "1", "3a", "3a", "3b", "1", 
"2", "1", "5", "3b"), secondY = c("N/A", "1", "2", "3a", "4", 
"1", "N/A", "1", "5", "3b"), ThirdY = c("N/A", "1", "N/A", "3b", 
"4", "1", "N/A", "1", "N/A", "3b"), FourthY = c("N/A", "1", "N/A", 
"3a", "4", "1", "N/A", "1", "N/A", "3a"), FifthY = c("N/A", "1", 
"N/A", "2", "5", "1", "N/A", "N/A", "N/A", "3b")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -10L))

Я хотел бы построить диаграмму Санки, которая показывает траекторию надвремя каждого пациента, и я знаю, что мне нужно создавать узлы и ссылки, но у меня возникают проблемы с преобразованием данных в формат, необходимый для достижения этой цели.В частности, наиболее проблематичным является подсчет количества пациентов, принадлежащих к каждой траектории, например, сколько пациентов прошло в первый год с этапа 1 до 2 и всех других комбинаций.

Любая помощь с даннымиПодготовка будет принята с благодарностью.

Пакет Alluvial, хотя и простой для понимания, не очень хорошо справляется, если данных много.

Ответы [ 3 ]

3 голосов
/ 05 июня 2019

Не очень ясно, чего вы хотите достичь, потому что вы не упоминаете пакет, который хотите использовать, но, глядя на ваши данные, кажется, что это может помочь, если вы могли бы использовать alluvialпакет:

library(alluvial) # sankey plots
library(dplyr)    # data manipulation

Функции alluvial могут использовать данные в широком формате, как у вас, но для этого нужен столбец частоты, поэтому мы можем его создать, а затем построить график:

dats_all <- df %>%                                                   # data
            group_by( firstY, secondY, ThirdY, FourthY, FifthY) %>%  # group them
            summarise(Freq = n())                                    # add frequencies

 # now plot it
alluvial( dats_all[,1:5], freq=dats_all$Freq, border=NA )

enter image description here

В других руках, если вы хотите использовать конкретный пакет, вы должны указать, какой.


РЕДАКТИРОВАТЬ

Использование network3D немного сложнее, но вы можете достичь некоторого хорошего результата из этого.Вам нужны ссылки и узлы, и они должны быть сопоставлены, поэтому сначала мы можем создать ссылки:

# put your df in two columns, and preserve the ordering in many levels (columns) with paste0
links <- data.frame(source = c(paste0(df$firstY,'_1'),paste0(df$secondY,'_2'),paste0(df$ThirdY,'_3'),paste0(df$FourthY,'_4')),
                  target   = c(paste0(df$secondY,'_2'),paste0(df$ThirdY,'_3'),paste0(df$FourthY,'_4'),paste0(df$FifthY,'_5')))

# now convert as character
links$source <- as.character(links$source)
links$target<- as.character(links$target)

Теперь узлы - это каждый элемент в ссылке unique() способом:

nodes <- data.frame(name = unique(c(links$source, links$target)))

Теперь нам нужно, чтобы у каждого узла была ссылка (или наоборот), поэтому мы сопоставляем их и преобразуем в числа.Обратите внимание на -1 в конце, поскольку networkD3 равен 0 индексам, это означает, что числа (индексы) начинаются с 0.

links$source <- match(links$source, nodes$name) - 1
links$target <- match(links$target, nodes$name) - 1
links$value <- 1 # add also a value

Теперь вы должны быть готовы построить свой санкей:

sankeyNetwork(Links = links, Nodes = nodes, Source = 'source',
              Target = 'target', Value = 'value', NodeID = 'name')

enter image description here

2 голосов
/ 05 июня 2019

a way с

library(tidyr)
library(dplyr)
library(networkD3)

links <-
  df %>% 
  mutate(row = row_number()) %>%  # add a row id
  gather('col', 'source', -row) %>%  # gather all columns
  mutate(col = match(col, names(df))) %>%  # convert col names to col nums
  mutate(source = paste0(source, '_', col)) %>%  # add col num to node names
  group_by(row) %>%
  arrange(col) %>%
  mutate(target = lead(source)) %>%  # get target from following node in row
  ungroup() %>% 
  filter(!is.na(target)) %>%  # remove links from last column in original data
  select(source, target) %>% 
  group_by(source, target) %>% 
  summarise(value = n())  # aggregate and count similar links

# create nodes data frame from unque nodes found in links data frame
nodes <- data.frame(id = unique(c(links$source, links$target)),
                    stringsAsFactors = FALSE)
# remove column id from names
nodes$name <- sub('_[0-9]*$', '', nodes$id)

# set links data to the 0-based index of the nodes in the nodes data frame
links$source <- match(links$source, nodes$id) - 1
links$target <- match(links$target, nodes$id) - 1

sankeyNetwork(Links = links, Nodes = nodes, Source = 'source',
              Target = 'target', Value = 'value', NodeID = 'name')

enter image description here

2 голосов
/ 05 июня 2019

Использование ggforce :

library(ggforce)
library(dplyr)

xx <- df %>% 
  count(firstY, secondY, ThirdY, FourthY, FifthY, name = "value") %>% 
  gather_set_data(1:5) %>% 
  mutate(x = factor(x, levels = colnames(df)))


ggplot(xx, aes(x, id = id, split = y, value = value)) +
  geom_parallel_sets(alpha = 0.3, axis.width = 0.1) +
  geom_parallel_sets_axes(axis.width = 0.3) +
  geom_parallel_sets_labels(colour = "white")

enter image description here

...