[r] 자신의 함수를 작성할 때 R의 줄임표 기능을 사용하는 방법은 무엇입니까?

R 언어에는 다양한 개수의 인수를 사용할 수있는 함수를 정의하는 멋진 기능이 있습니다. 예를 들어, 함수 data.frame는 여러 인수를 사용하며 각 인수는 결과 데이터 테이블의 열에 대한 데이터가됩니다. 사용법 예 :

> data.frame(letters=c("a", "b", "c"), numbers=c(1,2,3), notes=c("do", "re", "mi"))
  letters numbers notes
1       a       1    do
2       b       2    re
3       c       3    mi

함수의 서명에는 다음과 같은 줄임표가 포함됩니다.

function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, 
    stringsAsFactors = default.stringsAsFactors()) 
{
    [FUNCTION DEFINITION HERE]
}

비슷한 작업을 수행하는 함수를 작성하고 싶습니다. 여러 값을 가져 와서 단일 반환 값으로 통합하고 다른 처리를 수행합니다. 이를 위해 ...함수 내에서 함수의 인수에서 “압축을 해제하는”방법을 찾아야 합니다. 나는 이것을하는 방법을 모른다. 의 함수 정의의 관련 라인 data.frame입니다 object <- as.list(substitute(list(...)))[-1L]내가 어떤 이해가되지 수있는.

어떻게 생략 부호를 함수의 서명에서 예를 들어 목록으로 변환 할 수 있습니까?

좀 더 구체적으로, get_list_from_ellipsis아래 코드를 어떻게 작성할 수 있습니까?

my_ellipsis_function(...) {
    input_list <- get_list_from_ellipsis(...)
    output_list <- lapply(X=input_list, FUN=do_something_interesting)
    return(output_list)
}

my_ellipsis_function(a=1:10,b=11:20,c=21:30)

편집하다

이를 수행하는 두 가지 가능한 방법이있는 것 같습니다. 그들은이다 as.list(substitute(list(...)))[-1L]list(...). 그러나이 두 가지가 정확히 같은 것은 아닙니다. (차이점에 대해서는 답변의 예를 참조하십시오.) 누구든지 그들 사이의 실제적인 차이점과 사용해야 할 것이 무엇인지 말해 줄 수 있습니까?



답변

답변과 의견을 읽었으며 언급되지 않은 내용은 거의 없습니다.

  1. data.framelist(...)버전을 사용합니다 . 코드 조각 :

    object <- as.list(substitute(list(...)))[-1L]
    mrn <- is.null(row.names)
    x <- list(...)
    

    object열 이름으로 마술 x을 만드는 데 사용 되지만 final을 만드는 데 사용됩니다 data.frame.
    평가되지 않은 ...인수 를 사용하려면 사용 되는 write.csv코드를 확인하십시오 match.call.

  2. 의견에 쓰면 Dirk answer는 목록의 목록이 아닙니다. 길이가 4 인 요소의 목록입니다 language. 첫 번째 객체는 symbollist이고 두 번째 객체는 표현식 1:10입니다. [-1L]필요한 이유를 설명 합니다 : symbol제공된 인수에서 예상 인수를 제거합니다 ...(항상 목록이므로).
    Dirk 상태 substitute에서 “평가되지 않은 구문 분석 트리”를 반환합니다.
    당신이 호출 할 때 my_ellipsis_function(a=1:10,b=11:20,c=21:30)다음 ...인수 목록을 “만들어” list(a=1:10,b=11:20,c=21:30)하고 substitute그것을 네 가지 요소의 목록을 만들 :

    List of 4
    $  : symbol list
    $ a: language 1:10
    $ b: language 11:20
    $ c: language 21:30
    

    첫 번째 요소는 이름이 없으며 이것은 [[1]]Dirk answer에 있습니다. 다음을 사용 하여이 결과를 얻습니다.

    my_ellipsis_function <- function(...) {
      input_list <- as.list(substitute(list(...)))
      str(input_list)
      NULL
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
    
  3. 위와 같이 str함수에 어떤 객체가 있는지 확인할 수 있습니다 .

    my_ellipsis_function <- function(...) {
        input_list <- list(...)
        output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
        return(output_list)
    }
    my_ellipsis_function(a=1:10,b=11:20,c=21:30)
     int [1:10] 1 2 3 4 5 6 7 8 9 10
     int [1:10] 11 12 13 14 15 16 17 18 19 20
     int [1:10] 21 22 23 24 25 26 27 28 29 30
    $a
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       1.00    3.25    5.50    5.50    7.75   10.00 
    $b
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       11.0    13.2    15.5    15.5    17.8    20.0 
    $c
       Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
       21.0    23.2    25.5    25.5    27.8    30.0 
    

    괜찮아. substitute버전을 볼 수 있습니다 :

       my_ellipsis_function <- function(...) {
           input_list <- as.list(substitute(list(...)))
           output_list <- lapply(X=input_list, function(x) {str(x);summary(x)})
           return(output_list)
       }
       my_ellipsis_function(a=1:10,b=11:20,c=21:30)
        symbol list
        language 1:10
        language 11:20
        language 21:30
       [[1]]
       Length  Class   Mode 
            1   name   name 
       $a
       Length  Class   Mode 
            3   call   call 
       $b
       Length  Class   Mode 
            3   call   call 
       $c
       Length  Class   Mode 
            3   call   call 
    

    우리가 필요한 것이 아닙니다. 이러한 종류의 객체를 처리하려면 추가 트릭이 필요합니다 (에서와 같이 write.csv).

사용하려면 ...Shane answer에서와 같이 사용하십시오 list(...).


답변

줄임표를 사용하여 목록으로 변환 list()한 다음 작업을 수행 할 수 있습니다.

> test.func <- function(...) { lapply(list(...), class) }
> test.func(a="b", b=1)
$a
[1] "character"

$b
[1] "numeric"

따라서 귀하의 get_list_from_ellipsis기능은 그 이상 list입니다.

유효한 유스 케이스는 조작의 알 수없는 수의 오브젝트를 전달하려는 경우입니다 ( c()또는 의 예에서 와 같이 data.frame()). ...그러나 각 매개 변수를 미리 알고있을 때 인수 문자열에 약간의 모호함과 복잡성을 추가하고 함수 서명을 다른 사용자에게 불분명하게하기 때문에 를 사용하는 것은 좋지 않습니다 . 인수 목록은 함수 사용자를위한 중요한 문서입니다.

그렇지 않으면 매개 변수를 자신의 함수 인수에 모두 노출시키지 않고 하위 함수로 전달하려는 경우에도 유용합니다. 이것은 기능 문서에서 확인할 수 있습니다.


답변

Shane and Dirk의 답변에 추가하기 만하면됩니다.

get_list_from_ellipsis1 <- function(...)
{
  list(...)
}
get_list_from_ellipsis1(a = 1:10, b = 2:20) # returns a list of integer vectors

$a
 [1]  1  2  3  4  5  6  7  8  9 10

$b
 [1]  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

get_list_from_ellipsis2 <- function(...)
{
  as.list(substitute(list(...)))[-1L]
}
get_list_from_ellipsis2(a = 1:10, b = 2:20) # returns a list of calls

$a
1:10

$b
2:20

그것이 의미 하듯이, 두 버전 중 하나는의 목적에 적합한 것으로 my_ellipsis_function보이지만 첫 번째 버전은 더 간단합니다.


답변

이미 절반의 답을 주었다. 치다

R> my_ellipsis_function <- function(...) {
+   input_list <- as.list(substitute(list(...)))
+ }
R> print(my_ellipsis_function(a=1:10, b=2:20))
[[1]]
list

$a
1:10

$b
11:20

R> 

그래서이 두 개의 인수했다 ab전화에서와 목록에 변환됩니다. 그게 당신이 요청한 것이 아닙니까?


답변

이것은 예상대로 작동합니다. 다음은 대화식 세션입니다.

> talk <- function(func, msg, ...){
+     func(msg, ...);
+ }
> talk(cat, c("this", "is", "a","message."), sep=":")
this:is:a:message.
> 

기본 인수를 제외하고 동일합니다.

> talk <- function(func, msg=c("Hello","World!"), ...){
+     func(msg, ...);
+ }
> talk(cat,sep=":")
Hello:World!
> talk(cat,sep=",", fill=1)
Hello,
World!
>

보시다시피, 기본값이 특정 경우에 원하는 것이 아닌 경우 함수를 사용하여 ‘추가’인수를 함수에 전달할 수 있습니다.


답변