创建关于 r 中出现次数的平行坐标图
Create parallel-coordinate plot regarding to number of occurrences in r
我有如下DF。它包含有关两个学生的 3 个学期和科目的信息,无论他们是否通过。
我想画一条平行坐标的学生轨迹。我想看看走哪条路才能走到尽头
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 的块应该是下面第 1 学期的最大块。
连接线连接学生在本学期和下学期选修的科目。线的粗细对应于该点的连接数。例如,如果许多学生在第一学期未通过 math01 (math01fail) 并在第二学期重新参加 math01 并通过它 (math01pass),则 math01fail 和 math01pass 之间的连接线在出现次数方面应该更粗。
如何在 R 中创建这样的绘图?
我认为你最好从图形的角度来解决这个问题,而不是在平行坐标的上下文中。
这是我会做的:
从加载必要的库开始
library(tidyverse)
library(igraph)
首先我们定义图的边列表。为此,我们将 df
与 ID
和 select 对应于连续(递增)项的行进行自连接。然后每一行对应于每个学生从学期 i 到 i+1 的 link。
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
前两列中的条目匹配。
我们现在准备好从两个 data.frame
构造一个 igraph
并绘制图形。
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)
生成的图可能需要进一步 tweaking/polishing,但这应该可以帮助您入门。
我有如下DF。它包含有关两个学生的 3 个学期和科目的信息,无论他们是否通过。
我想画一条平行坐标的学生轨迹。我想看看走哪条路才能走到尽头
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 的块应该是下面第 1 学期的最大块。
连接线连接学生在本学期和下学期选修的科目。线的粗细对应于该点的连接数。例如,如果许多学生在第一学期未通过 math01 (math01fail) 并在第二学期重新参加 math01 并通过它 (math01pass),则 math01fail 和 math01pass 之间的连接线在出现次数方面应该更粗。
如何在 R 中创建这样的绘图?
我认为你最好从图形的角度来解决这个问题,而不是在平行坐标的上下文中。
这是我会做的:
从加载必要的库开始
library(tidyverse) library(igraph)
首先我们定义图的边列表。为此,我们将
df
与ID
和 select 对应于连续(递增)项的行进行自连接。然后每一行对应于每个学生从学期 i 到 i+1 的 link。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
前两列中的条目匹配。我们现在准备好从两个
data.frame
构造一个igraph
并绘制图形。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)
生成的图可能需要进一步 tweaking/polishing,但这应该可以帮助您入门。