当前位置: 首页 > 知识库问答 >
问题:

r删除不适合序列的值

司马昕
2023-03-14

我有一个序列s,其中我期望每个过程值与前一个相同或1。

s = c(1,1,1,1,2,2,2,-2,3,3,4,8,8,8,9,5,5,12,6)

我想要什么:

1,1,1,1,2,2,2,3,3,4,5,5,6

我用以下代码解决了这个问题:

counter = 2
repeat{
  
  if(s[counter] == s[counter-1] | s[counter] == s[counter-1]+1){
    counter = counter+1
  } else{
    s = s[-counter]
  }
  
  if(counter >= length(s)) break
}

然而,这看起来相当“肮脏”和低效。有没有计算上耗时更少的解决方案?

共有3个答案

张心水
2023-03-14

编辑

R概念翻译成Rcpp:

Rcpp::cppFunction('LogicalVector foo(NumericVector s) {
  int n = s.size();
  Rcpp::LogicalVector keep(n);
  keep[0]  = 1;
  int last = 0;
  for (int i = 1; i < n; i++) {
    if        (s[i] - s[last] == 0) {
      keep[i] = 1;
    } else if (s[i] - s[last] == 1) {
      keep[i] = 1;
      last = i;
    } 
  }
  return keep;
}')


s[foo(s)]
# [1] 1 1 1 1 2 2 2 3 3 4 5 5 6

原始解决方案(非常相似,但不如Flick先生的):

另一个稍微高效的R循环。然而,如果效率很重要,Rcpp可能是一个不错的选择。

keep      = vector(length = length(s))
keep[1]   = TRUE
last_keep = 1L
for (counter in 2:length(s)) {
  if ((s[counter] - s[last_keep]) %in% c(0, 1)) {
    last_keep = counter
    keep[counter] = TRUE
  }
}
s[keep]

# [1] 1 1 1 1 2 2 2 3 3 4 5 5 6
闻人和泽
2023-03-14

这可以通过< code>Reduce来完成:

Reduce(function(prev, this) 
  c(prev, if (any(this %in% (prev[length(prev)] + 0:1))) this),
  s)
#  [1] 1 1 1 1 2 2 2 3 3 4 5 5 6

这不能被矢量化,因为一个位置上的计算依赖于先前计算的结果,但是这是紧凑的和(imo)可读的。

仅供参考,如果性能是你的主要指标,那么sindri_baldur的Rcpp和Flick先生目前的答案似乎以压倒性优势胜出:

bench::mark(
sindri_baldur = {
  keep      = vector(length = length(s))
  keep[1]   = TRUE
  last_keep = 1L
  for (counter in 2:length(s)) {
    if ((s[counter] - s[last_keep]) %in% c(0, 1)) {
      last_keep = counter
      keep[counter] = TRUE
    }
  }
  s[keep]
},
sindri_baldur_rcpp = s[foo(s)],
r2evans = {
  Reduce(function(prev, this) 
    c(prev, if (any(this %in% (prev[length(prev)] + 0:1))) this),
    s)
},
MrFlick = increasing_seq(s))
# # A tibble: 4 x 13
#   expression              min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result     memory     time     gc       
#   <bch:expr>         <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list>     <list>     <list>   <list>   
# 1 sindri_baldur        2.62ms   3.05ms      317.   37.81KB     15.5   143     7    450.5ms <dbl [13]> <Rprofmem~ <bench_~ <tibble ~
# 2 sindri_baldur_rcpp      1us    1.4us   533120.    2.49KB      0   10000     0     18.8ms <dbl [13]> <Rprofmem~ <bench_~ <tibble ~
# 3 r2evans              28.5us   36.9us    23454.   24.67KB     18.8  9992     8      426ms <dbl [13]> <Rprofmem~ <bench_~ <tibble ~
# 4 MrFlick               2.1us    2.5us   345770.        0B      0   10000     0     28.9ms <dbl [13]> <Rprofmem~ <bench_~ <tibble ~
康文昌
2023-03-14

我看不到一个简单的基于向量的解决方案,但是一个带预分配的普通for循环在这里会有所帮助

s = c(1,1,1,1,2,2,2,-2,3,3,4,8,8,8,9,5,5,12,6)
increasing_seq <- function(x) {
  keep <- logical(length(x))
  current <- x[1]
  for (i in seq_along(x)) {
    if (x[i] == current) {
      keep[i] <- TRUE
    } else if (x[i] == current + 1) {
      current <- current + 1
      keep[i] <- TRUE
    }
  }
  x[keep]
}
increasing_seq(s)
# [1] 1 1 1 1 2 2 2 3 3 4 5 5 6

这里我们避免重新创建不同大小的< code>s向量。通常是重新分配很慢,而不是循环

 类似资料:
  • 我有一个dataframe和要删除dataframe中的列列表。让我们使用数据集作为示例。我希望删除和,只使用剩余的列。如何使用或从包中执行此操作? drop.cols中的错误:参数类型无效 我觉得我错过了一些明显的东西,因为这些看起来像是一个相当有用的操作,应该已经存在了。在Github上,有人发布了一个类似的问题,Hadley说要使用“负面索引”。那是(我想)我试过的,但没有效果。有什么建议吗

  • 我有一个包含和以及的字符串。 我们如何删除和,同时保持机智?

  • 问题内容: 我有一张桌子。为了快速升级/部署网站,我做了一个新表,其中包含一些新数据,方法是: 现在每个表都有一个PK列,看起来像: 重要的一点是,两个表都依赖于完全相同的序列。没有。就我的目的而言,这似乎还可以。 此后,我加载了新数据并重命名了表,以便将其作为实盘接管,而原始表变成了。现在我尝试删除: 足够公平,列默认值仍取决于顺序。 这是踢脚线。 因此,不再对序列具有任何可见的依赖关系,但是它

  • 本文向大家介绍如何通过R中data.table中的列名删除列?,包括了如何通过R中data.table中的列名删除列?的使用技巧和注意事项,需要的朋友参考一下 我们可以通过将列设置为NULL来实现 示例 删除一列x 删除两列

  • 问题内容: 我有脏数据。有时它包含像字符这样。我使用这些数据进行查询 对于这个角色我得到 org.hibernate.exception.GenericJDBCException:操作’IN’的排序规则(utf8_bin,IMPLICIT),(utf8mb4_general_ci,COERCIBLE),(utf8mb4_general_ci,COERCIBLE)的非法混合 如何过滤出这样的字符?我

  • 为此,我尝试使用lapply和一个自定义函数: 我知道我可以用一堆联合声明来做到这一点,或者也许有一种方法可以用循环和联合来做到这一点。但是考虑到需要遍历的列数,我想尝试用一种更优雅的方式来完成它。