Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 拆分向量并求和值_R_Split_Cut - Fatal编程技术网

R 拆分向量并求和值

R 拆分向量并求和值,r,split,cut,R,Split,Cut,我是个新手。我有一个向量 vec <- c(105,29,41,70,77,0,56,49,63,0,105) vec从这个向量开始 > vec [1] 105 29 41 70 77 0 56 49 63 0 105 我们可以计算逻辑真/假向量,其中零为: > vec == 0 [1] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE 当你加上FALSE和TRUE

我是个新手。我有一个向量

vec <- c(105,29,41,70,77,0,56,49,63,0,105)

vec从这个向量开始

> vec
 [1] 105  29  41  70  77   0  56  49  63   0 105
我们可以计算逻辑真/假向量,其中零为:

> vec == 0
 [1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE
当你加上FALSE和TRUE时,FALSE是0,TRUE是1,所以如果我们每次加上这个向量,值就会增加。因此,对累积和使用
cumsum
,我们得到:

> cumsum(vec==0)
 [1] 0 0 0 0 0 1 1 1 1 2 2
现在,该结果定义了我们要在其中添加的组,因此让我们根据该结果拆分vec:

> split(vec, cumsum(vec==0))
$`0`
[1] 105  29  41  70  77

$`1`
[1]  0 56 49 63

$`2`
[1]   0 105
所以除了第二部分和后面部分的零之外,这就是我们想要加起来的数字。因为我们在加,所以我们可以加零,这没有任何区别(但是如果你想要平均值,你就必须去掉零)。现在我们使用
sapply
迭代列表元素并计算总和:

> sapply(split(vec, cumsum(vec==0)),sum)
  0   1   2 
322 168 105 

工作完成了。忽略
0 1 2
标签。

聚合
函数对于这类事情很有用。使用
cumsum
创建分组变量(类似于@Spacedman的解释)。使用
sum
函数作为聚合操作。最后的
[[2]]
仅从
聚合返回的内容中提取所需内容:

aggregate(vec, by = list(cumsum(vec == 0)), FUN = sum)[[2]]

[1] 322 168 105

另一个选项是通过

as.numeric(by(vec, cumsum(vec == 0), sum))
#[1] 322 168 105

基准 基于
microbenchmark

# Create sample vector with N entries
set.seed(2018)
N <- 10000
vec <- sample(100, N, replace = T)
vec[sample(length(vec), 100)] <- 0

library(microbenchmark)
res <- microbenchmark(
    vapply = {
        I <- which(vec == 0)
        vapply(1:(length(I)+1),
            function(k) sum(vec[max(I[k-1],1):min(I[k], length(vec), na.rm = TRUE)]),
            numeric(1))
   },
   by = {
       as.numeric(by(vec, cumsum(vec == 0), sum))
   },
   aggregate = {
       aggregate(vec, by = list(cumsum(vec == 0)), FUN = sum)[[2]]
   },
   split = {
       sapply(split(vec, cumsum(vec == 0)), sum)
   },
   Reduce = {
       ans <- numeric(0)
       s <- n <- 0
       Reduce(f = function (y,x) {
           if(x == 0) {
               ans <<- c(ans,s)
               s <<- 0
           }
           n <<- n+1
           s <<- x+s
           if (n == length(vec))
               ans <<- c(ans,s)
           s
       }, vec, init = 0, accumulate = TRUE)
       ans
   },
   for_loop = {
       I   <- which(vec == 0)
       n   <- length(vec)
       N   <- length(I) + 1
       res <- numeric(N)
       for(k in seq_along(res)) {
           if (k == 1) {
               res[k] <- sum(vec[1:I[1]])
               next
           }
           if (k == N) {
               res[k] <- sum(vec[I[N-1]:n])
               next
           }
           res[k] <- sum(vec[I[k-1]:I[k]])
       }
       res
   }
)
res
#    Unit: microseconds
#      expr       min         lq       mean     median         uq       max
#    vapply   435.658   487.4230   621.6155   511.3625   607.2005  6175.039
#        by  3897.401  4187.2825  4721.3168  4436.5850  4936.2900 12365.351
# aggregate  4817.032  5392.0620  6002.2579  5831.2905  6310.3665  9782.524
#     split   611.175   758.4485   895.2201   838.7665   957.0085  1516.556
#    Reduce 21372.054 22169.9110 25363.8684 23022.6920 25503.6145 49255.714
#  for_loop 15172.255 15846.5735 17252.6895 16445.7900 17572.7535 34401.827

library(ggplot2)
autoplot(res)
#创建包含N个条目的样本向量
种子集(2018)
带着吸血鬼
这里有一个带有
vapply

I <- which(vec == 0)
vapply(1:(length(I)+1), 
       function(k) sum(vec[max(I[k-1],1):min(I[k], length(vec), na.rm = TRUE)]), 
       numeric(1))
# [1] 322 168 105

打圈 或者是一个老式的循环

I   <- which(vec == 0)
n   <- length(vec)
N   <- length(I) + 1
res <- numeric(N)
for(k in seq_along(res)) {
  if (k == 1) {
    res[k] <- sum(vec[1:I[1]])
    next
  }
  if (k == N) {
    res[k] <- sum(vec[I[N-1]:n])
    next
  }
  res[k] <- sum(vec[I[k-1]:I[k]])
}
res
# [1] 322 168 105
rowsum()
众所周知速度非常快。我们可以使用
cumsum(vec==0)
进行分组

c(rowsum(vec, cumsum(vec == 0)))
# [1] 322 168 105

尼斯:)我真的很喜欢那张图!我添加了两个sol(
Reduce
&
for
),循环似乎比所有其他解决方案都快得多(使用测试数据并且
时间=10^3
)。你会测试它并更新基准吗?(我自己做过,但我想既然你已经贴了,我会问:)@nate.edwinton done;-)这很奇怪,你知道为什么结果会有这么大的差异吗?我使用了完全相同的代码-只是将不同的解决方案包装为函数,并在
microbenchmark
@nate.edwinton中对它们进行了评估。您介意将
microbenchmark
比较的代码和输出包括在内吗?我不知道为什么结果会如此不同。我刚刚复制并粘贴了这些方法。这让我夜不能寐,所以我昨晚已经问过了哈哈(见这里)我已经将您的解决方案添加到基准测试中,没有外部
c()
虽然-应该不会有太大的区别。对于一些“max”时间,接近数量级的因子增加是有趣的。这是第一次运行需要编译还是什么?@Spacedman我恐怕不太明白。我也没能辨别出那些在-/减少中的模式。如果你重新运行基准测试,但是“时间”设置为2或3,并且仍然得到一个非常大的“最大值”和一个小的“最小值”,那么第一次重复似乎要花很长时间。对平均值影响不大,但如果代码只是一次性的,而不是在循环中,则第一次运行所花费的时间通常更为重要……还有
tapply
选项:
tapply(vec,cumsum(vec==0),sum)
I   <- which(vec == 0)
n   <- length(vec)
N   <- length(I) + 1
res <- numeric(N)
for(k in seq_along(res)) {
  if (k == 1) {
    res[k] <- sum(vec[1:I[1]])
    next
  }
  if (k == N) {
    res[k] <- sum(vec[I[N-1]:n])
    next
  }
  res[k] <- sum(vec[I[k-1]:I[k]])
}
res
# [1] 322 168 105
# c.f. @MauritsEvers
# Create sample vector with N entries
set.seed(2018)
N <- 10000
vec <- sample(100, N, replace = T)
vec[sample(length(vec), 100)] <- 0
reduce <- function(vec) {
  ans <- numeric(0)
  s <- n <- 0
  Reduce(f = function (y,x) {
    if(x == 0) {
      ans <<- c(ans,s)
      s <<- 0
    }
    n <<- n+1
    s <<- x+s
    if(n == length(vec))
     ans <<- c(ans,s)
     s 
  }, vec, init = 0, accumulate = TRUE)
  ans
}
Vapply <- function (vec) {
  I <- which(vec == 0)
  vapply(1:(length(I)+1), 
         function(k) sum(vec[max(I[k-1],1):min(I[k], length(vec), na.rm = TRUE)]), 
         numeric(1))
}
By <- function (vec) as.numeric(by(vec, cumsum(vec == 0), sum))
Split <- function (vec) sapply(split(vec, cumsum(vec==0)),sum)
Aggregate <- function (vec) aggregate(vec, by = list(cumsum(vec == 0)), FUN = sum)[[2]]
for_loop <- function(vec) {
  I <- which(vec == 0)
  n <- length(vec)
  N <- length(I)+1
  res <- numeric(N)
  for(k in seq_along(res)) {
    if (k == 1) {
      res[k] <- sum(vec[1:I[1]])
      next
    }
    if (k == N) {
      res[k] <- sum(vec[I[N-1]:n])
      next
    }
    res[k] <- sum(vec[I[k-1]:I[k]])
  }
  res
}
Rowsum <- function (vec) rowsum(vec, cumsum(vec == 0))
# c.f. @MauritsEvers
resBoth <- microbenchmark::microbenchmark(
  Vapply = {
    I <- which(vec == 0)
    vapply(1:(length(I)+1),
           function(k) sum(vec[max(I[k-1],1):min(I[k], length(vec), na.rm = TRUE)]),
           numeric(1))
  },
  Vapply(vec),
  By = {
    as.numeric(by(vec, cumsum(vec == 0), sum))
  },
  By(vec),
  Aggregate = {
    aggregate(vec, by = list(cumsum(vec == 0)), FUN = sum)[[2]]
  },
  Aggregate(vec),
  Split = {
    sapply(split(vec, cumsum(vec == 0)), sum)
  },
  Split(vec),
  reduce = {
    ans <- numeric(0)
    s <- n <- 0
    Reduce(f = function (y,x) {
      if(x == 0) {
        ans <<- c(ans,s)
        s <<- 0
      }
      n <<- n+1
      s <<- x+s
      if (n == length(vec))
        ans <<- c(ans,s)
      s
    }, vec, init = 0, accumulate = TRUE)
    ans
  },
  reduce(vec),
  for_loop = {
    I   <- which(vec == 0)
    n   <- length(vec)
    N   <- length(I) + 1
    res <- numeric(N)
    for(k in seq_along(res)) {
      if (k == 1) {
        res[k] <- sum(vec[1:I[1]])
        next
      }
      if (k == N) {
        res[k] <- sum(vec[I[N-1]:n])
        next
      }
      res[k] <- sum(vec[I[k-1]:I[k]])
    }
    res
  },
  for_loop(vec),
  Rowsum = {rowsum(vec, cumsum(vec == 0))},
  Rowsum(vec),
  times = 10^3
 )
resBoth
# Unit: microseconds
#           expr       min         lq       mean     median         uq       max neval     cld
#         Vapply   234.121   281.5280   358.0708   311.7955   343.5215  4775.018  1000 ab     
#    Vapply(vec)   234.850   278.6100   376.3956   306.3260   334.4050 14564.278  1000 ab     
#             By  1866.029  2108.7175  2468.1208  2209.0025  2370.5520 23316.045  1000   c    
#        By(vec)  1870.769  2120.5695  2473.1643  2217.3900  2390.6090 21039.762  1000   c    
#      Aggregate  2738.324  3015.6570  3298.0863  3117.9480  3313.2295 13328.404  1000    d   
# Aggregate(vec)  2733.583  2998.1530  3295.6874  3109.1955  3349.1500  8277.694  1000    d   
#          Split   359.202   412.0800   478.0553   444.1710   492.3080  4622.220  1000  b     
#     Split(vec)   366.131   410.4395   475.2633   444.1715   490.3025  4601.799  1000  b     
#         reduce 10862.491 13062.3755 15353.2826 14465.0870 16559.3990 76305.463  1000       g
#    reduce(vec) 10403.004 12448.9965 14658.4035 13825.9995 15893.3255 67337.080  1000      f 
#       for_loop  6687.724  7429.4670  8518.0470  7818.0250  9023.9955 27541.136  1000     e  
#  for_loop(vec)   123.624   145.8690   187.2201   157.5390   177.4140  9928.200  1000 a      
#         Rowsum   235.579   264.3880   305.7516   282.2570   322.7360   792.068  1000 ab     
#    Rowsum(vec)   239.590   264.9350   307.2508   284.8100   322.0060  1778.143  1000 ab  
c(rowsum(vec, cumsum(vec == 0)))
# [1] 322 168 105