【问题标题】:subset() of a vector in RR中向量的子集()
【发布时间】:2012-01-19 21:19:23
【问题描述】:

我基于subset()编写了以下函数,我觉得很方便:

ss <- function (x, subset, ...) 
{
    r <- eval(substitute(subset), data.frame(.=x), parent.frame())
    if (!is.logical(r)) 
        stop("'subset' must be logical")
    x[r & !is.na(r)]
}

所以,我可以写:

ss(myDataFrame$MyVariableName, 500 < . & . < 1500)

而不是

myDataFrame$MyVariableName[ 500 < myDataFrame$MyVariableName 
                                & myDataFrame$MyVariableName < 1500]

这似乎是其他人可能已经开发出解决方案的东西 - 包括我可能错过的核心 R 中的一些东西。已经有什么了吗?

【问题讨论】:

  • 如果我们将data.frame(.=x) 更改为list(.=x),它似乎仍然有效,我怀疑性能会提高。
  • 澄清一下——我只是用myDataFrame$MyVariableName作为一个很长的向量名称的例子。我可能应该使用myVeryVeryVeryLongVariableName 或其他东西,但如果我现在编辑它,@joran 的回答将没有多大意义。 =)

标签: r subset


【解决方案1】:

我意识到 Ken 提供的解决方案比仅在范围内选择项目更通用(因为它应该适用于任何逻辑表达式)但这确实提醒我 Greg Snow 在他的教学演示包中有比较中缀运算符:

library(TeachingDemos)
x0 <- rnorm(100)
x0[ 0 %<% x0 %<% 1.5 ]

【讨论】:

  • 酷!我也一直想要一个 x &lt; y &lt; z 构造。
  • 我记得当 Perl 遇到这样的事情时 - 他们意识到他们已经有一个致命错误说“你使用了 'x
  • 注意a &lt; x &lt; b等价于abs(x-mean(c(a,b))) &lt; (b-mean(c(a,b)))
  • @James 当您只想评估一次 x 时很方便。
【解决方案2】:

感谢肯分享。

你可以使用:

x <- myDataFrame$MyVariableName; x[x > 100 & x < 180] 

您的代码可能需要较少的输入,但如果您共享代码,则代码对其他人的概括性较差。我自己也有一些类似的节省时间的功能,但要谨慎使用它们,因为它们可能会减慢您的代码(额外步骤),并且在您与其他人共享文件时还要求您还包含该功能的代码。

比较写作长度。几乎相同的长度:

ss(mtcars$hp, 100 < . & . < 180)
x <- mtcars$hp; x[x > 100 & x < 180] 

比较 1000 次复制的时间。

library(rbenchmark)
benchmark(
       tyler = x[x > 100 & x < 180],
       ken = ss(mtcars$hp, 100 <. & . < 180),
 replications=1000)

   test replications elapsed relative user.self sys.self user.child sys.child
2   ken         1000    0.56 18.66667      0.36     0.03         NA        NA
1 tyler         1000    0.03  1.00000      0.03     0.00         NA        NA

所以我想这取决于您是否需要速度和/或可共享性与便利性。如果它只适合您在一个小型数据集上使用,我会说它很有价值。

编辑:新基准测试

> benchmark(
+     tyler = {x <- mtcars$hp; x[x > 100 & x < 180]}, 
+     ken = ss(mtcars$hp, 100 <. & . < 180), 
+     ken2 = ss2(mtcars$hp, 100 <. & . < 180),
+     joran = with(mtcars,hp[hp>100 & hp< 180 ]), 
+  replications=10000)

   test replications elapsed  relative user.self sys.self user.child sys.child
4 joran        10000    0.83  2.677419      0.69     0.00         NA        NA
2   ken        10000    3.79 12.225806      3.45     0.02         NA        NA
3  ken2        10000    0.67  2.161290      0.35     0.00         NA        NA
1 tyler        10000    0.31  1.000000      0.20     0.00         NA        NA

【讨论】:

  • 是的,我也想过这个问题——当然,这本质上就是我在 ss() 函数中所做的,但我的 x 被命名为 .。
  • 至于速度,我采纳了@DWin 的建议,在这个基准上看到了大约 10 倍的改进。 benchmark( tyler = {x &lt;- mtcars$hp; x[x &gt; 100 &amp; x &lt; 180]}, ken = ss(mtcars$hp, 100 &lt;. &amp; . &lt; 180), ken2 = ss2(mtcars$hp, 100 &lt;. &amp; . &lt; 180),+ replications=10000) test replications elapsed relative user.self sys.self user.child sys.child 2 ken 10000 2.26 15.06667 2.25 0 NA NA 3 ken2 10000 0.24 1.60000 0.25 0 NA NA 1 tyler 10000 0.15 1.00000 0.15 0 NA NA
  • 呸,一点都不漂亮!
  • 我在该基准测试中更改的另一件事是在 tyler 代码中包含对 x 的分配。
  • Ken 只需将代码添加到您的原始帖子或作为底部的答案
猜你喜欢
  • 1970-01-01
  • 2020-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 2021-06-16
相关资源
最近更新 更多