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


186

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(...). 그러나이 두 가지가 정확히 같은 것은 아닙니다. (차이점에 대해서는 답변의 예를 참조하십시오.) 누구든지 그들 사이의 실제적인 차이점과 사용해야 할 것이 무엇인지 말해 줄 수 있습니까?

답변:


113

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

  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. 첫 번째 객체는 symbol- list이고 두 번째 객체는 표현식 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(...).


38

줄임표를 사용하여 목록으로 변환 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()). ...그러나 각 매개 변수를 미리 알고있을 때 인수 문자열에 약간의 모호함과 복잡성을 추가하고 함수 서명을 다른 사용자에게 불분명하게하기 때문에 를 사용하는 것은 좋지 않습니다 . 인수 목록은 함수 사용자를위한 중요한 문서입니다.

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


하위 함수에 대한 인수를 전달하는 데 줄임표를 사용하는 방법에 대해 알고 있지만 R 프리미티브 사이에서 내가 설명한 방식으로 줄임표를 사용하는 것이 일반적입니다. 실제로 listand와 cfunction은 모두 이런 식으로 작동하지만 둘 다 프리미티브이므로 소스 코드를 쉽게 검사하여 작동 방식을 이해할 수 없습니다.
Ryan C. Thompson

rbind.data.frame이 방법을 사용하십시오.
Marek

5
경우 list(...)에 충분하다, 왜 R의 내장 명령은 같은 할 data.frame사용 긴 양식을 as.list(substitute(list(...)))[-1L]대신?
Ryan C. Thompson

1
내가 만들지 않았 data.frame으므로 그것에 대한 대답을 모릅니다 (즉, 그럴만 한 이유 있다고 확신 합니다). 나는 list()이 목적으로 내 패키지로 사용하지만 아직 문제가 발생하지 않았습니다.
셰인

34

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보이지만 첫 번째 버전은 더 간단합니다.


15

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

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전화에서와 목록에 변환됩니다. 그게 당신이 요청한 것이 아닙니까?


2
내가 원하는 것은 아닙니다. 실제로 목록 목록을 반환하는 것으로 보입니다. 를 확인하십시오 [[1]]. 또한 마법의 주문이 어떻게 as.list(substitute(list(...)))작동 하는지 알고 싶습니다 .
Ryan C. Thompson

2
내부 는 인수를 기반으로 객체를 list(...)만듭니다 list. 그런 다음 substitute()평가되지 않은 식에 대한 구문 분석 트리를 만듭니다. 이 기능에 대한 도움말을 참조하십시오. R (또는 S)에 대한 고급 텍스트뿐만 아니라. 이것은 사소한 것이 아닙니다.
Dirk Eddelbuettel

좋아, [[-1L]](내 질문에서) 부분은 어떻습니까? 그렇지 [[1]]않습니까?
Ryan C. Thompson

3
인덱싱에 대해 읽어야합니다. 빼기는 '제외'를 의미 print(c(1:3)[-1])합니다. 즉, 2와 3 만 인쇄합니다. 이것은 L정수로 끝나는 것을 보장하는 새로운 방법입니다. 이것은 R 소스에서 많이 수행됩니다.
Dirk Eddelbuettel

7
나는 색인에 읽을 필요는 없지만, 나는 않습니다 당신이 표시하는 명령의 출력에 가까운 관심을 지불 할 필요가있다. [[1]]$a지수 의 차이로 인해 중첩 된 목록이 포함되었다고 생각했습니다. 그러나 이제는 실제로 얻는 것이 내가 원하는 목록이지만 추가 요소가 앞에 있다는 것을 알았습니다. 그렇다면 [-1L]의미가 있습니다. 어쨌든 그 여분의 첫 번째 요소는 어디에서 왔습니까? 그리고 단순히 이것을 대신 사용해야하는 이유가 list(...)있습니까?
Ryan C. Thompson

6

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

> 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!
>

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.