下面的代码根据$Weight列中的值更改$type列中的值.

n <- 1e3; m <- n*10
Treshold <- 50
wts      <-runif(m)
df  <- data.frame(id=seq_len(m), weight=wts * 100, type='L')

library(microbenchmark)
microbenchmark(
"df-col-row" = (df$type[df$weight < Treshold]   <- "M"),
"df-row-col" = (df[df$weight < Treshold, ]$type <- "M")
)
#
#Unit: microseconds
#       expr   min     lq    mean median     uq    max neval
# df-col-row  80.6  87.65 145.429  89.55 104.55 5109.1   100
# df-row-col 564.9 586.10 618.496 592.40 618.90 1601.0   100

为什么第一种替代方案比第二种方案快?

Update 1
正如预期的那样,添加的列越多,差异就越大.

d9  <- data.frame(type='L', weight=wts * 100, c3=3, c4=4, c5=5, c6=6, c7=7, c8=8, c9=9)
microbenchmark(
"df-row-9col" = (d9[d9$weight < Treshold, ]$type <- "M")
)
# nit: microseconds
#         expr   min      lq     mean median      uq  max neval
# df-row-9col 950.1 1091.55 1267.982 1111.1 1172.45 5806   100

Update 2
在第一个备选方案中,df被复制一次,在第二个备选方案中,被复制两次.

tracemem(df)
df$type[df$weight < Treshold]   <- "M"    # Alt 1.
#tracemem[0x000002c92d2b87c8 -> 0x000002c92d2b9498]: $<-.data.frame $<- 

df[df$weight < Treshold, ]$type <- "M"    # Alt 2.
#tracemem[0x000002c92d2b9498 -> 0x000002c92d2b9ad8]: 
#tracemem[0x000002c92d2b9ad8 -> 0x000002c92d2c47d8]: [<-.data.frame [<-
untracemem(df)

推荐答案

请记住,data.frame是建立在list的基础上的.例如,如果您是unclass(mtcars),您会看到它只是一个向量列表:

$mpg
 [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
[16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
[31] 15.0 21.4

$cyl
 [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4

$disp
 [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8
[13] 275.8 275.8 472.0 460.0 440.0  78.7  75.7  71.1 120.1 318.0 304.0 350.0
[25] 400.0  79.0 120.3  95.1 351.0 145.0 301.0 121.0

# ... 

这使得在筛选之前 Select 列更快的原因变得更加直观.这相当于从向量列表中 Select 向量的子集,然后仅对这些向量进行子集设置.而不是在列表中设置every个向量的子集,然后只保留其中的一些.

如果您unclass()个示例数据并对底层列表进行操作,我们将获得类似的完全不同的性能,但更清楚的是第二个操作更昂贵的原因:

set.seed(13)

library(microbenchmark)

undf <- unclass(df)

microbenchmark(
  "undf-col-row" = undf$type[undf$weight < Treshold],
  "undf-row-col" = lapply(undf, \(x) x[undf$weight < Treshold])$type
)
Unit: microseconds
         expr    min       lq     mean   median       uq       max neval cld
 undf-col-row  72.18  89.1200 103.0429 101.5650 112.1550   254.341   100  a 
 undf-row-col 201.87 269.9105 433.0011 282.4355 310.7255 14712.019   100   b

R相关问答推荐

R根据名称的载体对收件箱列采取行动

如何计算新变量中的通货inflating 率?

是否可以 Select 安装不带文档的R包以更有效地存储?

列出用m n个值替换来绘制n个数字的所有方法(i.o.w.:R中大小为n的集合的所有划分为m个不同子集)

更新合适的R mgcv::bam模型报告无效类型(关闭).'';错误

管道末端运行功能

警告:lmdif:info = 0. nls. lm()函数的输入参数不正确

如何直接从R中的风险分数计算c指数?

使用sf或terra的LINESTRAING的累积长度

计算时间段的ECDF(R)

如何在PackageStatus()中列出&q;不可用的包&q;?

基于R中的间隔扩展数据集行

如何在R中通过多个变量创建交叉表?

R如何计算现有行的总和以添加新的数据行

安全地测试文件是否通过R打开

如何将这个小列表转换为数据帧?

ggplot R:X,Y,Z使用固定/等距的X,Y坐标绘制六边形热图

为R中的16组参数生成10000个样本的有效方法是什么?

具有自定义仓位限制和计数的GGPLATE直方图

附加中缀操作符