Как я могу манипулировать структурой данных, чтобы создать формат, необходимый для использования с networkD3 (в частности, функцией sankeyNetwork) в R? - PullRequest
0 голосов
/ 12 февраля 2020

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

Я пытался использовать пакет , в частности, функцию sankeyNetwork. Моя трудность состоит в том, чтобы получить данные, которые у меня есть, в правильную структуру для использования с sankeyNetwork.

Мои данные - это данные опроса, в которых респондентов просят ранжировать показатели от наиболее важных до наименее важных. Например,

     W        X        Y        Z       
[1,] "Rank 1" "Rank 2" "Rank 3" "Rank 4"
[2,] "Rank 2" "Rank 3" "Rank 1" "Rank 4"
[3,] "Rank 1" "Rank 2" "Rank 3" "Rank 4"
[4,] "Rank 1" "Rank 2" "Rank 4" "Rank 3"

, где W, X, Y & Z - метрики.

Чтобы создать санки, мне нужны данные в виде:

   0  1  10
   0  2  5
   1  3  2

Первый столбец представляет начальный узел (нумерация начинается с 0). Второй столбец является конечным узлом. Третий столбец - это значение / вес ссылки, соединяющей узлы. Также будет вектор, содержащий имена узлов.

Моя конечная цель - создать санки (перемещаясь слева направо) по первым узлам столбца, представляющим метрики с их долей полученных голосов "Ранга 1". Столбец 2 снова будет содержать все метрики, кроме ссылок, представляющих долю голосов «Ранг 2» и т. Д., Пока в последнем столбце не будут указаны доли голосов за последнее место каждого полученного показателя c.

Я ищу способ автоматизировать преобразование данных (из-за отсутствия лучшего слова), так как набор данных, который у меня должен быть, будет иметь 7 метрик (таким образом, 7 позиций ранжирования) и ответы от 50-100 человек и Таким образом, существует множество возможных комбинаций рейтинга.

В данный момент я могу использовать что-то похожее на

example_data %>%
    filter(W == "Rank 1" && X == "Rank 2") %>%
    tally()

, чтобы предоставить счет, но для этого требуется, чтобы я записал его или через l oop, каждую возможную комбинацию метрик и рейтинги. На самом деле это неосуществимо для объема данных, с которыми я предлагаю работать.

Редактировать: Спасибо за отзыв CJ Yetman. Мне уже удалось решить проблему, и поэтому мне не нужно было реализовывать ваш ответ, но ваше решение потенциально немного проще, чем то, что я в итоге сделал.

Я создал набор данных sankey_data, содержащий исходные данные, чтобы Я хотел бы иметь копию данных для работы с.

sankey_data[["id"]] <- seq(1, nrow(sankey_data))
sankey_data <- sankey_data %>%
  select(id, everything())

sankey_data <- apply(sankey_data, 2, as.character)
# Not necessarily required but I needed to convert the data points from factors 
# to characters.

# Creating new variables to store data in more helpful format
sankey_data$Rank1 <- rep(NA, nrow(sankey_data))
sankey_data$Rank2 <- rep(NA, nrow(sankey_data))
sankey_data$Rank3 <- rep(NA, nrow(sankey_data))
sankey_data$Rank4 <- rep(NA, nrow(sankey_data)) 

# Filling in those new variables
ranking_levels <- c("Rank 1", "Rank 2", "Rank 3", "Rank 4")

for (i in 1:nrow(sankey_data)) {
  for (j in 1:length(ranking_levels)) {
    hold <- colnames(sankey_data[i, grep(sankey_data[i,], 
        pattern = paste0("^", ranking_levels[j]), fixed = F)])
    sankey_data[i, 8 + j] <- hold
  }
}

# Creating the Link data
Link1 <- sankey_data %>%
    plyr::count(vars = c("Rank1", "Rank2")) %>%
    mutate("link" = 1)

Link2 <- sankey_data %>%
    plyr::count(vars = c("Rank2", "Rank3")) %>%
    mutate("link" = 2)

Link3 <- sankey_data %>%
    plyr::count(vars = c("Rank3", "Rank4")) %>%
    mutate("link" = 3)
# I then added prefixes to each data point within links 1 - 3 respectively.
# I just used paste0 but won't include the detail here as this is additional to
# what is strictly necessary to create the Sankey.

# Adding column names
colnames(Link1) <- c("source", "target", "value", "link")
colnames(Link2) <- colnames(Link1)
colnames(Link3) <- colnames(Link1)

# Combing into a single data set
links <- rbind(Link1, Link2, Link3)

nodes <- data.frame(name = c(as.character(links[["source"]]), 
                             as.character(links[["target"]])) %>% unique())

# As sankeyNetwork requires the nodes to be in numeric form (starting from 0),
# this serevs to convert the node names to numbers for input into the function
links[["IDsource"]] <- match(links[["source"]], nodes[["name"]]) - 1 
links[["IDtarget"]] <- match(links[["target"]], nodes[["name"]]) - 1

# The Sankey
sankeyNetwork(Links  = links, 
              Nodes  = nodes,
              Source = "IDsource", 
              Target = "IDtarget",
              Value  = "value", 
              fontFamily = "Arial",
              NodeID = "name", 
              sinksRight = FALSE, fontSize = 24, height = 1400, width = 3200)

Этот код работал для меня. Я попытался адаптировать его для работы с данными примера, так как не могу опубликовать sh фактические данные, чтобы мог быть один или два артефакта, которые я пропустил и которые не имеют смысла. Просто дайте мне знать, если это так, и я постараюсь обновить его.

1 Ответ

0 голосов
/ 21 февраля 2020

Я не совсем уверен, какой вывод вы ищете, но он звучит очень похоже на это решение .

Вот это решение, примененное к вашей проблеме .. .

library(dplyr)
library(tidyr)

example_data <-
  tibble::tribble(
    ~W,       ~X,       ~Y,       ~Z,       
    "Rank 1", "Rank 2", "Rank 3", "Rank 4",
    "Rank 2", "Rank 3", "Rank 1", "Rank 4",
    "Rank 1", "Rank 2", "Rank 3", "Rank 4",
    "Rank 1", "Rank 2", "Rank 4", "Rank 3"
  )

events <- 
  example_data %>% 
  mutate(row = row_number()) %>% 
  gather(column, choice, -row) %>% 
  mutate(column_num = match(column, names(example_data))) %>% 
  arrange(row, column_num) %>% 
  mutate(target = paste0(column, "_", choice)) %>% 
  group_by(row) %>% 
  mutate(source = lag(target)) %>% 
  filter(!is.na(source) & !is.na(target)) %>% 
  group_by(source, target) %>% 
  summarise(value = n())

# # A tibble: 8 x 3
# # Groups:   source [7]
#   source   target   value
#   <chr>    <chr>    <int>
# 1 W_Rank 1 X_Rank 2     3
# 2 W_Rank 2 X_Rank 3     1
# 3 X_Rank 2 Y_Rank 3     2
# 4 X_Rank 2 Y_Rank 4     1
# 5 X_Rank 3 Y_Rank 1     1
# 6 Y_Rank 1 Z_Rank 4     1
# 7 Y_Rank 3 Z_Rank 4     2
# 8 Y_Rank 4 Z_Rank 3     1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...