【问题标题】:Subset function does not evaluate arguments子集函数不评估参数
【发布时间】:2014-09-14 18:59:17
【问题描述】:

使用下面称为“数据”的数据框,我可以直接将值分配给两个变量“状态”和“测量”,并确定子集中得分最低的学校:

创建数据框“数据”:

school<-c("NYU", "BYU", "USC", "FIT", "Oswego","UCLA","USF","Columbia")
state<-c("NY","UT","CA","NY","NY","CA", "CA","NY")
measure<-c("MSAT","MSAT","GPA","MSAT","MSAT","GPA","GPA","GPA")
score<-c(590, 490, 2.9, 759, 550, 1.2, 3.1, 3.2)
data<-data.frame(school,state, measure,score)

“状态”和“测量”的子集:

answer<-subset(data,subset=(state=="NY" & measure=="MSAT"))
order.answer<-order(answer$score,answer$school) #answer$school is tie-breaker
answer1<-as.matrix(answer[order.answer,])
answer1[1,1]

这是正确答案:

[1] "Oswego"

我的问题是当我创建一个函数来完成同样的事情时,我得到了一个不正确的结果:

lowest <- function(state, measure){
    answer<-subset(data,subset=(state==state & measure==measure))
    order.answer<-order(answer$score,answer$school)
    answer1<-as.matrix(answer[order.answer,])
    answer1[1,1]
  }

lowest("NY","MSAT")

错误答案:

[1] "UCLA"

问题似乎是变量“状态”和“测量”不采用函数子集行中参数“NY”和“MSAT”的值。我已经尝试使用 '=' 而不是 '==' 并且还尝试了子集(数据,子集=(状态==“状态” & measure==“测量”)),但找不到解决方案。

【问题讨论】:

    标签: r function subset argument-passing


    【解决方案1】:

    您的函数调用中似乎有些问题与您的函数参数与您的数据列相同这一事实有关,因为这有效

    lowest <- function(State, Measure){
      answer<-subset(data,subset=(state==State & measure==Measure))
      order.answer<-order(answer$score,answer$school)
      answer1<-as.matrix(answer[order.answer,])
      answer1[1,1]
    }
    ##
    > lowest("NY","MSAT")
    [1] "Oswego"
    

    更新:在仔细考虑之后,我想我可以提供更多关于内部发生的事情的细节。请注意,您的第一个(手动)子集在上面正常工作:

    > subset(data,subset=(state=="NY" & measure=="MSAT"))
      school state measure score
    1    NYU    NY    MSAT   590
    4    FIT    NY    MSAT   759
    5 Oswego    NY    MSAT   550
    

    但是,请注意,如果我们在全局环境中创建两个对象,state &lt;- "NY"measure &lt;- "MSAT",这将不起作用

    state <- "NY"
    measure <- "MSAT" 
    > subset(data,state==state & measure==measure)
        school state measure score
    1      NYU    NY    MSAT 590.0
    2      BYU    UT    MSAT 490.0
    3      USC    CA     GPA   2.9
    4      FIT    NY    MSAT 759.0
    5   Oswego    NY    MSAT 550.0
    6     UCLA    CA     GPA   1.2
    7      USF    CA     GPA   3.1
    8 Columbia    NY     GPA   3.2
    

    原因(我相信)与 R 的范围解析机制及其在函数中的运行方式有关。当在 R 中调用一个函数时,这个函数调用会创建一个(临时?)环境,其中该函数中的对象驻留在本地框架中,即如果您在全局环境中有一个变量 x,它们的优先级,以及定义为foo &lt;- function(x){do something interesting to x} 的函数,do something interesting 作用于通过参数x 传递给foo 的对象,而不是 全局环境中的对象x .但是,R 使用动态作用域,这意味着如果没有找到本地框架中引用的对象,解释器将递归搜索框架/环境的层次结构,直到找到所引用的对象。因此,如果您有 foo(z){do something interesting to x} 而不是 foo &lt;- function(x){do something interesting to x},但您仍然在全局环境中定义了 x,而不是导致错误,该函数将搜索调用堆栈,直到它找到对象x 来“做一些有趣的事情”。

    在上面的示例中,subset(data,state==state &amp; measure==measure) 没有产生预期结果而subset(data,state=="NY &amp; measure=="MSAT") 产生的原因是因为在subset(data, ...) 函数调用中,data 及其所有列都在本地范围内,即在全局环境中,statemeasure 列的优先级高于对象 statemeasure。因此,对于data 的每一行,子集条件state==state &amp; measure==measure 评估为TRUE,因此返回的“子集”是data 的整体。现在,如果我们这样做

    State <- "NY"
    Measure <- "MSAT"
    > subset(data, state==State & measure==Measure)
      school state measure score
    1    NYU    NY    MSAT   590
    4    FIT    NY    MSAT   759
    5 Oswego    NY    MSAT   550
    

    这很好用,因为在 subset 函数调用的本地框架中找不到 StateMeasure,解释器将继续搜索环境,直到它第一次遇到这些对象(在这种情况下,它在全局环境中找到它们)。这就是为什么当我在函数lowest 中将参数更改为StateMeasure(并在函数体中进行了相应的更改)时,它产生了所需的结果——实际上你可以将它们更改为几乎任何东西,因为只要名称不与data 的列名冲突,但将首字母大写是一种快速解决方法。

    【讨论】:

    • 谢谢@nrussell。您提到 R 使用动态范围,但我查看的几个来源,包括 cran.r-project.org/doc/contrib/Fox-Companion/appendix-scope.pdf,说 R 使用词法或静态范围。无论如何,这只是语义。您对我的范围界定问题的解释非常有帮助。
    • 没问题,很高兴为您提供帮助。你说得对,我所指的特殊情况是词法作用域的情况,但为了记录,R has two types of scoping: lexical scoping, implemented automatically at the language level, and dynamic scoping, used in select functions to save typing during interactive analysis. - 来自 Hadley 的Advanced R manual(绝对是 R 的“必读”)。
    猜你喜欢
    • 2015-12-01
    • 2015-02-17
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    相关资源
    最近更新 更多