структурирование двоичных данных для сюжета санки - PullRequest
0 голосов
/ 19 октября 2018

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

# example
library(networkD3)
library(tidyverse)
library(tidyr)

set.seed(900)
n=1000
example.data<-data.frame("A" = rep(1,n),
                         "B" = sample(c(0,1),n,replace = T),
                         "C" = rep(NA,n),
                         "D" = rep(NA,n),
                         "E" = rep(NA,n),
                         "F" = rep(NA,n),
                         "G" = rep(NA,n))

for (i in 1:n){
  example.data$C[i]<- ifelse(example.data$B[i]==1,
                                   sample(c(0,1),1,prob = c(0.3,0.7),replace = F),
                                   sample(c(0,1),1,prob = c(0.55,0.45),replace = F))
  example.data$D[i]<-ifelse(example.data$C[i]==1,
                                              sample(c(0,1),1,prob = c(0.95,0.05),replace = F),
                                              sample(c(0,1),1,prob = c(0.65,0.35),replace = F))
  example.data$E[i]<-ifelse(example.data$C[i]==0 & example.data$D[i]==0,
                                    sample(c(0,1),1,prob = c(.9,.1),replace = F),
                                    ifelse(example.data$C[i]==0 & example.data$D[i]==1,
                                           sample(c(0,1),1,prob = c(.3,.7),replace = F),
                                           ifelse(example.data$C[i]==1 & example.data$D[i]==0,
                                                  sample(c(0,1),1,prob = c(.9,.1),replace = F),
                                                  sample(c(0,1),1,prob = c(.1,.9),replace = F))))
  example.data$F[i]<-ifelse(example.data$E==1,
                                         sample(c(1,0),1,prob=c(.85,.15),replace = F),
                                         sample(c(1,0),1,prob = c(.01,.99),replace = F))
  example.data$G[i]<-sample(c(1,0),1,prob = c(.78,.22),replace = F)
}


example.data.1<-example.data%>%
  gather()%>%
  mutate(ORDER = c(rep(0,n),rep(1,n),rep(2,n),rep(3,n),rep(4,n),rep(5,n),rep(6,n)))%>%
  dplyr::select("Event" = key,
                "Success" = value,
                ORDER)%>%
  group_by(ORDER)%>%
  summarise("YES" = sum(Success==1),
            "NO" = sum(Success==0))

Сложность для меня заключается в том, как я могу сгенерировать данные ссылок без необходимости вручную указывать исходные цели и значения.

IЯ использовал пример Санки с этого сайта и продолжил набирать собственные данные примера как можно менее элегантно:

links<-data.frame("source" = sort(rep(seq(0,10,1),2)),
           "target" = c(1,2,3,4,3,4,5,6,5,6,7,8,7,8,9,10,9,10,11,12,11,12),
           "value" = c(sum(example.data$A==1 &example.data$B==1), #1
                       sum(example.data$A==1 & example.data$B==0),#2
                       sum(example.data$B==1 & example.data$C==1),#3
                       sum(example.data$B==1 & example.data$C==0),#4
                       sum(example.data$B==0 & example.data$C==1),#5
                       sum(example.data$B==0 & example.data$C==0),#6
                       sum(example.data$C==1 & example.data$D==1),#7
                       sum(example.data$C==1 & example.data$D==0),#8
                       sum(example.data$C==0 & example.data$D==1),#9
                       sum(example.data$C==0 & example.data$D==0),#10
                       sum(example.data$D==1 & example.data$E==1),#11
                       sum(example.data$D==1 & example.data$E==0),#12
                       sum(example.data$D==0 & example.data$E==1),#13
                       sum(example.data$D==0 & example.data$E==0),#14
                       sum(example.data$E==1 & example.data$F==1),#15
                       sum(example.data$E==1 & example.data$F==0),#16
                       sum(example.data$E==0 & example.data$F==1),#17
                       sum(example.data$E==0 & example.data$F==0),#18
                       sum(example.data$F==1 & example.data$G==1),#19
                       sum(example.data$F==1 & example.data$G==0),#20
                       sum(example.data$F==0 & example.data$G==1),#21
                       sum(example.data$F==0 & example.data$G==0)))#22

nodes<-data.frame("name" = names(example.data))


example.list<-list(nodes,links)

names(example.list)<-c("nodes","links")

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

Я нашел пример в стеке, где человек использовал вызов match в функции dplyr :: mutate, которая выглядела многообещающе для того, чего я пытаюсь достичь, но данные имели немного иную структуру, и я действительно не знал, какзаставить вызов совпадения работать с моими собственными данными.

Вывод, к которому я обращаюсь, представляет собой диаграмму Санки, которая показывает количество наблюдений, перемещающихся между каждым из событий / результатов [A: F].Итак, представьте, что каждый из столбцов представляет событие как успешное, так и не успешное.Сюжетный график иллюстрирует итоги всех успехов и неудач каждого события.Таким образом, все 1000 наблюдений, начиная с A с 493, идут к узлу с B = 1, а оставшиеся 507 идут к узлу, указывающему B = 0. Из 493 в B = 1 345 идут к узлу с указанием C = 1, и148 переходят в узел C = 0. Из 507 в B = 0 263 переходят в C = 1, а 244 переходят в C = 0 и так далее до конца событий от A до F. Я надеюсь, что я сделал этодостаточно ясно.Любая помощь по этому вопросу будет принята с благодарностью.

1 Ответ

0 голосов
/ 19 октября 2018

График sankey не работает, потому что вы ссылаетесь на узлы в ваших target и source столбцах, которые не существуют в вашем nodes фрейме данных.

для демонстрации ...

sort(unique(c(links$source, links$target)))
# [1]  0  1  2  3  4  5  6  7  8  9 10 11 12

nrow(nodes)
# [1] 7

Чтобы преобразовать ваши исходные данные в правильный формат ...

Причина, по которой с вашими исходными данными трудно работать, заключается в том, что важная информация, которую вы хотите использовать, неявно закодирована в формеваших данных, но явно не включены в данные.Каждая точка данных в данной строке имеет неявное отношение, что они были выбраны одним и тем же объектом, но эта информация явно не существует в ваших данных.Аналогично, каждый столбец неявно представляет одну из последовательных цепочек действий.Хороший тест для этой ситуации - спросить себя, изменили ли вы данные, или отсортировали их по столбцам, или изменили порядок столбцов, у вас останется та же информация?Если бы вы поменяли столбец B на столбец D, у вас все еще была бы та же информация?Игнорируя тот факт, что можно неявно принять предполагаемый порядок ваших столбцов, потому что они названы в алфавитном порядке, ответ - нет ... вот с чего вам нужно начать, кодируя эту информацию в ваши данные.

Добавьте номер строки в качестве переменной / столбца, затем соберите все столбцы в длинный формат и добавьте номер столбца ...

events <- 
  example.data %>% 
  as_tibble() %>% 
  mutate(row = row_number()) %>% 
  gather(column, choice, -row) %>% 
  mutate(column_num = match(column, names(example.data))) %>% 
  arrange(row, column_num) %>% 
  select(row, column_num, everything())

events
# # A tibble: 7,000 x 4
#      row column_num column choice
#    <int>      <int> <chr>   <dbl>
#  1     1          1 A           1
#  2     1          2 B           1
#  3     1          3 C           1
#  4     1          4 D           0
#  5     1          5 E           1
#  6     1          6 F           1
#  7     1          7 G           0
#  8     2          1 A           1
#  9     2          2 B           0
# 10     2          3 C           1
# # ... with 6,990 more rows

Теперь данные представляют одно событие / выбор на строку со всемикритическая информация, которая вам нужна.В вашем желаемом выводе каждый «узел» определяется столбцом и выбором, сделанным на этом этапе ... так A_1, B_0, B_1, C_0, C_1 и т. Д. Для каждого события в ваших измененных данных вы хотите знать вс какого узла произошел этот выбор / событие («цель»), и с какого узла оно пришло («источник»).Целевой узел - это имя столбца и выбор этого события.Исходный узел - это имя столбца и выбор предшествующего ему события (-1 column_num) в той же строке (персона / сущность / наблюдение).

links <-
  events %>% 
  mutate(target = paste0(column, "_", choice)) %>% 
  group_by(row) %>% 
  mutate(source = lag(target)) %>% 
  filter(!is.na(source) & !is.na(target))

links
# # A tibble: 6,000 x 6
# # Groups:   row [1,000]
#      row column_num column choice target source
#    <int>      <int> <chr>   <dbl> <chr>  <chr> 
#  1     1          2 B           1 B_1    A_1   
#  2     1          3 C           1 C_1    B_1   
#  3     1          4 D           0 D_0    C_1   
#  4     1          5 E           1 E_1    D_0   
#  5     1          6 F           1 F_1    E_1   
#  6     1          7 G           0 G_0    F_1   
#  7     2          2 B           0 B_0    A_1   
#  8     2          3 C           1 C_1    B_0   
#  9     2          4 D           0 D_0    C_1   
# 10     2          5 E           1 E_1    D_0   
# # ... with 5,990 more rows

Теперь вы хотите суммировать эти данные.Вы хотите посчитать количество каждой уникальной ссылки / пути.

links <- 
  links %>% 
  select(source, target) %>% 
  group_by(source, target) %>% 
  summarise(value = n()) %>% 
  ungroup()

links
# # A tibble: 22 x 3
#    source target value
#    <chr>  <chr>  <int>
#  1 A_1    B_0      507
#  2 A_1    B_1      493
#  3 B_0    C_0      244
#  4 B_0    C_1      263
#  5 B_1    C_0      148
#  6 B_1    C_1      345
#  7 C_0    D_0      267
#  8 C_0    D_1      125
#  9 C_1    D_0      579
# 10 C_1    D_1       29
# # ... with 12 more rows

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

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

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

enter image description here

...