r - 为桑基图构建二进制数据
问题描述
我无法弄清楚如何为有多种成功机会(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))
对我来说棘手的部分是如何生成链接数据而无需手动指定源目标和值。
我使用了这个网站上的 sankey 示例,并以最不优雅的方式继续增强我自己的示例数据:
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 个以上的目标。
我在堆栈上找到了一个示例,该人在 dplyr::mutate 函数中使用了 match 调用,该函数看起来很有希望完成我想要完成的工作,但是数据的结构略有不同,我真的不知道如何获得match 调用来处理我自己的数据。
我要的输出是一个 sankey 图,它显示了在每个事件/结果 [A:F] 之间移动的观察次数。所以想象每一列代表一个成功或不成功的事件。sakey 图将说明每个事件的总成功和失败的总结。因此,从 A 开始的所有 1000 个观测值,其中 493 个进入 B = 1 的节点,其余 507 个进入指示 B = 0 的节点。在 B = 1 的 493 个中,345 个进入指示 C = 1 的节点,并且148 到节点 C = 0。在 B = 0 中的 507 中,263 到 C = 1 和 244 到 C = 0,等等事件 A 到 F 的其余部分。我希望我已经做到了够清楚。对此的任何帮助将不胜感激。
解决方案
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")
推荐阅读
- python - 如何获得列表所需的实际内存大小?
- c# - 如何在datagridview c#中获取包含$字符的列的总和
- curl - curl POST 在云 linux 实例中返回错误 503,同时在本地 mac 上工作
- python - 从 Web 目录而不是单个 url 读取
- jquery - jQuery 在控制台中有效,但在 WordPress 中无效
- python - 如何计算数据框的协方差矩阵
- python - 如何使程序创建新变量并以特定方式应用它们?
- python - 在 Python 中按照 youtube 教程创建了一个乒乓球游戏,然后想在进球后提高球速?
- javascript - 从没有插件的 Cordova WebView (JS) 调用本机 Android java 代码
- r - 累积不同数和重置