0

我有如下的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 学期以下的最大块。

连接线将学生在本学期学习的科目与下一学期联系起来。线的粗细对应于该点的连接数。例如,如果许多学生在第 1 学期未通过 math01 (math01fail) 并在第 2 学期重修 math01 并通过 (math01pass),则 math01fail 和 math01pass 之间的连接线在出现次数方面应该更粗。

如何在 R 中创建这样的图? 在此处输入图像描述

4

1 回答 1

1

我认为你最好从图形的角度来解决这个问题,而不是在平行坐标的背景下。

这是我要做的:

  1. 首先加载必要的库

    library(tidyverse)
    library(igraph)
    
  2. 首先,我们定义图的边列表。为此,我们对dfby进行自连接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个学生设置更粗的线条。

  3. 接下来我们定义一个节点列表。这里的关键是添加列xy这将确定节点的网格布局。

    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")
    

    请注意,nlneed 的第一列中的条目与 的前两列中的条目相匹配el

  4. 我们现在准备igraph从两个data.frames 构造一个并绘制图形。

    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)
    

    在此处输入图像描述

    由此产生的情节可能需要一些进一步的调整/抛光,但这应该让你开始。

于 2018-11-28T06:32:58.000 回答