2011-01-13 25 views
9

Bulmaca bir ifade olarak değerlendirilir bir R fonksiyonu yazmak için: BenceR cognoscenti için bir veri-çerçeve içinde

with(df, a) 
gibi şeyler yapabileceğini biliyorum

df <- data.frame(a = 1:5, b = 1:5) 

: Biz bir veri dilimi var ki Sonuçların bir vektörünü almak için

.

Ancak, bir ifadeyi (a veya a > 3 gibi) alan ve içinde aynı şeyi yapan bir işlevi nasıl yazarım. Yani Veri çerçevesini ve ifadeyi argüman olarak alan ve veri çerçevesi içindeki ifadeyi "çevre" olarak değerlendirmenin sonucunu döndüren bir işlev fn yazmak istiyorum.

Bu durumun sesler çıkardığını unutmayın (sadece with'u yukarıdaki gibi kullanabilirim), ancak bu, yazdığım daha karmaşık bir işlevin basitleştirilmiş bir sürümüdür. Çeşitli varyantları denedim (eval, with, envir, substitute, local, vs) ancak bunların hiçbiri çalışmaz. Mesela ben şöyle fn tanımlarsanız: ortamları ve değerlendirme konusunda ince

> fn(df, a) 
Error in eval(expr, envir = dat) : object 'a' not found 

Açıkçası ben eksik bir şey:

fn <- function(dat, expr) { 
    eval(expr, envir = dat) 
} 

bu hatayı alıyorum. Böyle bir işlevi tanımlamanın bir yolu var mı?

+1

'u kullanarak [Hadley's bu konuyla ilgili wiki] bölümünde bir bölüm var (https: // github.com/hadley/devtools/wiki/Değerlendirme) – Marek

+0

@Marek okumak için harika bir referans, teşekkürler! –

+0

Bu sayfa hala erişilebilir mi? –

cevap

10

kafes paketi farklı bir şekilde bu tür bir şey yok. Bakınız örn., lattice:::xyplot.formula.

fn <- function(dat, expr) { 
    eval(substitute(expr), dat) 
} 
fn(df, a)    # 1 2 3 4 5 
fn(df, 2 * a + b)  # 3 6 9 12 15 
+0

+1 bu en basit yoldur, teşekkürler –

+0

+1, çok hoş (yedek hakkında düşünmedim). Match.call'in avantajı, tüm argümanlarınızı uygun bir listede bulundurmanızdır, bu yüzden bunu daha sık kullanıyorum. Ama gerisine ihtiyacınız yoksa, ikame gerçekten çok güzel ve kolay bir yoldur. –

+0

Bir listede() veya c() birden çok ifadeyi geçirmenin ve her birinde bir listede saklanan farklı veri çerçeveleri için for döngüsünde değerlendirmenin bir yolu var mı? Aynı işlevselliği istiyorum. Listede saklanan dataframe ve ifadeler için çalışamıyorum. – Blind0ne

9

Bunun nedeni, bir ifadeyi geçmiyor olmanızdır.

Dene:

fn <- function(dat, expr) { 
    mf <- match.call() # makes expr an expression that can be evaluated 
eval(mf$expr, envir = dat) 
} 

> df <- data.frame(a = 1:5, b = 1:5) 
> fn(df, a) 
[1] 1 2 3 4 5 
> fn(df, a+b) 
[1] 2 4 6 8 10 

bu kullanarak fonksiyonların kaynak kodu hızlı bir bakış (örn lm) bu konuda çok daha ilginç şeyler ortaya çıkarabilir.

+0

teşekkürler, eksik olduğum şey bu! Ve evet, nasıl yaptıklarını görmek için 'altkümesi' ve bazı diğerleri gibi işlevlere bakmayı denedim, ama onlar içseldiler. Gelecek referans için lm' hakkında iyi düşünmedim. –

+1

Bu durumda yerine kullanmanın daha kanonik olduğunu düşünüyorum. Ve emin değilim, lm iyi bir rol modelidir - en azından standart standart dışı değerlendirme kurallarını okuduğunuzdan emin olun. – hadley

+0

@hadley: true. Sadece 'data' argümanı nedeniyle 'match.call()' ve 'lm() 'yi düşündüm. –

-1

? Da ayrıca ilginizi çekebilir.

df <- data.frame(a = 1:5, b = 1:5) 
within(df, cx <- a > 3) 
    a b cx 
1 1 1 FALSE 
2 2 2 FALSE 
3 3 3 FALSE 
4 4 4 TRUE 
5 5 5 TRUE 
+0

@mdsummer: Korkarım ki soru tamamen kavramadınız ... –

2

Geç giriş, ama data.table yaklaşım ve sözdizimi sonra ne olabileceği düşünülür. Tam olarak bu, [.data.table, j, i ve by bağımsız değişkenleriyle çalışır.

forma fn(x,expr) bunu gerekiyorsa, o zaman kullanabilirsiniz Ben daha yerli formu içinde kullanımı daha kolay olduğunu düşünüyorum aşağıdaki

library(data.table) 

DT <- data.table(a = 1:5, b = 2:6) 

`[`(x=DT, j=a) 

## [1] 1 2 3 4 5 

`[`(x=DT, j=a * b) 
## [1] 2 6 12 20 30 

DT[,a] 
## [1] 1 2 3 4 5 

vb. Arka planda bu, substitute ve eval

İlgili konular