【问题标题】:Average neighbours inside a vector向量内的平均邻居
【发布时间】:2018-12-10 11:40:11
【问题描述】:

我的数据:

data <- c(1,5,11,15,24,31,32,65)

有 2 个邻居:31 和 32。我希望删除它们并只保留平均值(例如31.5),这样数据将是:

data <- c(1,5,11,15,24,31.5,65)

看起来很简单,但我希望自动完成,有时使用包含更多邻居的向量。例如:

data_2 <- c(1,5,11,15,24,31,32,65,99,100,101,140)

【问题讨论】:

  • 这只是关于连续数字对还是关于更长的运行,例如31、32、33、34?
  • 也可以是更长的运行时间(比如 data_2 中的 99、100、101)
  • 也许使用cumsum(...diff(... 成语来创建组,例如tapply(data, cumsum(c(1L, diff(data) &gt; 1)), mean)
  • 你的数据排序了吗?
  • 是的,订单一直在增长

标签: r vector difference neighbours


【解决方案1】:

这是另一个通过cumsum(c(TRUE, diff(a) &gt; 1)) 创建 id 的想法,其中1 显示间隙阈值,即

#our group variable
grp <- cumsum(c(TRUE, diff(a) > 1))

#keep only groups with length 1 (i.e. with no neighbor)
i1 <- a[!!!ave(a, grp, FUN = function(i) length(i) > 1)] 

#Find the mean of the groups with more than 1 rows,
i2 <- unname(tapply(a, grp, function(i)mean(i[length(i) > 1])))

#Concatenate the above 2 (eliminating NAs from i2) to get final result
c(i1, i2[!is.na(i2)])
#[1]  1.0  5.0 11.0 15.0 24.0 65.0 31.5

您也可以将其包装在一个函数中。我把间隙作为参数留给大家调整,

get_vec <- function(x, gap) {
    grp <- cumsum(c(TRUE, diff(x) > gap))
    i1 <- x[!!!ave(x, grp, FUN = function(i) length(i) > 1)]
    i2 <- unname(tapply(x, grp, function(i) mean(i[length(i) > 1])))
    return(c(i1, i2[!is.na(i2)]))
}

get_vec(a, 1)
#[1]  1.0  5.0 11.0 15.0 24.0 65.0 31.5

get_vec(a_2, 1)
#[1]   1.0   5.0  11.0  15.0  24.0  65.0 140.0  31.5 100.0

数据:

a <- c(1,5,11,15,24,31,32,65)
a_2 <- c(1, 5, 11, 15, 24, 31, 32, 65, 99, 100, 101, 140)

【讨论】:

    【解决方案2】:

    这是我的解决方案,它使用游程编码来识别组:

    foo <- function(x) {
      y <- x - seq_along(x) #normalize to zero differences in groups
      ind <- rle(y) #run-length encoding
      ind$values <- ind$lengths != 1 #to find groups
      ind$values[ind$values] <- cumsum(ind$values[ind$values]) #group ids
      ind <- inverse.rle(ind)
      xnew <- x
      xnew[ind != 0] <- ave(x, ind, FUN = mean)[ind != 0] #calculate means
      xnew[!(duplicated(ind) & ind != 0)] #remove duplicates from groups
    }
    
    foo(data)
    #[1]  1.0  5.0 11.0 15.0 24.0 31.5 65.0
    foo(data_2)
    #[1]   1.0   5.0  11.0  15.0  24.0  31.5  65.0 100.0 140.0
    data_3 <- c(1, 2, 4, 1, 2)
    foo(data_3)
    #[1] 1.5 4.0 1.5
    

    我假设您不需要非常有效的解决方案。如果你这样做,我建议在 Rcpp 中使用一个简单的 C++ for 循环。

    【讨论】:

      【解决方案3】:

      我有一个基于 data.table 的解决方案,我猜同样可以翻译成 dplyr:

      library(data.table)
      df <- data.table(data2 = c(1,5,11,15,24,31,32,65,99,100,101,140))
      df[,neighbours := ifelse(c(0,diff(data_2)) == 1,1,0)]
      df[,neighbours := c(neighbours[1:(.N-1)],1),by = rleid(neighbours)]
      df[,neigh_seq := rleid(neighbours)]
      
      unique(df[,ifelse(neighbours == 1,mean(data2),data2),by = neigh_seq])
      
         neigh_seq    V1
      1:         1   1.0
      2:         1   5.0
      3:         1  11.0
      4:         1  15.0
      5:         1  24.0
      6:         2  31.5
      7:         3  65.0
      8:         4 100.0
      9:         5 140.0
      

      它的作用: 如果与以下数字的差为 1,则第一行将 neigbours 设置为 1

       1:     1          0
       2:     5          0
       3:    11          0
       4:    15          0
       5:    24          0
       6:    31          0
       7:    32          1
       8:    65          0
       9:    99          0
      10:   100          1
      11:   101          1
      12:   140          0
      

      我想对所有邻居进行分组,以便 neighbour 变量为 1。我需要在每个组的每一端添加 1:

      df[,neighbours := c(neighbours[1:(.N-1)],1),by = rleid(neighbours)]
          data2 neighbours
       1:     1          0
       2:     5          0
       3:    11          0
       4:    15          0
       5:    24          0
       6:    31          1
       7:    32          1
       8:    65          0
       9:    99          1
      10:   100          1
      11:   101          1
      12:   140          0
      

      然后,我只是对更改 neighbour 值进行分组,并将该值设置为表示它们是否是邻居

      df[,ifelse(neighbours == 1,mean(data2),data2),by = rleid(neighbours)]
          rleid    V1
       1:     1   1.0
       2:     1   5.0
       3:     1  11.0
       4:     1  15.0
       5:     1  24.0
       6:     2  31.5
       7:     2  31.5
       8:     3  65.0
       9:     4 100.0
      10:     4 100.0
      11:     4 100.0
      12:     5 140.0
      

      并获取唯一值。瞧。

      【讨论】:

        【解决方案4】:

        这是一个dplyr 版本,也用作分组变量cumsum(c(1,diff(x)!=1))

        library(dplyr)
        data_2 %>% data.frame(x = .) %>% 
        group_by(id = cumsum(c(1,diff(x)!=1))) %>% 
        summarise(res = mean(x)) %>% 
        select(res)
        # A tibble: 9 x 1
            res
          <dbl>
        1   1.0
        2   5.0
        3  11.0
        4  15.0
        5  24.0
        6  31.5
        7  65.0
        8 100.0
        9 140.0
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-03
          • 1970-01-01
          • 1970-01-01
          • 2014-10-31
          • 1970-01-01
          • 2023-02-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多