我有如下DF。它包含有关两个学生三个学期的信息,以及他们是否合格。
我想绘制一个平行坐标。我想看看走到底的路。
ID term subject result
1 1 math01 fail
1 1 Phys01 pass
1 1 chem01 pass
1 2 math01 pass
1 2 math02 fail
1 3 math02 fail
1 3 cmp01 pass
2 1 math01 fail
2 1 phys01 pass
2 2 math01 pass
2 2 math02 pass
2 3 cmp01 pass
所需的结果类似于下图。
每个学期的每个方框都显示带有result
列(失败或通过)的科目别名。块的大小应对应于所拍摄主题的数量。例如,如果大多数学生在第1学期未通过math01,则math01fail的块应该是在term1以下的最大块。
连接线将学生在学期中选修的科目与下一学期联系起来。线的粗细对应于该点的连接数。例如,如果许多学生在term1上不通过math01(math01fail),而在term2上重新通过math01并通过(math01pass),则考虑到出现的次数,math01fail与math01pass之间的连接线应该更粗。
答案 0 :(得分:1)
我认为您最好从图形的角度解决此问题,而不是在平行坐标的情况下。
这就是我要做的:
从加载必要的库开始
library(tidyverse)
library(igraph)
首先,我们定义图的边缘列表。为此,我们用df
进行ID
的自联接,并选择与连续(递增)项相对应的行。然后,每一行对应于每个学生从学期i到i + 1的链接。
el <- left_join(df, df, by = "ID") %>%
filter(term.x == term.y - 1) %>%
mutate_at(vars(starts_with("term")), funs(paste0("term", .))) %>%
unite(from, term.x, subject.x, result.x, sep = "\n") %>%
unite(to, term.y, subject.y, result.y, sep = "\n") %>%
select(from, to) %>%
group_by(from, to) %>%
summarise(weight = (n() - 1) * 5 + 1)
我们添加了一个权重列,该列与每个边缘的学生数量成正比。我们之所以不简单地weight = n()
,原因纯粹是出于美学考虑,我们喜欢为1个以上的学生提供较粗的线条。
接下来,我们定义一个节点列表。此处的关键是添加x
和y
列,这些列将确定节点的网格布局。
nl <- df %>%
mutate(term = paste0("term", term)) %>%
arrange(term) %>%
distinct(term, subject, result) %>%
mutate(x = as.integer(as.factor(term))) %>%
group_by(term) %>%
mutate(y = 1:n()) %>%
unite(node, term, subject, result, sep = "\n")
请注意,nl
第一栏中的条目必须与el
前两栏中的条目相匹配。
我们现在准备从两个igraph
构造一个data.frame
并绘制图形。
gr <- graph_from_data_frame(d = el, vertices = nl, directed = F)
plot(
gr,
edge.width = E(gr)$weight,
vertex.shape = "rectangle",
vertex.size = 50, vertex.size2 = 50,
vertex.color = "white",
vertex.label.family = "sans",
vertex.label.cex = 0.7)
生成的图可能需要进一步调整/抛光,但这应该可以帮助您入门。