r - 计算 R 中每个组的凸包

标签 r dplyr tibble

我有以下数据集:

structure(list(time = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 
3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L), 
x = c(40.8914337158203, 20.0796813964844, 13.9093618392944, 
17.1513957977295, 18.5109558105469, 40.7868537902832, 19.9750995635986, 
13.804780960083, 16.8376483917236, 18.4063758850098, 40.6822700500488, 
19.7659358978271, 13.7001991271973, 16.6284866333008, 18.3017921447754, 
40.5776901245117, 19.66135597229, 13.5956182479858, 16.3147411346436, 
18.1972122192383, 40.5776901245117, 19.5567722320557, 13.4910354614258, 
16.1055774688721, 17.9880485534668), y = c(0.603550314903259, 
-8.24852085113525, 9.65680503845215, -19.0118350982666, 6.43787002563477, 
0.704141974449158, -8.34911251068115, 9.75739574432373, -19.2130165100098, 
6.43787002563477, 0.704141974449158, -8.44970417022705, 9.75739574432373, 
-19.5147914886475, 6.43787002563477, 0.704141974449158, -8.65088748931885, 
9.85798835754395, -19.8165683746338, 6.33727836608887, 0.704141974449158, 
-8.85207080841064, 9.85798835754395, -20.1183433532715, 6.33727836608887
), object = c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 1L, 
2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L)), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -25L), .Names = c("time", 
"x", "y", "object"))

现在,我想为 chull 的每个值计算一个凸包(使用 time 函数)并将其存储在同一个数据集中(因为我想用 ggplot2 绘制一个图)。
我可以用 chull对于每个使用 with 的时间值
chull(filter(data_sample, time == 1)$x, filter(data_sample, time == 1)$y)

返回 4 3 1 的向量.所以我认为我可以先按时间分组,然后用类似的方法计算组内的凸包点
data_sample %>% group_by(time) %>% summarise(pts = chull(data_sample$x, data_sample$y))

问题是我不能连续存储向量。将每个顶点存储在单独的列中将是一个选项,但以下
data_sample %>% group_by(time) %>% summarise(pt1 = chull(data_sample$x, data_sample$y)[1])

没有给出合理的结果。所以我的问题是:
1. 如何为一列中的每一行存储一个向量?我已经读过 tibbles 实际上可以有一个列表列,但是在我的情况下如何创建它?
2. 我试图计算 chull 有什么问题?每个组内?
  • (额外的问题,如果可以的话)为什么实际上 data_sample %>% filter(time == 1) %>% chull(.$x, .$y)不起作用?这是因为chull不是设计用于管道和 dplyr ?
  • 最佳答案

    chull正在为您提供原始数据的索引,您可能希望随时保留坐标,这意味着您可能不应该使用 summarize .我建议你使用“嵌套”概念,就像 tidyr 一样。 .第一步是嵌套数据:

    library(tidyr)
    data_sample %>%
      group_by(time) %>%
      nest()
    # # A tibble: 5 × 2
    #    time             data
    #   <int>           <list>
    # 1     1 <tibble [5 × 3]>
    # 2     2 <tibble [5 × 3]>
    # 3     3 <tibble [5 × 3]>
    # 4     4 <tibble [5 × 3]>
    # 5     5 <tibble [5 × 3]>
    

    从这里开始,只需计算 shell (它将返回索引向量),然后按照提供的顺序输出相关行。这将受益于 map purrr 提供的功能:
    library(purrr)
    data_sample %>%    data_sample %>%
      group_by(time) %>%
      nest() %>%
      mutate(
        hull = map(data, ~ with(.x, chull(x, y))),
        out = map2(data, hull, ~ .x[.y,,drop=FALSE])
      )
    # # A tibble: 5 × 4
    #    time             data      hull              out
    #   <int>           <list>    <list>           <list>
    # 1     1 <tibble [5 × 3]> <int [3]> <tibble [3 × 3]>
    # 2     2 <tibble [5 × 3]> <int [3]> <tibble [3 × 3]>
    # 3     3 <tibble [5 × 3]> <int [3]> <tibble [3 × 3]>
    # 4     4 <tibble [5 × 3]> <int [3]> <tibble [3 × 3]>
    # 5     5 <tibble [5 × 3]> <int [3]> <tibble [3 × 3]>
    

    (您应该能够将两个作业放入单个 mutate 中。我

    从这里,您可以通过删除现在不需要的列并取消嵌套将其转换为您需要的坐标:
    data_sample %>%
      group_by(time) %>%
      nest() %>%
      mutate(
        hull = map(data, ~ with(.x, chull(x, y))),
        out = map2(data, hull, ~ .x[.y,,drop=FALSE])
      ) %>%
      select(-data) %>%
      unnest()
    # # A tibble: 15 × 5
    #     time  hull        x           y object
    #    <int> <int>    <dbl>       <dbl>  <int>
    # 1      1     4 17.15140 -19.0118351      4
    # 2      1     3 13.90936   9.6568050      3
    # 3      1     1 40.89143   0.6035503      1
    # 4      2     4 16.83765 -19.2130165      4
    # 5      2     3 13.80478   9.7573957      3
    # 6      2     1 40.78685   0.7041420      1
    # 7      3     4 16.62849 -19.5147915      4
    # 8      3     3 13.70020   9.7573957      3
    # 9      3     1 40.68227   0.7041420      1
    # 10     4     4 16.31474 -19.8165684      4
    # 11     4     3 13.59562   9.8579884      3
    # 12     4     1 40.57769   0.7041420      1
    # 13     5     4 16.10558 -20.1183434      4
    # 14     5     3 13.49104   9.8579884      3
    # 15     5     1 40.57769   0.7041420      1
    

    (我将 hull 保留在此处用于演示目的;您可能可以在上面的 select(-data, -hull) 中使用,因为您将拥有所需的东西,尤其是如果 object 是多余的。)

    对于您的最后一个问题,您可以执行以下任一操作:
    filter(data_sample, time == 1) %>%
      with(., chull(x, y))
    with(filter(data_sample, time == 1), chull(x, y))
    

    关于r - 计算 R 中每个组的凸包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50117043/

    相关文章:

    r - bind_rows 到每组 tibble

    r - 从 Shiny 的输入创建数据框

    R:大向量的高效迭代子集和过滤

    R中数据的行比较

    子集后小标题中的行号 - R编程

    r - Tibble 默默地更改回收的 difftime 变量

    r - 使用 Xaringan 显示彩色背景方程时出现问题

    R grep特殊字符存储在变量中

    r - 在连续的x轴上按组填充和躲避箱线图

    r - 使用 dplyr 创建虚拟变量