r - `مستويات<-`(ما السحر هو هذا؟




types levels (3)

في إجابة لسؤال آخر ، نشر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<- الاسم levels<- مربكة بعض الشيء لأنها تقترح مهمة ، لكن هذا ليس ما يجري. رمز هو مجرد إعداد نوع من خطوط الأنابيب:

  • ابدأ dat$product

  • تحويله إلى عامل

  • تغيير المستويات

  • تخزين هذا في res

شخصيا ، أعتقد أن خط الكود جميل ؛)


السبب في ذلك "السحر" هو أن نموذج "المهمة" يجب أن يكون له متغير حقيقي للعمل عليه. ولم يتم تعيين 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)
  )

للحصول على رمز المستخدم لا أتساءل لماذا يتم استخدام هذه التلاعب اللغة ذلك؟ تسأل ما سحر هذا ، وأشار آخرون إلى أنك تقوم باستدعاء وظيفة الاستبدال التي تحتوي على levels<- الاسم levels<- . بالنسبة لمعظم الناس هذا هو السحر وحقاً الاستخدام المقصود هو levels(foo) <- bar .

تختلف حالة الاستخدام التي تعرضها نظرًا لعدم وجود product في البيئة العالمية ، لذا لا توجد إلا في البيئة المحلية للدعوة إلى levels<- وبالتالي ، فإن التغيير الذي تريده لا يستمر - فليس هناك إعادة انتداب dat .

في هذه الظروف ، within() هي وظيفة مثالية للاستخدام. كنت ترغب بالطبع في الكتابة

levels(product) <- bar

في R لكن بالطبع لا يوجد منتج ككائن. 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<- المكالمة تفعل بعد كل شيء).





levels