我有一个数字向量
x <- c(2,5,1,6)
我试图生成一个值序列--从1开始--介于x中的值之间并包括x中的值,这样我就得到了以下字符串
x
1,2,3,4,5,4,3,2,1,2,3,4,5,6
我试图找到执行此任务所需的功能(e。但是我似乎找不到我需要做的事情。
a0zr77ik1#
这似乎是可行的,假设隐式初始值为1:
res <- Reduce(function(y, z) c(head(y,-1), tail(y,1):z), x, init=1L) # 1 2 3 4 5 4 3 2 1 2 3 4 5 6
如果必须将其作为逗号字符串:paste(res, collapse=",") .对于一个大问题,这将变得非常低效,因为我正在循环中增长一个对象。我建议在这种情况下使用Rcpp包,或者更仔细地计算。
paste(res, collapse=",")
zynd9foi2#
我们可以使用Rcpp实现。如果文件是'file1.人民党
Rcpp
#include <Rcpp.h> //[[Rcpp::export]] using namespace Rcpp; // [[Rcpp::export]] List rleC(NumericVector x) { std::vector<int> lengths; std::vector<double> values; // Initialise first value int i = 0; double prev = x[0]; values.push_back(prev); lengths.push_back(1); NumericVector::iterator it; for(it = x.begin() + 1; it != x.end(); ++it) { if (prev == *it) { lengths[i]++; } else { values.push_back(*it); lengths.push_back(1); i++; prev = *it; } } return List::create( _["lengths"] = lengths, _["values"] = values ); } // [[Rcpp::export]] Rcpp::NumericVector newSeq(Rcpp::NumericVector z) { int zlen = z.length(); Rcpp::List zlist(zlen); for(int i = 0; i < zlen; i++){ if(z[i+1] > z[i]) { zlist[i] = Rcpp::seq(z[i], z[i+1]); } else { zlist[i] = Rcpp::rev(Rcpp::seq(z[i+1], z[i])); } } Rcpp::Environment stats1("package:base"); Rcpp::Function unlist = stats1["unlist"]; return rleC(unlist(Rcpp::head(zlist, -1)))["values"]; }
我们把文件来源
library(Rcpp) sourceCpp("file1.cpp") c(1, newSeq(x)) #[1] 1 2 3 4 5 4 3 2 1 2 3 4 5 6
此外,使用base R选项(先前删除的答案)
base R
v1 <- rle(unlist(Map(":", x[-length(x)], x[-1])))$values c(seq(v1[1]), v1[-1]) #[1] 1 2 3 4 5 4 3 2 1 2 3 4 5 6
ki0zmccv3#
使用mapply的另一个解决方案:
mapply
c(1, unlist(mapply(function(s,e) tail(s:e,-1), head(c(1,x),-1), x))) #[1] 1 2 3 4 5 4 3 2 1 2 3 4 5 6
或
c(seq(x[1]-1), unlist(sapply(seq(length(x)-1), function(i) head(x[i]:x[i+1], -1))), tail(x,1)) #[1] 1 2 3 4 5 4 3 2 1 2 3 4 5 6
对标(base R解决方案)
base
library(microbenchmark) set.seed(1) x <- sample(1000, 500, replace = FALSE) f_Frank <- function(x) Reduce(function(y, z) c(head(y,-1), tail(y,1):z), x, init=1L) f_989_1 <- function(x) c(1, unlist(mapply(function(s,e) tail(s:e,-1), head(c(1,x),-1), x))) f_989_2 <- function(x) c(seq(x[1]-1), unlist(sapply(seq(length(x)-1), function(i) head(x[i]:x[i+1], -1))), tail(x,1)) f_akrun <- function(x){ v1 <- rle(unlist(Map(":", x[-length(x)], x[-1])))$values c(seq(v1[1]), v1[-1]) } r <- f_Frank(x) all(r==f_989_1(x)) #[1] TRUE all(r==f_989_2(x)) #[1] TRUE all(r==f_akrun(x)) #[1] TRUE res <- microbenchmark(f_Frank(x), f_989_1(x), f_989_2(x), f_akrun(x)) print(res, order="mean") # Unit: milliseconds # expr min lq mean median uq max neval # f_989_1(x) 5.851345 6.113956 6.627022 6.308359 7.256490 9.286613 100 # f_989_2(x) 5.604960 5.794707 7.260833 5.946143 6.876246 58.284487 100 # f_akrun(x) 6.826068 7.726124 13.491295 8.263214 8.983740 63.384959 100 # f_Frank(x) 287.564706 340.390713 351.593511 344.465231 359.258399 454.095461 100
hivapdat4#
类似于@Mike H。的注解,每个元素都是序列的开始或结束。使用矢量化的diff()和lapply也可以提高速度:
x <- c(2,5,1,6) xpand <- unlist(lapply(1:(length(x)-1),function(a){x[a]:x[a+1]})) xpand <- xpand[diff(xpand)!=0] #remove duplicates
如果你想让序列从1开始,只需要在x的开头绑定一个1。编辑:基准测试结果:
f_max <- function(x){ x <- c(1,x) v1 <- unlist(lapply(1:(length(x)-1),function(a){x[a]:x[a+1]})) v1[diff(v1)!=0] } expr min lq mean median uq max neval cld f_max(x) 3.1681 3.30260 5.094495 3.49680 5.03835 19.2932 100 a f_989_2(x) 3.6907 3.83715 6.019684 4.14230 5.61495 21.6221 100 a f_989_1(x) 4.2068 4.32475 6.275782 4.60405 6.02450 22.2171 100 a f_akrun(x) 5.0433 5.22070 8.345722 5.48435 8.84605 30.4506 100 a f_Frank(x) 130.6774 141.29090 217.772798 156.17090 181.07895 738.2167 100 b
j0pj023g5#
这是一个有趣的问题,用它玩approx或approxfun会很有趣
approx
approxfun
> k <- cumsum(abs(c(x[1], diff(x)))) > c(if (min(k) > 1) seq(min(k) - 1), approxfun(k, x)(min(k):max(k))) [1] 1 2 3 4 5 4 3 2 1 2 3 4 5 6
R
(有一些有趣的发现,见下面的结果)
借用989的基准测试示例即可。鉴于以下所述的方法
f_Frank <- function(x) Reduce(function(y, z) c(head(y, -1), tail(y, 1):z), x, init = 1L) f_989_1 <- function(x) c(1, unlist(mapply(function(s, e) tail(s:e, -1), head(c(1, x), -1), x))) f_989_2 <- function(x) { c( seq(x[1] - 1), unlist(sapply(seq(length(x) - 1), function(i) head(x[i]:x[i + 1], -1))), tail(x, 1) ) } f_akrun <- function(x) { v1 <- rle(unlist(Map(":", x[-length(x)], x[-1])))$values c(seq(v1[1]), v1[-1]) } f_TIC <- function(x) { k <- cumsum(abs(c(x[1], diff(x)))) c(if (min(k) > 1) seq(min(k) - 1), approxfun(k, x)(min(k):max(k))) }
我们运行一个长度为500的向量x
500
set.seed(1) x <- sample(1000, 500, replace = FALSE) bm <- microbenchmark( f_Frank(x), f_989_1(x), f_989_2(x), f_akrun(x), f_TIC(x), check = "equal" ) ggplot2::autoplot(bm)
我们会看到
然而,有趣的是,如果我们将x的长度增加到更长,例如5000,i。即x <- sample(5000, replace = FALSE),我们看到
5000
x <- sample(5000, replace = FALSE)
5条答案
按热度按时间a0zr77ik1#
这似乎是可行的,假设隐式初始值为1:
如果必须将其作为逗号字符串:
paste(res, collapse=",")
.对于一个大问题,这将变得非常低效,因为我正在循环中增长一个对象。我建议在这种情况下使用Rcpp包,或者更仔细地计算。
zynd9foi2#
我们可以使用
Rcpp
实现。如果文件是'file1.人民党我们把文件来源
此外,使用
base R
选项(先前删除的答案)ki0zmccv3#
使用
mapply
的另一个解决方案:或
对标(
base
R解决方案)hivapdat4#
类似于@Mike H。的注解,每个元素都是序列的开始或结束。使用矢量化的diff()和lapply也可以提高速度:
如果你想让序列从1开始,只需要在x的开头绑定一个1。
编辑:基准测试结果:
j0pj023g5#
这是一个有趣的问题,用它玩
approx
或approxfun
会很有趣基准测试(基础
R
选项)(有一些有趣的发现,见下面的结果)
借用989的基准测试示例即可。鉴于以下所述的方法
我们运行一个长度为
500
的向量x
我们会看到
然而,有趣的是,如果我们将
x
的长度增加到更长,例如5000
,i。即x <- sample(5000, replace = FALSE)
,我们看到