117

別の質問への回答で、@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)
  )

明らかに、これはレベル関数へのある種の呼び出しですが、ここで何が行われているのかわかりません。この種の魔法の用語は何ですか? また、この領域で魔法の能力を高めるにはどうすればよいですか?

4

4 に答える 4

108

ここでの答えは良いですが、重要な点が欠けています。説明してみましょう。

Rは関数型言語であり、そのオブジェクトを変更するのは好きではありません。ただし、置換関数を使用して、代入ステートメントを使用できます。

levels(x) <- y

と同等です

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

秘訣は、この書き換えは<-;によって行われるということです。によっては行われませんlevels<-levels<-入力を受け取り、出力を提供する単なる通常の関数です。何も変化しません。

その結果の1つは、上記の規則によれば、<-再帰的でなければならないということです。

levels(factor(x)) <- y

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

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

この純粋な機能変換(割り当てが行われる最後まで)が、命令型言語での割り当てと同等であることは、一種の美しいことです。私が正しく覚えていれば、関数型言語でのこの構成はレンズと呼ばれます。

ただし、のような置換関数を定義するとlevels<-、予期しない別の急降下が発生します。割り当てを行うだけでなく、ある要素を取り込んで、さまざまなレベルの別の要素を出力する便利な関数があります。それについては本当に「割り当て」はありません!

したがって、あなたが説明しているコードは、この他の解釈を利用しているだけですlevels<-。名前levels<-は割り当てを示唆しているので少し紛らわしいことは認めますが、これは起こっていることではありません。コードは、ある種のパイプラインを設定するだけです。

  • 皮切りにdat$product

  • 係数に変換する

  • レベルを変更する

  • に保存するres

個人的には、コード行は美しいと思います;)

于 2012-05-08T02:40:42.237 に答える
34

魔法はありません。それは、(サブ)代入関数が定義されている方法です。 levels<-要素自体ではなく、要素の属性を (サブ) 割り当てるためのプリミティブであるため、少し異なります。このタイプの関数の例はたくさんあります:

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

他の二項演算子も同様に呼び出すことができます:

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

あなたがそれを知ったので、このようなことは本当にあなたの心を驚かせるはずです:

Data <- data.frame(x=1:10, y=10:1)
names(Data)[1] <- "HI"              # How does that work?!? Magic! ;-)
于 2012-05-04T13:10:38.250 に答える
31

その「魔法」の理由は、「割り当て」フォームには、作業する実際の変数が必要だからです。そして、factor(dat$product)は何にも割り当てられていませんでした。

# 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)
  )
于 2012-05-04T13:23:28.533 に答える
17

ユーザーコードの場合、なぜそのような言語操作が使用されるのだろうか? これは何の魔法なのかと尋ねると、他の人はあなたが名前を持つ置換関数を呼び出していると指摘しましたlevels<-。ほとんどの人にとって、これは魔法であり、実際の使用目的はlevels(foo) <- bar.

productグローバル環境には存在せず、呼び出しのローカル環境にのみ存在するため、表示するユースケースは異なります。levels<-したがって、変更したい変更は持続しません。 の再割り当てはありませんでしdatた。

このような状況でwithin() は、使用するのに理想的な機能です。あなたは自然に書きたいと思うでしょう

levels(product) <- bar

Rではもちろんproduct、オブジェクトとしては存在しません。within()これは、R コードを実行する環境を設定し、その環境内で式を評価するためです。したがって、呼び出しからの戻りオブジェクトの割り当てはwithin()、適切に変更されたデータ フレームで成功します。

以下に例を示します (新規作成する必要はありませんdatX- 私はそれを行うだけなので、中間ステップは最後に残ります)

## 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))

これにより、次のことが得られます。

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

あなたが示したような構造がほとんどの場合にどのように役立つかを理解するのに苦労しています-データを変更したい場合は、データを変更し、別のコピーを作成してそれを変更しないでください(結局のところ、levels<-呼び出しが行っているのはこれだけです) )。

于 2012-05-04T14:58:10.410 に答える