`स्तर <-` (यह किस टोना-टोटका है?


114

एक अन्य प्रश्न के उत्तर में, @ मारेक ने निम्नलिखित समाधान पोस्ट किया: https://stackoverflow.com/a/10432263//36366

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

स्पष्ट रूप से यह स्तर के कार्य के लिए किसी प्रकार की कॉल है, लेकिन मुझे नहीं पता कि यहां क्या किया जा रहा है। इस प्रकार के टोना के लिए क्या शब्द है, और मैं इस डोमेन में अपनी जादुई क्षमता कैसे बढ़ाऊं?


1
names<-और भी है [<-
हून

1
इसके अलावा, मैं इस बारे में अन्य प्रश्न पर आश्चर्यचकित था, लेकिन यह नहीं पूछा: क्या structure(...)सिर्फ निर्माण के लिए कोई कारण नहीं है data.frame(product = c(11L, 11L, ..., 8L))? (अगर वहाँ कुछ जादू हो रहा है, तो मैं इसे भी
मिटा देना चाहूँगा

2
यह "levels<-"फ़ंक्शन के लिए एक कॉल है : function (x, value) .Primitive("levels<-")की तरह X %in% Y, के लिए एक संक्षिप्त नाम है "%in%"(X, Y)
बेनबर्न्स

2
@dbaupp प्रतिलिपि प्रस्तुत करने योग्य उदाहरणों के लिए बहुत आसान है: stackoverflow.com/questions/5963269/…
अरी बी। फ्रीडमैन

8
मुझे नहीं पता कि किसी ने इसे बंद करने के लिए वोट क्यों नहीं दिया? Q का बहुत स्पष्ट उत्तर है: उदाहरण में प्रयुक्त वाक्य रचना का अर्थ क्या है और यह R में कैसे काम करता है?
गैविन सिम्पसन

जवाबों:


104

यहां उत्तर अच्छे हैं, लेकिन वे एक महत्वपूर्ण बिंदु को याद कर रहे हैं। मुझे इसका वर्णन करने का प्रयास करें।

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

व्यक्तिगत रूप से, मुझे लगता है कि कोड की पंक्ति सुंदर है;)


33

कोई टोना-टोटका नहीं, बस इतना ही (उप) असाइनमेंट फ़ंक्शंस को कैसे परिभाषित किया जाता है। 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! ;-)

1
क्या आप इस बारे में थोड़ा और समझा सकते हैं कि जब यह सामान्य तरीके के बजाय कार्यों को कॉल करने के लिए समझ में आता है? मैं लिंक्ड प्रश्न में @ मारेक के उदाहरण के माध्यम से काम कर रहा हूं, लेकिन यह अधिक स्पष्ट स्पष्टीकरण देने में मदद करेगा।
ड्रू स्टीन

4
@DrewSteen: कोड स्पष्टता / पठनीयता कारणों के लिए, मैं कहूंगा कि यह कभी भी समझ में नहीं आता क्योंकि `levels<-`(foo,bar)जैसा है वैसा ही है levels(foo) <- bar। @ मर्क के उदाहरण का उपयोग करना: `levels<-`(as.factor(foo),bar)जैसा है वैसा ही है foo <- as.factor(foo); levels(foo) <- bar
यहोशू उलरिच

अच्छी सूची है। क्या आपको नहीं लगता levels<-कि वास्तव में यह केवल शॉर्टहैंड है attr<-(x, "levels") <- value, या कम से कम यह शायद तब तक था जब तक कि इसे एक आदिम में बदल दिया गया था और सी-कोड को सौंप दिया गया था।
IRTFM

30

उस "जादू" का कारण यह है कि "असाइनमेंट" फॉर्म में काम करने के लिए एक वास्तविक चर होना चाहिए। और 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)
  )

+1 मुझे लगता है कि पहले कारक में बदलना क्लीनर होगा, फिर ए के माध्यम से स्तरों को बदलें within()और transform()कॉल थे कि इस तरह संशोधित वस्तु को लौटाया और सौंपा गया है।
गेविन सिम्पसन

4
@GavinSimpson - मैं सहमत हूं, मैं केवल जादू की व्याख्या करता हूं, मैं इसका बचाव नहीं करता; ;-)
टॉमी

16

उपयोगकर्ता-कोड के लिए मुझे आश्चर्य है कि इस तरह की भाषा में हेरफेर क्यों किया जाता है? आप पूछते हैं कि यह क्या जादू है और दूसरों ने बताया है कि आप प्रतिस्थापन फ़ंक्शन को बुला रहे हैं जिसका नाम है levels<-। अधिकांश लोगों के लिए यह जादू है और वास्तव में अभीष्ट उपयोग है levels(foo) <- bar

आपके द्वारा दिखाया जाने वाला उपयोग-मामला अलग है क्योंकि productवैश्विक वातावरण में मौजूद नहीं है, इसलिए यह केवल कॉल के स्थानीय वातावरण में ही मौजूद है, levels<-इस प्रकार आप जो परिवर्तन करना चाहते हैं, वह जारी नहीं रहता है - का कोई पुनर्मूल्यांकन नहीं था dat

इन परिस्थितियों में, within() उपयोग करने के लिए आदर्श कार्य है। आप स्वाभाविक रूप से लिखना चाहेंगे

levels(product) <- bar

आर में लेकिन निश्चित productरूप से एक वस्तु के रूप में मौजूद नहीं है। within()इसके आस-पास हो जाता है क्योंकि यह उस वातावरण को सेट करता है जिसे आप अपने आर कोड के खिलाफ चलाना चाहते हैं और उस वातावरण में अपनी अभिव्यक्ति का मूल्यांकन करते हैं। कॉल से रिटर्न ऑब्जेक्ट को 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<-कॉल के बाद कर रहा है )।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.