2012-10-11 38 views
8

可能重複:
How to write an R function that evaluates an expression within a data-frame爲什麼懶惰的評估工作在這個R函數中?

我想寫一個排序一個data.frame功能 - 而不是使用繁瑣的順序()。鑑於類似

> x=data.frame(a=c(5,6,7),b=c(3,5,1)) 
> x 
    a b 
1 5 3 
2 6 5 
3 7 1 

我想說的是這樣的:

sort.df(x,b) 

因此,這裏是我的功能:

sort.df <- function(df, ...) { 
    with(df, df[order(...),]) 
} 

我真的爲此感到自豪。鑑於R的懶惰評估,我認爲只有在需要的時候纔會評估......參數,到那個時候它將在範圍內,這是由於「與」。

如果我直接運行'with'行,它可以工作。但該功能沒有。

> with(x,x[order(b),]) 
    a b 
3 7 1 
1 5 3 
2 6 5 
> sort.df(x,b) 
Error in order(...) : object 'b' not found 

怎麼了,怎麼解決?例如,我經常在像plyr這樣的軟件包中看到這種「魔力」。有什麼訣竅?

+0

sort.df(X,X $ B)的作品,但我仍然不知道爲什麼排序。 df(x,b)不起作用 – Ali

+0

另請參見'plyr :: arrange'。 – hadley

+1

謝謝!儘管每天都使用plyr,但我不知道有關安排。另一個很難在R世界找到正確解決方案的例子 - 以及很多優秀的R編程,都是使用一些好的包來學習最佳實踐。 –

回答

7

這是因爲,當你路過B您實際上是不及格的對象。把browser放在你的函數中,你會明白我的意思。我從一些互聯網機器人偷了這個:

x=data.frame(a=c(5,6,7),b=c(3,5,1)) 

sort.df <- function(df, ..., drop = TRUE){ 
    ord <- eval(substitute(order(...)), envir = df, enclos = parent.frame()) 
    return(df[ord, , drop = drop]) 
} 

sort.df(x, b) 

將工作。

所以纔會如果你正在尋找一個不錯的方式施加感要做到這一點:

library(taRifx) 
sort(x, f=~b) 
+2

+ 1爲好的解決方案,特別是提示在函數內部使用'browser()'調用。恕我直言,這是遙不可及的最好的方式來了解'...'和圍繞它的所有奇怪。 –

+0

有人可以糾正我,但'enclos = parent.frame()'在'eval'中是默認的,所以簡單的'eval(substitute(...)),envir = df)'也行得通:) – user1665355

9

這會做你想要什麼:

sort.df <- function(df, ...) { 
    dots <- as.list(substitute(list(...)))[-1] 
    ord <- with(df, do.call(order, dots)) 
    df[ord,] 
} 

## Try it out 
x <- data.frame(a=1:10, b=rep(1:2, length=10), c=rep(1:3, length=10)) 
sort.df(x, b, c) 

,因此將這樣的:

sort.df2 <- function(df, ...) { 
    cl <- substitute(list(...)) 
    cl[[1]] <- as.symbol("order") 
    df[eval(cl, envir=df),] 
} 
sort.df2(x, b, c) 
+1

或'sort.df < - 函數(df,...)df [order(eval(substitute(...),df)),]' –

+0

@JoshuaUlrich - 不完全相同。你的結果只會由'...'的第一個元素排序,因爲'substitute(...)'只能捕獲這個元素。 (在'sort.df()'中放入一個'browser()'調用,然後比較'substitute(...)'和'substitute(list(...))'來查看我的意思。) –