代码之家  ›  专栏  ›  技术社区  ›  John Gagnon

基于密度的数据帧子集

  •  0
  • John Gagnon  · 技术社区  · 7 年前

    我正在寻找一个函数,它允许基于二元观测的密度对数据帧进行子集设置。例如:

    ggplot(iris, aes(x = Petal.Length, y = Sepal.Width, color = Species)) + 
      stat_density2d(geom = 'polygon', aes(fill = ..level..), n = 8) + 
      geom_point()
    

    在这里,我只想根据一个物种内点的密度来显示异常点(即,只显示setosa的3个点和virginica的4个点,它们位于轮廓之外)。

    2 回复  |  直到 7 年前
        1
  •  1
  •   C-x C-c    7 年前

    我的方法有点复杂,请容忍我,我将解释如下:

    library(data.table)
    dt <- as.data.table(iris)[, .(Petal.Length, Sepal.Width, Species)]
    dt[, sample := .I]
    dt <- melt(dt, id.vars = c("Species", "sample"))
    dt[, c("meanval", "sdval") := .(mean(value), sd(value)), .(Species, variable)]
    dt[abs({value - meanval} / sdval) > 2, outlier := TRUE]
    dt[, anyOutliers := sum(outlier, na.rm = T), sample]
    dt[anyOutliers != 0, outlier := TRUE]
    dt <- dcast(
      dt[, .(Species, variable, value, outlier, sample)],
      sample + outlier + Species ~ variable,
      value.var = "value"
    )
    

    首先我们指定 dt 作为数据集,只保留我们计划打印的列。接下来,我们分配一个虚拟列,这对于这个特定的数据集日后区分行很重要。然后我们 melt() 方便使用的数据集。然后,对于每个物种,我们计算每个值的平均值和标准差。这允许我们在下面的行中定义异常值(您可以更改 > 2 这里影响要使用的sd的数量)。

    然后,对于每一朵花,我们发现在我们选择的任何一个度量中它是否是一个异常值(在本例中是花瓣长度和萼片宽度)。如果是的话,整朵花都会被标记为异常值。然后,我们将表还原为原来的形式,只是现在有一个离群值列,显示花在任何out度量中是否是离群值。

    我不打算去策划这些,因为你可以自己搞清楚你想怎么做,但这应该给一个大致的方向。希望能有所帮助。

        2
  •  1
  •   LucyMLi    7 年前

    这是一个相当简单的解决方案,但是您可以编写一个函数来提取等高线图之外的点,并返回仅包含这些点的数据帧:

    plot_outliers_only <- function (original_plot) {
      require(ggplot2)
      require(sp)
      pb <- ggplot_build(original_plot)
      group_labels <- grep("001", levels(pb$data[[1]]$group), value=TRUE)
      outlier_points <- lapply(group_labels, function (gl) {
        contour_data <- filter(pb$data[[1]], as.character(group)==gl)
        original_data <- 
        group_id <- as.numeric(strsplit(gl, "-")[[1]][1])
        outlier_id <- pb$data[[2]] %>%
          filter(group==group_id) %>%
          select(c(x, y)) %>%
          apply(1, function (point) {
            point.in.polygon(point[1], point[2], contour_data$x, contour_data$y)==0
          }) %>%
          which()
        if (length(outlier_id)==0) return (outlier_id)
        grouping_name <- as.character(original_plot$mapping$colour)
        as.numeric(original_plot$data[, grouping_name]) %>%
          `==`(group_id) %>%
          which() %>%
          slice(original_plot$data, .) %>%
          `[`(., outlier_id, )
      })
      do.call(what=rbind, outlier_points)
    }
    
    P <- ggplot(iris, aes(x = Petal.Length, y = Sepal.Width, color = Species)) + 
        stat_density2d(geom = 'polygon', aes(fill = ..level..), n = 8) + 
        geom_point()
    
    plot_outliers_only(P)