dplyr :: mutate birden çok değer eklemek için

Bu konuda dplyr Github repo 'da ve bununla ilgili en az bir SO sorusunda birkaç sorun var. ama hiçbiri sorumu tam olarak karşılamıyor - sanırım.

İşte kullanım durumum: Tam binom güven aralıklarını hesaplamak istiyorum

dd <- data.frame(x=c(3,4),n=c(10,11))
get_binCI <- function(x,n) {
    rbind(setNames(c(binom.test(x,n)$conf.int),c("lwr","upr")))
}
with(dd[1,],get_binCI(x,n))
##             lwr       upr
## [1,] 0.06673951 0.6524529

Bunu do() ile yapabilirim ancak bunu yapmanın daha anlamlı bir yolu olup olmadığını merak ediyorum ( mutate() yapabileceği gibi geliyor) Özetlemek için tartışıldığı gibi bir .n argümanına sahip > ...)

library("dplyr")
dd %>% group_by(x,n) %>%
    do(cbind(.,get_binCI(.$x,.$n)))

## Source: local data frame [2 x 4]
## Groups: x, n
## 
##   x  n        lwr       upr
## 1 3 10 0.06673951 0.6524529
## 2 4 11 0.10926344 0.6920953

24
Bunu özellikle dplyr ile yapmaya karar verdiniz mi? data.table ile setDT (dd) [ as.list (get_binCI (x, n)) = 'i (x, n)] hızlı bir şekilde yapabilirsiniz. Zihin okuma becerilerim tam olarak ne demek istediğimi belirlememe izin vermese de " etkileyici yol " ...
katma yazar David Arenburg, kaynak
Bu kesinlikle iyi. Ben bir dplyr yanıtını umuyordum (yukarıdaki çözümüm ATM yapabilecek en iyisiyse şaşırmayacağım). data.table 'a karşı hiçbir şeyim yok, ancak dplyr ' ı tercih ediyorum ve - çoğunlukla - hala kafamı dolaştırarak çok fazla beyin gücü harcıyorum. Şu anda tamamen yeni bir sözdizimi kümesi eklemek istemiyorum (ya da öğrencilerime ve meslektaşlarıma eklemek). Ama bu şekilde cevap verirsen, oy kullanacağım, işe yarar.
katma yazar Ben Bolker, kaynak
Bu kesinlikle iyi. Ben bir dplyr yanıtını umuyordum (yukarıdaki çözümüm ATM yapabilecek en iyisiyse şaşırmayacağım). data.table 'a karşı hiçbir şeyim yok, ancak dplyr ' ı tercih ediyorum ve - çoğunlukla - hala kafamı dolaştırarak çok fazla beyin gücü harcıyorum. Şu anda tamamen yeni bir sözdizimi kümesi eklemek istemiyorum (ya da öğrencilerime ve meslektaşlarıma eklemek). Ama bu şekilde cevap verirsen, oy kullanacağım, işe yarar.
katma yazar Ben Bolker, kaynak
Herkese selam, bunu çarpmak için umut; Şimdi bunu yuvalama ile yapmanın daha iyi bir yolu var mı? Deniyorum ama henüz almadım.
katma yazar Aaron, kaynak
Herkese selam, bunu çarpmak için umut; Şimdi bunu yuvalama ile yapmanın daha iyi bir yolu var mı? Deniyorum ama henüz almadım.
katma yazar Aaron, kaynak
@Aaron, ilginizi çekebilecek map2 'i kullanan unnest ' ı kullanmaya gittim
katma yazar markdly, kaynak
@Aaron, ilginizi çekebilecek map2 'i kullanan unnest ' ı kullanmaya gittim
katma yazar markdly, kaynak

6 cevap

Yine başka bir varyasyon, sanırım hepimiz burada saçları ayırıyoruz.

> dd <- data.frame(x=c(3,4),n=c(10,11))
> get_binCI <- function(x,n) {
+   as_data_frame(setNames(as.list(binom.test(x,n)$conf.int),c("lwr","upr")))
+ }
> 
> dd %>% 
+   group_by(x,n) %>%
+   do(get_binCI(.$x,.$n))
Source: local data frame [2 x 4]
Groups: x, n

  x  n        lwr       upr
1 3 10 0.06673951 0.6524529
2 4 11 0.10926344 0.6920953

Şahsen, eğer sadece okunabilirliğe gidiyorsak, bunu tercih ederim:

foo  <- function(x,n){
    bi <- binom.test(x,n)$conf.int
    data_frame(lwr = bi[1],
               upr = bi[2])
}

dd %>% 
    group_by(x,n) %>%
    do(foo(.$x,.$n))

... ama şimdi saçları gerçekten bölüyoruz.

10
katma
@weymouth magrittr vignette adresini deneyin.
katma yazar joran, kaynak
Sanırım ikinci çözümün kazandı, ama bir süreliğine kabullenmeye devam edeceğim.
katma yazar Ben Bolker, kaynak
... ve ... gerçek kullanım durumumda x ve n dışında bir şey üzerinde gruplanmam gerekiyor ... ancak bunu kullanabilirim
katma yazar Ben Bolker, kaynak
dışarı ayarlamalar Yine de data.frame() 'a ihtiyacım olmadı (düzenlemelere bakın).
katma yazar Ben Bolker, kaynak
Birisi beni '. $ A' sözdiziminin açıklandığı yere işaret edebilir mi?
katma yazar weymouth, kaynak

Yine bir başka seçenek ise, purrr :: map işlev ailesini kullanmak olabilir.

If you replace rbind with dplyr::bind_rows in the get_binCI function:

library(tidyverse)

dd <- data.frame(x = c(3, 4), n = c(10, 11))
get_binCI <- function(x, n) {
  bind_rows(setNames(c(binom.test(x, n)$conf.int), c("lwr", "upr")))
}

You can use purrr::map2 with tidyr::unnest:

dd %>% mutate(result = map2(x, n, get_binCI)) %>% unnest()

#>   x  n        lwr       upr
#> 1 3 10 0.06673951 0.6524529
#> 2 4 11 0.10926344 0.6920953

Or purrr::map2_dfr with dplyr::bind_cols:

dd %>% bind_cols(map2_dfr(.$x, .$n, get_binCI))

#>   x  n        lwr       upr
#> 1 3 10 0.06673951 0.6524529
#> 2 4 11 0.10926344 0.6920953
6
katma
Güzel, teşekkürler, bu yardımcı oldu.
katma yazar Aaron, kaynak

İşte bunun yerine data.table paketini kullanarak hızlı bir çözüm

İlk olarak, işlevinde küçük bir değişiklik

get_binCI <- function(x,n) as.list(setNames(binom.test(x,n)$conf.int, c("lwr", "upr")))

O zaman, basitçe

library(data.table)
setDT(dd)[, get_binCI(x, n), by = .(x, n)]
#    x  n        lwr       upr
# 1: 3 10 0.06673951 0.6524529
# 2: 4 11 0.10926344 0.6920953
5
katma
@rawr Neden bunu cevabımın altında bir yorum olarak yayınladığınızdan emin değilim :) Bunu kendi çözümünüz olarak göndermenizi öneririm (oy vereceğim).
katma yazar David Arenburg, kaynak
Map() ve mapply() 'ın temelde aynı olduğunu düşündüm: ' Harita ', sonucu basitleştirmeye çalışmayan' mapply 'için basit bir paketleyicidir. Common Lisp'in 'mapcar'ına benzer (ancak argümanlar geri dönüştürülür).
katma yazar Ben Bolker, kaynak
@rawr, Harita() daha güvenli (basitleştirme yok)?
katma yazar Ben Bolker, kaynak
@BenBolker, ancak sanırım, bir do.call kullanmak zorunda kalacaksınız, değil mi?
katma yazar rawr, kaynak
Burada bir temel çözüm @David Arenburg !! dd [ c ('lwr', 'upr')]] <- t (eşleme (get_binCI, dd [ 1], dd [ 2]))
katma yazar rawr, kaynak
@BenBolker tek fark, eşlemenin varsayılan değerinin SIMPLIFY = TRUE olması ve haritanın yanlış olması ve haritanın varsayılanını açıkça değiştiremeyeceğinizdir
katma yazar rawr, kaynak

İşte bunun yerine data.table paketini kullanarak hızlı bir çözüm

İlk olarak, işlevinde küçük bir değişiklik

get_binCI <- function(x,n) as.list(setNames(binom.test(x,n)$conf.int, c("lwr", "upr")))

O zaman, basitçe

library(data.table)
setDT(dd)[, get_binCI(x, n), by = .(x, n)]
#    x  n        lwr       upr
# 1: 3 10 0.06673951 0.6524529
# 2: 4 11 0.10926344 0.6920953
5
katma
@rawr Neden bunu cevabımın altında bir yorum olarak yayınladığınızdan emin değilim :) Bunu kendi çözümünüz olarak göndermenizi öneririm (oy vereceğim).
katma yazar David Arenburg, kaynak
Map() ve mapply() 'ın temelde aynı olduğunu düşündüm: ' Harita ', sonucu basitleştirmeye çalışmayan' mapply 'için basit bir paketleyicidir. Common Lisp'in 'mapcar'ına benzer (ancak argümanlar geri dönüştürülür).
katma yazar Ben Bolker, kaynak
@rawr, Harita() daha güvenli (basitleştirme yok)?
katma yazar Ben Bolker, kaynak
@BenBolker, ancak sanırım, bir do.call kullanmak zorunda kalacaksınız, değil mi?
katma yazar rawr, kaynak
Burada bir temel çözüm @David Arenburg !! dd [ c ('lwr', 'upr')]] <- t (eşleme (get_binCI, dd [ 1], dd [ 2]))
katma yazar rawr, kaynak
@BenBolker tek fark, eşlemenin varsayılan değerinin SIMPLIFY = TRUE olması ve haritanın yanlış olması ve haritanın varsayılanını açıkça değiştiremeyeceğinizdir
katma yazar rawr, kaynak

Bu "standart" bir dplyr iş akışı kullanıyor, ancak yorumlarda @BenBolker'ın not ettiği gibi, iki kez get_binCI çağırılmasını gerektiriyor:

dd %>% group_by(x,n) %>%
  mutate(lwr=get_binCI(x,n)[1],
         upr=get_binCI(x,n)[2])

  x  n        lwr       upr
1 3 10 0.06673951 0.6524529
2 4 11 0.10926344 0.6920953
5
katma
Evet, bu bir çözüm, ancak bunun çirkinliği get_binCI() 'yi iki kez aramak zorunda. Bakıcının gözünde, 'dan (cbind (., Data.frame (get_binCI (. $ X,. $ N)))' dan daha iyi veya daha kötü olup olmadığına bakın. get_binCI içine yapıştırarak data.frame() 'dan kurtulun
katma yazar Ben Bolker, kaynak
Katılıyorum. Sadece dplyr ile do demeden çalışacak bir şey bulmaya çalışıyordum.
katma yazar eipi10, kaynak

rowwise ve iç içe geçme ile ilgili bazı olasılıklar.

library("dplyr")
library("tidyr")

Eğlence için, tekrarlanan x/n kombinasyonlarına sahip veri çerçevesi

dd <- data.frame(x=c(3, 4, 3), n=c(10, 11, 10))

Joran'ın gibi, bir veri çerçevesi döndüren CI işlevinin sürümleri

get_binCI_df <- function(x,n) {
  binom.test(x, n)$conf.int %>% 
    setNames(c("lwr", "upr")) %>% 
    as.list() %>% as.data.frame()
}

Önceden olduğu gibi x ve n öğelerine göre gruplama, kopyayı kaldırır.

dd %>% group_by(x,n) %>% do(get_binCI_df(.$x,.$n))
# # A tibble: 2 x 4
# # Groups:   x, n [2]
#       x     n       lwr       upr
#              
# 1     3    10 0.1181172 0.8818828
# 2     4    11 0.1092634 0.6920953

rowwise öğesini kullanmak tüm satırları tutar, ancak cbind (. (gibi) komutunu tekrar kullanmazsanız x ve n öğelerini kaldırır. Ben OP'sinde yapar).

dd %>% rowwise() %>% do(cbind(., get_binCI_df(.$x,.$n)))
# Source: local data frame [3 x 4]
# Groups: 
#   
# # A tibble: 3 x 4
#       x     n        lwr       upr
# *             
# 1     3    10 0.06673951 0.6524529
# 2     4    11 0.10926344 0.6920953
# 3     3    10 0.06673951 0.6524529

İç içe yerleştirme daha temiz çalışabilir gibi görünüyor, ancak bu alabildiğim kadar iyi. mutate kullanımı, doğrudan . $ X ve yerine x ve n kullanabileceğim anlamına gelir. $ N , ancak mutate tek bir değer bekliyor, bu nedenle list 'e sarılması gerekiyor.

dd %>% rowwise() %>% mutate(ci=list(get_binCI_df(x, n))) %>% unnest()
# # A tibble: 3 x 4
#       x     n        lwr       upr
#               
# 1     3    10 0.06673951 0.6524529
# 2     4    11 0.10926344 0.6920953
# 3     3    10 0.06673951 0.6524529

Son olarak, böyle bir şey gibi görünüyor dplyr için (5 Ekim 2017 itibariyle) açık bir sorun; bakınız https://github.com/tidyverse/dplyr/issues/2326 ; Böyle bir şey uygulanırsa o zaman bu en kolay yol olacak!

1
katma