Mutasyonun sağ tarafında recodeta düzenli tabanlı standart dışı değerlendirmenin kullanılması


13

Her sütunun birçok değer alabilen bir karakter vektörü olduğu bir tibble düşünün - diyelim ki "A" - "F".

library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))

Bağımsız değişken olarak bir sütun adı alır ve bu sütunu yeniden kodlar, böylece herhangi bir yanıt "A" bir NA olur ve df aksi halde olduğu gibi döndürülür. Bu şekilde tasarlanmasının nedeni, belirli bir sütunu kullanarak bir dizi işlemi gerçekleştiren daha geniş bir boru hattına uymaktır.

Bunu yapmanın birçok yolu var. Ama en iyi deyimsel tidy_eval / tidyverse yaklaşımının ne olacağını anlamak istiyorum. İlk olarak, soru adının mutasyona uğramış bir fiilin sol tarafında olması gerektiğinden , !!ve :=operatörlerini uygun şekilde kullanıyoruz. Ama sonra, sağ tarafa ne konmalı?

fix_question <- function(df, question) {
    df %>% mutate(!!question := recode(... something goes here...))
}

fix_question(sample_df, "q1") # should produce a tibble whose first column is (NA, "B", "C")

İlk düşüncem bunun işe yarayacağıydı:

df %>% mutate(!!question := recode(!!question, "A" = NA_character_))

Ama tabii ki fonksiyonun içindeki patlama sadece değişmez karakter dizesini döndürür (örneğin "q1"). Temel R [[operatörünü kullanarak ve .dplyr'den yapıya güvenerek , sağ taraftaki verilere başvurmak için hileli bir rota gibi hissettiren şeyi aldım ve dplyr'den yapıya güveniyorum ve işe yarıyor, bu yüzden bir anlamda temel sorunumu çözdüm:

df %>% mutate(!!question := recode(.[[question]], "A" = NA_character_))

Deneme konusunda çok iyi olan insanlardan, bunu yapmanın daha deyimsel bir yolu olup olmadığı konusunda geri bildirim almakla ilgileniyorum. Düşüncesi olan var mı?


Teşekkürler, bu akıllıca bir yaklaşımdır - Kodumdaki diğer bölümlerde fonksiyonel yaklaşımı kullanıyorum ve burada da yapmayı düşünebilirdim. Kod stilinde kaşlarını çatmış bazı insanların SO hakkında konuştuğunu biliyorum, ancak birkaç farklı cevap stilini bu kadar hızlı görmek benim için çok verimli oldu.
aaron

1
Bu sorudaki birkaç fikri birleştirerek, bunun hem q1(sembol) hem de "q1"(dize) ile çalışan en özlü versiyon olduğuna inanıyorum :df %>% mutate_at( vars(!!ensym(question)), recode, A = NA_character_)
Artem Sokolov

Yanıtlar:


6

Burada, sağ tarafında :=, biz belirtebilirsiniz sym(sembole dönüştürmek ve daha sonra değerlendirmek için !!)

fix_question <- function(df, question) {
    df %>%
       mutate(!!question := recode(!! rlang::sym(question), "A" = NA_character_))
  }

fix_question(sample_df, "q1") 
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

Hem alıntılanmış hem de alıntılanmamış girdi için işe yarayacak daha iyi bir yaklaşım ensym

fix_question <- function(df, question) {
    question <- ensym(question)
    df %>%
       mutate(!!question := recode(!! question, "A" = NA_character_))
  }


fix_question(sample_df, q1)
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

fix_question(sample_df, "q1")
# A tibble: 3 x 2
#  q1    q2   
#  <chr> <chr>
#1 <NA>  B    
#2 B     B    
#3 C     A    

2
Rlang dönüştürme işlevlerinden birkaçı ile uğraşmaya çalışmıştım ama tabii ki doğru olanı seçmedim, ama yaklaşımınız işe yarıyor - bence gerçekten sadece kafamdaki tip dönüşümlerini iş akışı yapmam gerekiyor. Benim soru çalışmıyor çünkü bir karakter dizesini tam anlamıyla değerlendirir. Sizinki çalışır, çünkü önce karakter dizesini bir sembole dönüştürür ve ardından vektörü döndürerek sembolü değerlendirir. Operasyonların sırası olduğunu aklıma katamadım. Tekrar teşekkürler.
aaron

8

Eğer rlang> = 0.4.0 ise "kıvırcık kıvırcık" yöntemini kullanabilirsiniz .

@ Eipi10 sayesinde açıklama:

Tek adımda içine alıntı sonra-unquote Bu birleştirir iki aşamalı bir işlemdir, bu nedenle {{question}}eşdeğerdir!!enquo(question)

fix_question <- function(df, question){
  df %>% mutate({{question}} := recode({{question}}, A = NA_character_))
}

fix_question(sample_df, q1)
# # A tibble: 3 x 2
#   q1    q2   
#   <chr> <chr>
# 1 NA    B    
# 2 B     B    
# 3 C     A    

ensymYaklaşımdan farklı olarak , bunun karakter adlarıyla çalışmadığını unutmayın. Daha da kötüsü, sadece bir hata vermek yerine yanlış şeyi yapar.

fix_question(sample_df, 'q1')

# # A tibble: 3 x 2
#   q1    q2   
#   <chr> <chr>
# 1 q1    B    
# 2 q1    B    
# 3 q1    A    

2
Henüz "kıvırcık kıvırcık" alışkanlığına girmedim. OP'nin görünüşte aynı "bang bang" versiyonu işe yaramazken bunun neden işe yaradığını biliyor musunuz?
camille

Yakında duyduğum kıvırcık kıvırcıktan bahsettiğiniz için teşekkürler. Cevap kurduğum rlang / dplyr sürümü için işe yaramıyor; LHS ile ilgili bir hata alıyorum. LHS'yi LHS'imle değiştirir ve q1 teklif edersem, yukarıda yaşadığım aynı problemi alırım; q1'i alıntılamazsam, bir hata alıyorum. Bu muhtemelen bir sürüm şeyidir.
aaron

1
O zamandan beri bunu yapmazsanız, bu yüzden 0.4.0 rlang Evet sadece Haziran ayı sonunda serbest bırakıldı bu mısın için değil iş
IceCreamToucan

2
Bence bang-bang işe yaramadı çünkü questionilk olarak question = enquo(question)dplyr borusunda kullanılmadan önce bir pozlama ( ) haline getirilmesi gerekiyor . {{question}}eşittir !!enquo(question).
eipi10

2
Sorunun ilk örneği için de eşdeğer olması için enquo gerekir.
IceCreamToucan

7

Bir kodlanmış değerler vektörünün argüman olarak da girilmesine izin vererek işlevi biraz daha esnek hale getirebilirsiniz. Örneğin:

library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))

fix_question <- function(df, question, recode.vec) {

  df %>% mutate({{question}} := recode({{question}}, !!!recode.vec))

}

fix_question(sample_df, q1, c(A=NA_character_, B="Was B"))
  q1    q2   
1 <NA>  B    
2 Was B B    
3 C     A

Not recode.vecile "unquote uçları birleştirilmiş" dir !!!. Dplyr skeç ile Programlama'dan uyarlanan bu örnekle bunun ne yaptığını görebilirsiniz (ilgili örnekleri görmek için "ekleme" yi arayın). Bağımsız değişken olarak kullanılmaları için, !!!değer çiftlerinin recodeişleve nasıl "eklediğini" unutmayın ....recode

x = c("A", "B", "C")
args = c(A=NA_character_, B="Was B")

quo(recode(x, !!!args))

<quosure>
expr: ^recode(x, A = <chr: NA>, B = "Was B")
env:  global

Potansiyel olarak birden fazla sütunda kodlama işlevini çalıştırmak istiyorsanız, bunu yalnızca bir sütun adı ve bir kodlama vektörü alan bir işleve dönüştürebilirsiniz. Bu yaklaşım daha boru dostu olacak gibi görünüyor.

fix_question <- function(question, recode.vec) {

  recode({{question}}, !!!recode.vec)

}

sample_df %>% 
  mutate_at(vars(matches("q")), list(~fix_question(., c(A=NA_character_, B="Was B"))))
  q1    q2   
1 <NA>  Was B
2 Was B Was B
3 C     <NA>

Veya tek bir sütunu yeniden kodlamak için:

sample_df %>% 
  mutate(q1 = fix_question(q1, c(A=NA_character_, B="Was B")))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.