R에서 "<<-"(범위 지정)을 어떻게 사용합니까?


140

I에 대한 단지 완성 된 독서 는 R 소개에 범위를 지정 하고,이에 대해 매우 궁금 <<-할당.

매뉴얼은에 대한 하나의 (매우 흥미로운) 예제를 보여주었습니다 <<-. 내가 여전히 누락 된 것은 이것이 유용 할 수있는 상황입니다.

그래서 내가 당신에게서 읽고 싶은 것은 언제 사용 <<-이 흥미롭고 유용 할 수 있는지에 대한 예 (또는 예에 대한 링크)입니다 . 그것을 사용하는 것의 위험은 무엇입니까 (쉽게 추적하는 것처럼 보임), 공유하고 싶은 팁이 있습니다.

답변:


196

<<-상태를 유지하기 위해 클로저와 함께 가장 유용합니다. 최근 논문에서 발췌 한 내용은 다음과 같습니다.

클로저는 다른 함수로 작성된 함수입니다. 클로저는 부모 함수의 환경을 둘러싸 기 때문에 소위 호출 되며 해당 함수의 모든 변수와 매개 변수에 액세스 할 수 있습니다. 이것은 두 가지 수준의 매개 변수를 가질 수 있기 때문에 유용합니다. 한 수준의 매개 변수 (부모)가 함수 작동 방식을 제어합니다. 다른 레벨 (자식)이 작업을 수행합니다. 다음 예제는이 아이디어를 사용하여 전력 함수 패밀리를 생성하는 방법을 보여줍니다. 부모 함수 ( power) 는 실제로 어려운 작업을 수행하는 자식 함수 ( squarecube)를 만듭니다 .

power <- function(exponent) {
  function(x) x ^ exponent
}

square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16

cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64

두 레벨에서 변수를 관리하는 기능은 또한 함수가 상위 환경에서 변수를 수정할 수 있도록하여 함수 호출 전체에서 상태를 유지할 수있게합니다. 다른 수준에서 변수를 관리하는 열쇠는 이중 화살표 할당 연산자 <<-입니다. <-항상 현재 레벨에서 작동 하는 일반적인 단일 화살표 할당 ( ) 과 달리 이중 화살표 연산자는 상위 레벨에서 변수를 수정할 수 있습니다.

이를 통해 다음 예제와 같이 함수가 호출 된 횟수를 기록하는 카운터를 유지할 수 있습니다. new_counter실행될 때마다 환경을 만들고이 환경에서 카운터 i를 초기화 한 다음 새 기능을 만듭니다.

new_counter <- function() {
  i <- 0
  function() {
    # do something useful, then ...
    i <<- i + 1
    i
  }
}

새로운 기능은 폐쇄이고 환경은 둘러싸는 환경입니다. 클로저 counter_onecounter_two실행시 각각의 엔 클로징 환경에서 카운터를 수정 한 다음 현재 카운트를 반환합니다.

counter_one <- new_counter()
counter_two <- new_counter()

counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1

4
이건 Rosettacode에서 해결되지 않은 R 작업입니다. ( rosettacode.org/wiki/Accumulator_factory#R ) 글쎄, 그것은 ...
Karsten W.

1
하나의 부모 함수에 둘 이상의 클로저를 묶어야합니까? 방금 하나의 스 니펫을 시도했는데 마지막 폐쇄 만 실행 된 것 같습니다.
mckf111

"<-"부호 대신 등호가 있습니까?
Genom

38

( 함수 의 매개 변수 를로 설정 한 경우) <<-와 동등한 것으로 생각하면 도움이됩니다 . 장점은 더 많은 매개 변수 (예 : 환경)를 지정할 수 있으므로 대부분의 경우 이상 사용하는 것을 선호합니다 . assigninheritsTRUEassignassign<<-

사용 <<-하고 assign(x, value, inherits=TRUE)"변수 'x'가 나타날 때까지 제공된 환경의 환경을 검색합니다." 다시 말해, 해당 이름의 변수를 찾을 때까지 환경을 순서대로 진행하여 할당합니다. 이것은 기능의 범위 내에 있거나 글로벌 환경에있을 수 있습니다.

이러한 기능의 기능을 이해하려면 R 환경 (예 :)을 이해해야합니다 search.

대규모 시뮬레이션을 실행할 때 이러한 기능을 정기적으로 사용하고 중간 결과를 저장하고 싶습니다. 이를 통해 주어진 함수 나 apply루프 범위 밖에서 객체를 만들 수 있습니다 . 특히 큰 루프가 예기치 않게 끝나는 것에 대해 우려하는 경우 (예 : 데이터베이스 연결 끊기),이 경우 프로세스의 모든 항목을 잃을 수 있습니다. 이는 장기 실행 프로세스 중에 결과를 R 환경 내에 대신 저장한다는 점을 제외하고 결과를 데이터베이스 또는 파일에 기록하는 것과 같습니다.

이것에 대한 나의 주요 경고 : 특히 전역 변수를 사용하고 있기 때문에 특히주의하십시오 <<-. 즉, 함수가 매개 변수로 제공된 값을 사용할 것으로 예상했을 때 함수가 환경의 오브젝트 값을 사용하는 상황으로 끝날 수 있습니다. 이것은 함수형 프로그래밍이 피하려고하는 주요한 것 중 하나입니다 ( 부작용 참조 ). 함수 내에서 사용되지 않지만 캐싱에 사용되며 나중에 복구 해야하는 경우 (또는 메타를 수행하는 경우) 고유 변수 이름 (세트 또는 고유 매개 변수와 함께 붙여 넣기 사용)에 값을 할당 하여이 문제를 피합니다. -중간 결과 분석).


3
고마워 탈. 블로그를 사용하고 있지만 실제로는 사용하지 않습니다. 나는 그것이 완벽하지 않다면 아무것도 게시하고 싶지 않기 때문에 글을 끝낼 수 없으며, 그럴 시간이 없다 ...
Shane

2
현명한 사람은 한 번 나에게 당신이 누구인지 완벽하게하는 것이 중요하지 않다고 말했습니다. 또한-독자는 때로는 의견으로 텍스트를 개선하는 데 도움이됩니다 (블로그에서 일어나는 일). 나는 언젠가 다시 생각하기를 바랍니다 :)
Tal Galili

9

내가 사용한 장소 <<-는 tcl / tk를 사용하는 간단한 GUI였습니다. statefullness를 위해 로컬 변수와 전역 변수를 구별해야하므로 초기 예제 중 일부에 있습니다. 예를 들어보십시오

 library(tcltk)
 demo(tkdensity)

사용하는 <<-. 그렇지 않으면 Marek과 동의합니다 :)-Google 검색이 도움이 될 수 있습니다.


흥미롭게도 tkdensityR 3.6.0에서 어떻게 든 찾을 수 없습니다 .
NelsonGon 2016 년

1
tcltk 패키지는 R과 함께 제공됩니다 : github.com/wch/r-source/blob/trunk/src/library/tcltk/demo/…
Dirk Eddelbuettel

5
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())}
plot(f(1000,0),typ="l")

11
이것은 사용 하지 않는 좋은 예입니다 <<-. 이 경우 for 루프가 더 명확합니다.
hadley

4

이 주제에서 나는 <<-연산자가 for 루프 내에서 (부적절하게) 적용될 때 이상하게 행동 한다는 것을 지적하고 싶습니다 (다른 경우도있을 수 있음). 다음 코드가 주어진다 :

fortest <- function() {
    mySum <- 0
    for (i in c(1, 2, 3)) {
        mySum <<- mySum + i
    }
    mySum
}

함수가 예상 합계 6을 반환 할 것으로 예상 할 수 있지만 대신 전역 변수 mySum가 만들어지고 값 3이 할당 된 상태에서 0을 반환 합니다. 루프는 새로운 범위 '레벨' 이 아닙니다 . 대신, R은 fortest함수 외부를보고 mySum할당 할 변수를 찾을 수 없으므로 루프를 통해 처음으로 변수를 만들고 값 1을 할당합니다. 후속 반복에서 할당의 RHS는 (변경되지 않은) 내부 mySum변수를 참조해야 하지만 LHS는 전역 변수를 나타냅니다. 따라서 각 반복은 전역 변수의 값을 해당 반복의 값 ()으로 겹쳐 쓰므로 i함수 종료시 값 3을 갖습니다.

이것이 누군가에게 도움이되기를 바랍니다. (BTW, 바로 교체 <<-와 함께 <-예상대로 및 기능 작동).


2
귀하의 예에서 local mySum은 증가하지 않고 global 만 증가합니다 mySum. 따라서 for 루프가 반복 될 때마다 전역 mySum은 값을 얻습니다 0 + i. 당신은 이것을 따라갈 수 있습니다 debug(fortest).
ClementWalter

for-loop 인 것과는 아무런 관련이 없습니다. 두 가지 다른 범위를 참조하고 있습니다. <-함수 내부의 로컬 변수 만 업데이트하려는 경우 함수 내 어디서나 일관되게 사용 하십시오.
smci

또는 <<-어디서나 @smci를 사용하십시오. 글로벌을 피하는 것이 가장 좋습니다.
학습 통계 통계 예 :

3

<<-연산자 또한 유용 할 수 참조 방법을 쓸 때 참조 클래스 . 예를 들면 다음과 같습니다.

myRFclass <- setRefClass(Class = "RF",
                         fields = list(A = "numeric",
                                       B = "numeric",
                                       C = function() A + B))
myRFclass$methods(show = function() cat("A =", A, "B =", B, "C =",C))
myRFclass$methods(changeA = function() A <<- A*B) # note the <<-
obj1 <- myRFclass(A = 2, B = 3)
obj1
# A = 2 B = 3 C = 5
obj1$changeA()
obj1
# A = 6 B = 3 C = 9
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.