koşullu değerlerle dplyr mutasyonu


88

Dört sütunlu büyük bir veri çerçevesinde ("dosyam"), ilk dört sütunu temel alan değerleri koşullu olarak içeren beşinci bir sütun eklemem gerekiyor.

Büyük veri kümelerindeki hızı nedeniyle dplyrve ile yanıtları tercih edin mutate.

Veri çerçevem ​​şöyle görünüyor:

  V1 V2 V3 V4
1  1  2  3  5
2  2  4  4  1
3  1  4  1  1
4  4  5  1  3
5  5  5  5  4
...

Beşinci sütunun (V5) değerleri bazı koşullu kurallara dayanmaktadır:

if (V1==1 & V2!=4) {
  V5 <- 1
} else if (V2==4 & V3!=1) {
  V5 <- 2
} else {
  V5 <- 0
}

Şimdi mutatebu kuralları tüm satırlarda kullanmak için işlevi kullanmak istiyorum (yavaş döngülerden kaçınmak için). Bunun gibi bir şey (ve evet, bu şekilde çalışmadığını biliyorum!):

myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
    else if (V2==4 & V3!=1){V5 = 2}
    else {V5 = 0})

Sonuç şu olmalı:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

Bu nasıl yapılır dplyr?


V1..4'ün tümünün tamsayı olup olmadığını (faktör, mantıksal, dize veya kayan nokta değil) belirtmek yararlıdır ve doğru şekilde işlemeyi önemsiyor musunuz NA( NaN, +Inf, -Inf)?
smci

Hız tercih etmek için bir sorun gibi görünüyorsa dplyr, kullansam iyi olur data.table.
Valentin

Yanıtlar:


108

Bunu dene:

myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))

veren:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

veya bu:

myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))

veren:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

Not

Veri çerçeveniz için daha iyi bir isim almanızı önerin. myfile, bir dosya adı tutuyormuş gibi görünmesini sağlar.

Yukarıda bu girişi kullandı:

myfile <- 
structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 
5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L
)), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5"))

Güncelleme 1 aslen yayınlanmıştır dplyr yana değişti %.%için %>%buna göre böylece değiştirdiniz cevap.

Güncelleme 2 dplyr artık case_whenbaşka bir çözüm sağlar:

myfile %>% 
       mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, 
                             V2 == 4 & V3 != 1 ~ 2,
                             TRUE ~ 0))

İkinci çözümünüzü denedim. Bu hatayı aldım: mutate_impl (.data, named_dots (...), environment ()) 'da hata: REAL () sadece bir' sayısal 'için uygulanabilir,' mantıksal 'değil Neyin yanlış gittiğini biliyor musunuz?
rdatasculptor

5
ifelseİfadeleri iç içe geçirmene izin veren bir yol keşfettim :myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, 0), V5 = ifelse(V2 == 4 & V3 != 1, 2, V5))
Alex

32

İle dplyr 0.7.2çok kullanışlı case_whenişlevi kullanabilirsiniz:

x=read.table(
 text="V1 V2 V3 V4
 1  1  2  3  5
 2  2  4  4  1
 3  1  4  1  1
 4  4  5  1  3
 5  5  5  5  4")
x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1,
                 x$V2==4 & x$V3!=1 ~ 2,
                 TRUE ~ 0)

İle ifade dplyr::mutateedildiğinde verir:

x = x %>% mutate(
     V5 = case_when(
         V1==1 & V2!=4 ~ 1,
         V2==4 & V3!=1 ~ 2,
         TRUE ~ 0
     )
)

NAYanıltıcı olabileceği için özel olarak ele alınmadığını lütfen unutmayın . İşlev NAyalnızca hiçbir koşul eşleşmediğinde dönecektir . Örneğimde TRUE ~ ...yaptığım gibi ile bir satır koyarsanız , dönüş değeri asla olmayacaktır NA.

Bu nedenle, expressively anlatmak zorunda case_whenkoymak NAo böyle bir açıklama ekleyerek ait olduğu is.na(x$V1) | is.na(x$V3) ~ NA_integer_. İpucu: dplyr::coalesce()işlev bazen burada gerçekten yararlı olabilir!

Üstelik unutmayın NAyalnız genellikle iş, özel koymak zorunda kalacak NA: değerleri NA_integer_, NA_character_ya da NA_real_.


1
Bu, derivedFactor'dan önemli ölçüde daha hızlıydı.
Fato39

12

Öyle görünüyor derivedFactorgelen mosaicpaket bunun için tasarlanmıştır. Bu örnekte şunun gibi görünecektir:

library(mosaic)
myfile <- mutate(myfile, V5 = derivedFactor(
    "1" = (V1==1 & V2!=4),
    "2" = (V2==4 & V3!=1),
    .method = "first",
    .default = 0
    ))

(Sonucun faktör yerine sayısal olmasını istiyorsanız, bunu bir derivedFactorile sarın as.numeric.)

İle .defaultbirleştirilen seçeneğin .method = "first""else" koşulunu belirlediğini unutmayın - bu yaklaşım için yardım dosyasında açıklanmıştır derivedFactor.


Ayrıca, .asFactor = Fseçeneği kullanarak veya derivedVariableaynı paketteki (benzer) işlevini kullanarak sonucun faktör olmasını önleyebilirsiniz .
Jake Fisher

Görünüşe göre recodedplyr 0.5 bunu yapacak. Yine de henüz araştırmadım. Bkz. Blog.rstudio.org/2016/06/27/dplyr-0-5-0
Jake Fisher

Bu, 1e6 satırlı verilerim için yavaştı.
Fato39

3
@ Fato39 Evet, mosaic::derivedFactorişlevler ailesi çok yavaş. Nedenini anlarsanız, lütfen SO sorumu yanıtlayın: stackoverflow.com/questions/33787691/… . Diğer yorumunuzdan dplyr::case_whendaha hızlı olduğunu gördüğüme sevindim - buna geçmem gerekecek.
Jake Fisher

Aşağıdaki komutu deniyorum, kütüphane (mozaik) VENEZ.FINAL2 <- mutate (VENEZ, SEX = derivatedFactor ("M" = (CATEGORY == "BULL" & CATEGORY! = "SIRE"), "F" = ( KATEGORİ == "İNEK" & KATEGORİ! = "HEIFER"), .method = "ilk", .default = "NA")) ama işe yaramıyor, sadece VENEZ.FINAL2 <- mutate (VENEZ, SEKS = türetilmişFaktör ("M" = (KATEGORİ == "BULL Bana yardım edebilir misin? Çok teşekkürler!
Johanna Ramirez
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.