我有数据框,例如:
productid ordernum
p1 10
p2 20
p3 30
p4 5
p5 20
p6 8
我想添加另一个名为 groupid 的列,它将产品按顺序组合在一起,一旦 sum(ordernum) 达到 30 ,就分配一个新的组 ID,例如结果应该是
productid ordernum groupid
p1 10 1
p2 20 1
p3 30 2
p4 5 3
p5 20 3
p6 8 3
通过循环很容易做到这一点,我如何在不循环的情况下实现这一目标?
最佳答案
短的怎么样c++
已写 for
循环使用 Rcpp
.这个小函数需要一个 numeric
向量,即您的 ordernum
列和 threshold
参数(要从中开始新 ID 的累积总和)并返回长度等于输入向量的 ID 向量。应该运行得相对较快,因为它是 for
在 c++
中循环.下面的代码片段将安装 Rcpp
如果您还没有安装它并且将编译该函数以供使用,则为您准备。只需复制并粘贴到 R...
if( !require(Rcpp) ) install.packages("Rcpp"); require(Rcpp)
Rcpp::cppFunction( ' NumericVector grpid( NumericVector x , int threshold ){
int n = x.size();
NumericVector out(n);
int tot = 0;
int id = 1;
for( int i = 0; i < n; ++i){
tot += x[i];
out[i] = id;
if( tot >= threshold ){
id += 1;
tot = 0;
}
}
return out;
}')
然后要使用该函数,只需像任何其他 R 函数一样使用它,提供相关参数:
df$groupid <- grpid( df$ordernum , 30 )
# productid ordernum groupid
#1 p1 10 1
#2 p2 20 1
#3 p3 30 2
#4 p4 5 3
#5 p5 20 3
#6 p6 8 3
基准比较
OP 要求我针对基本 R for 循环对 Rcpp 循环进行基准测试。这是代码和结果。在包含 100,000 个产品 ID 的向量上,速度提高了大约 400 倍:
set.seed(1)
x <- sample(30,1e5,repl=T)
for.loop <- quote({
tot <- 0
id <- 1
out <- numeric(length(x))
for( i in 1:length(x) ){
tot <- tot + x[i]
out[i] <- id
if( tot >= 30 ){
tot <- 0
id <- id + 1
}
}
})
rcpp.loop <- quote( out <- grpid(x,30))
require( microbenchmark )
print( bm , unit = "relative" , digits = 2 , "median" )
Unit: relative
expr min lq median uq max neval
eval(rcpp.loop) 1 1 1 1 1 50
eval(for.loop) 533 462 442 428 325 50
关于r - 如何在不循环的情况下添加组 ID?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18530605/