program tip

`levels <-` (이것은 어떤 마법입니까?

radiobox 2020. 8. 4. 07:36
반응형

`levels <-` (이것은 어떤 마법입니까?


다른 질문에 대한 답변으로 @Marek은 다음 솔루션을 게시했습니다. https://stackoverflow.com/a/10432263/636656

dat <- structure(list(product = c(11L, 11L, 9L, 9L, 6L, 1L, 11L, 5L, 
                                  7L, 11L, 5L, 11L, 4L, 3L, 10L, 7L, 10L, 5L, 9L, 8L)), .Names = "product", row.names = c(NA, -20L), class = "data.frame")

`levels<-`(
  factor(dat$product),
  list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
  )

출력으로 생성되는 것 :

 [1] Generic Generic Bayer   Bayer   Advil   Tylenol Generic Advil   Bayer   Generic Advil   Generic Advil   Tylenol
[15] Generic Bayer   Generic Advil   Bayer   Bayer  

이것은 벡터의 출력물이므로 저장하면 훨씬 더 혼란 스러울 수 있습니다.

res <- `levels<-`(
  factor(dat$product),
  list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
  )

분명히 이것은 레벨 함수에 대한 일종의 호출이지만, 여기서 무엇을하고 있는지 전혀 모른다. 이런 종류의 마법에 대한 용어는 무엇이며,이 영역에서 마법 능력을 어떻게 향상시킬 수 있습니까?


여기에 대한 답변은 좋지만 중요한 요점이 없습니다. 시도하고 설명하겠습니다.

R은 기능적 언어이며 객체를 변경하는 것을 좋아하지 않습니다. 그러나 대체 함수를 사용하여 할당 문을 허용합니다.

levels(x) <- y

에 해당

x <- `levels<-`(x, y)

트릭은,이 재 작성이 수행되고있다 <-; 에 의해 수행되지 않습니다 levels<-. levels<-입력을 받아 출력하는 정규 함수일뿐입니다. 아무것도 변경하지 않습니다.

그 결과 한 가지 결과는 위의 규칙에 따라 <-재귀 적이어야한다는 것입니다.

levels(factor(x)) <- y

이다

factor(x) <- `levels<-`(factor(x), y)

이다

x <- `factor<-`(x, `levels<-`(factor(x), y))

이 순수한 기능적 변형 (배정이 끝날 때까지)이 과제가 명령형 언어로 된 것과 동등하다는 것은 매우 아름답습니다. 올바르게 기억한다면 기능 언어로 된이 구성을 렌즈라고합니다.

그러나 다음과 같은 대체 함수를 정의 levels<-하면 예상치 못한 또 다른 횡재가 발생합니다. 할당을 수행 할 수있는 기능이 아니라 인자를 취하고 다른 레벨의 다른 인자를 제공하는 편리한 함수가 있습니다. 그것에 대한 "할당"은 실제로 없습니다!

따라서 설명하는 코드는이 다른 해석을 사용 levels<-합니다. 나는 levels<-그것이 과제를 제안하기 때문에 그 이름 이 약간 혼란 스럽다는 것을 인정 하지만, 이것은 일어나고 있지 않습니다. 코드는 단순히 일종의 파이프 라인을 설정합니다.

  • 로 시작 dat$product

  • 요인으로 변환

  • 레벨 변경

  • 저장 res

개인적으로, 나는 코드 라인이 아름답다고 생각합니다.)


No sorcery, that's just how (sub)assignment functions are defined. levels<- is a little different because it is a primitive to (sub)assign the attributes of a factor, not the elements themselves. There are plenty of examples of this type of function:

`<-`              # assignment
`[<-`             # sub-assignment
`[<-.data.frame`  # sub-assignment data.frame method
`dimnames<-`      # change dimname attribute
`attributes<-`    # change any attributes

Other binary operators can be called like that too:

`+`(1,2)  # 3
`-`(1,2)  # -1
`*`(1,2)  # 2
`/`(1,2)  # 0.5

Now that you know that, something like this should really blow your mind:

Data <- data.frame(x=1:10, y=10:1)
names(Data)[1] <- "HI"              # How does that work?!? Magic! ;-)

The reason for that "magic" is that the "assignment" form must have a real variable to work on. And the factor(dat$product) wasn't assigned to anything.

# This works since its done in several steps
x <- factor(dat$product)
levels(x) <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
x

# This doesn't work although it's the "same" thing:
levels(factor(dat$product)) <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
# Error: could not find function "factor<-"

# and this is the magic work-around that does work
`levels<-`(
  factor(dat$product),
  list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
  )

For user-code I do wonder why such language manipulations are used so? You ask what magic is this and others have pointed out that you are calling the replacement function that has the name levels<-. For most people this is magic and really the intended use is levels(foo) <- bar.

The use-case you show is different because product doesn't exist in the global environment so it only ever exists in the local environment of the call to levels<- thus the change you want to make does not persist - there was no reassignment of dat.

In these circumstances, within() is the ideal function to use. You would naturally wish to write

levels(product) <- bar

in R but of course product doesn't exist as an object. within() gets around this because it sets up the environment you wish to run your R code against and evaluates your expression within that environment. Assigning the return object from the call to within() thus succeeds in the properly modified data frame.

Here is an example (you don't need to create new datX - I just do that so the intermediary steps remain at the end)

## one or t'other
#dat2 <- transform(dat, product = factor(product))
dat2 <- within(dat, product <- factor(product))

## then
dat3 <- within(dat2, 
               levels(product) <- list(Tylenol=1:3, Advil=4:6, 
                                       Bayer=7:9, Generic=10:12))

Which gives:

> head(dat3)
  product
1 Generic
2 Generic
3   Bayer
4   Bayer
5   Advil
6 Tylenol
> str(dat3)
'data.frame':   20 obs. of  1 variable:
 $ product: Factor w/ 4 levels "Tylenol","Advil",..: 4 4 3 3 2 1 4 2 3 4 ...

I struggle to see how constructs like the one you show are useful in the majority of cases - if you want to change the data, change the data, don't create another copy and change that (which is all the levels<- call is doing after all).

참고URL : https://stackoverflow.com/questions/10449366/levels-what-sorcery-is-this

반응형