r تقسيم الحجج `` `وتوزيعها على وظائف متعددة




(3)

باستخدام الدالة التالية foo() كمثال بسيط ، أود توزيع القيم المعطاة في ... وظيفتين مختلفتين ، إن أمكن.

foo <- function(x, y, ...) {
    list(sum = sum(x, ...), grep = grep("abc", y, ...))
}

في المثال التالي ، أود أن يتم تمرير na.rm إلى sum() ، value المراد تمريرها إلى grep() . لكنني أتلقى خطأ في حجة غير مستخدمة في grep() .

X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, na.rm = TRUE, value = TRUE)
# Error in grep("abc", y, ...) : unused argument (na.rm = TRUE)

يبدو أن تم إرسال الحجج إلى grep() أولاً. هل هذا صحيح؟ أعتقد أن R sum() ويقيّم sum() أولاً ، ويعيد خطأً في هذه الحالة.

علاوة على ذلك ، عندما حاولت تقسيم الحجج في ... ، واجهت المتاعب. الوسيطة الرسمية sum() هي NULL لأنها هي .Primitive ، وبالتالي لا يمكنني استخدامها

names(formals(sum)) %in% names(list(...))

أنا أيضا لا أريد أن نفترض أن الحجج المتبقية من

names(formals(grep)) %in% names(list(...))

يتم تمريرها تلقائيًا إلى sum() .

كيف يمكنني توزيع ... الحجج إلى وظائف متعددة بحيث لا يتم إجراء التقييمات غير الضرورية؟

على المدى الطويل ، أود أن أكون قادرًا على تطبيق هذا على الوظائف مع قائمة طويلة من ... الحجج ، شبيهة بتلك الخاصة بـ download.file() scan() .


Answer #1
  1. لماذا خطأ grep قبل sum ؟

    انظر هذا sum هو أكثر ملاءمة مع حججها:

    X <- c(1:5, NA, 6:10)
    sum(X, na.rm = TRUE, value = TRUE)
    ## [1] 56
    

    لا يفشل ذلك لأنه لا يهتم بالوسائط المسماة الأخرى ، لذلك فإن value = TRUE تبسط إلى TRUE فقط والتي يتم تجميعها إلى 1. بالمناسبة:

    sum(X, na.rm = TRUE)
    ## [1] 55
    
  2. كيفية تقسيم ... إلى وظائف مختلفة؟

    إحدى الطرق (التي هي عرضة للخطأ) هي البحث عن الوسيطة لوظائف الهدف. على سبيل المثال:

    foo <- function(x, y, ...){
        argnames <- names(list(...))
        sumargs <- intersect(argnames, names(as.list(args(sum))))
        grepargs <- intersect(argnames, names(as.list(args(grep))))
        list(sum = do.call(sum, c(list(x), list(...)[sumargs])),
             grep = do.call(grep, c(list("abc", y), list(...)[grepargs])))
    }
    

    هذا عرضة للخطأ في أي وقت لا يتم الإبلاغ عن الوسيطات التي تستخدمها الدالة بشكل صحيح بواسطة args ، مثل كائنات S3. كمثال:

    names(as.list(args(plot)))
    ## [1] "x"   "y"   "..." ""   
    names(as.list(args(plot.default)))
    ##  [1] "x"           "y"           "type"        "xlim"        "ylim"       
    ##  [6] "log"         "main"        "sub"         "xlab"        "ylab"       
    ## [11] "ann"         "axes"        "frame.plot"  "panel.first" "panel.last" 
    ## [16] "asp"         "..."         ""           
    

    في هذه الحالة ، يمكنك استبدال الدالة S3 المناسبة. وبسبب هذا ، ليس لدي حل عام لهذا (على الرغم من أنني لا أعلم أنه موجود أو غير موجود).


Answer #2

قوائم منفصلة إذا كنت تريد حقاً اجتياز مجموعات مختلفة من المعلمات لوظائف مختلفة ، فمن المحتمل أن تكون أنظف لتحديد قوائم منفصلة:

foo <- function(x, y, sum = list(), grep = list()) {
 list(sum = do.call("sum", c(x, sum)), grep = do.call("grep", c("abc", y, grep)))
}

# test

X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, sum = list(na.rm = TRUE), grep = list(value = TRUE))

## $sum
## [1] 55
## 
## $grep
## [1] "xyzabcxyz"

القائمة المختلطة / ... البديل هو أننا يمكن أن نستخدم ... لواحدة من هذه ثم نختار الآخر كقائمة ، خاصة في حالة استخدام أحدها بشكل متكرر والآخر نادر الاستخدام. سيتم تمرير واحدة تستخدم بشكل متكرر عن طريق ... واستخدامها بشكل غير متكرر عبر قائمة. على سبيل المثال

foo <- function(x, y, sum = list(), ...) {
 list(sum = do.call("sum", c(x, sum)), grep = grep("abc", y, ...))
}

foo(X, Y, sum = list(na.rm = TRUE), value = TRUE)

في ما يلي مثالان للطريقة المختلطة من R نفسها:

ط) تأخذ وظيفة mapply هذا النهج باستخدام كل من ... وقائمة MoreArgs :

> args(mapply)
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) 
NULL

ii) تأخذ nls أيضًا هذا الأسلوب باستخدام كلٍّ من ... وقائمة control :

> args(nls)
function (formula, data = parent.frame(), start, control = nls.control(), 
    algorithm = c("default", "plinear", "port"), trace = FALSE, 
    subset, weights, na.action, model = FALSE, lower = -Inf, 
    upper = Inf, ...) 
NULL

Answer #3

يمكنك فقط تمرير الوسيطة ... إلى وظيفة أخرى ، إذا كانت تلك الدالة الأخرى تتضمن جميع الوسيطات التي تم تمريرها إلى ... أو إذا كان لها ... وسيطة بحد ذاتها. إذن ، بالنسبة sum ، هذه ليست مشكلة ( args(sum) function (..., na.rm = FALSE) ). على الجانب الآخر grep ليس na.rm ولا ... كحجة.

args(grep)
# function (pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, 
#     fixed = FALSE, useBytes = FALSE, invert = FALSE) 

هذا لا يشمل ... ولا يشمل أيضا على الوسيطة المسماة na.rm إما. الحل البسيط هو مجرد تحديد mygrep الخاصة بك على النحو التالي:

mygrep <- function (pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, 
                    fixed = FALSE, useBytes = FALSE, invert = FALSE, ...)
  grep(pattern, x, ignore.case, perl, value, fixed, useBytes, invert)

ثم يبدو أن العمل:

foo <- function(x, y, ...){
  list(sum = sum(x, ...), grep = mygrep("abc", y, ...))
}
X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, na.rm = TRUE, value = TRUE)

# $sum
# [1] 56
# 
# $grep
# [1] "xyzabcxyz"



r  

r