2015-06-29 25 views
5

Umarım gelişmiş Ar kullanıcıları için büyük bir engel olmayacak bir soru ... R: bir durumda birden fazla kopyasını değerlerini ayarlamak

test.data <- data.frame(case = c(1, 1, 1, 2, 2, 2, 3), year = c(2006, 2007, 2008, 2007, 2006, 2008, 2006), level = c(10, 20, 20, 12, 20, 20, 20)) 

görmek mümkün olabilir gibi

, birden sahip olması yıl ayırt her durumda için olaylar. seviyesinin değerleri bir durumda içinde farklılık ve ben belirli bir durumda asgari seviyeye seviyesinin her değerini ayarlayarak o düzeltmek isterim. Bu örnekte, seviye değerin her durum için = 1 ila 10 olmalıdır ve durum için seviye her değeri = 2 Aşağıdaki yapabileceği her özel durum için 12. olmalıdır:

test.data$level[test.data$case==1] <- min(test.data$level[test.data$case==1]) 
Ben birkaç yüz durumlarda beri

Fakat bu oldukça uzun sürer. Bu nedenle, daha hızlı bir çözümünüz olup olmadığını sormak istiyorum.

cevap

5

Sen

library(data.table) 
setDT(test.data)[, level:= min(level, na.rm=TRUE), case] 
# case year level 
#1: 1 2006 10 
#2: 1 2007 10 
#3: 1 2008 10 
#4: 2 2007 12 
#5: 2 2006 12 
#6: 2 2008 12 
#7: 3 2006 20 

Ya sqldf/dplyr

library(sqldf) 
    library(dplyr) 
    sqldf('select * from "test.data" 
      left join(select "case", 
       min(level) as Level 
       from "test.data" 
       group by "case") 
      using ("case")') %>% 
         select(-level) 
    # case year Level 
    #1 1 2006 10 
    #2 1 2007 10 
    #3 1 2008 10 
    #4 2 2007 12 
    #5 2 2006 12 
    #6 2 2008 12 
    #7 3 2006 20 

kullanılarak dplyr

library(dplyr) 
test.data %>% 
     group_by(case) %>% 
     mutate(level= min(level, na.rm=TRUE)) 
# case year level 
#1 1 2006 10 
#2 1 2007 10 
#3 1 2008 10 
#4 2 2007 12 
#5 2 2006 12 
#6 2 2008 12 
#7 3 2006 20 

Ya kullanmayı deneyebilirsiniz Veya @ G.Grothendieck önerdiği bir değişiklik sadece sqldf

kullanarak
sqldf('select "case", year, "min(level)" as Level 
      from "test.data" 
       left join(select "case", min(level) 
         from "test.data" 
         group by "case") 
        using ("case")') 

    #1 1 2006 10 
    #2 1 2007 10 
    #3 1 2008 10 
    #4 2 2007 12 
    #5 2 2006 12 
    #6 2 2008 12 
    #7 3 2006 20 

Ya base R

test.data$level <- with(test.data, ave(level, case, FUN=min)) 
5

kullanarak Burada klasik kullanılarak baz R fonksiyonlarını var. şeyler yapmanın

# may not be optimal for larger datasets due to merge 
min.lvl <- aggregate(level ~ case, data = test.data, FUN = min) 
merge(x = test.data, y = min.lvl, by = "case", all.x = TRUE, sort = FALSE) 

    case year level.x level.y 
1 1 2006  10  10 
2 1 2007  20  10 
3 1 2008  20  10 
4 2 2007  12  12 
5 2 2006  20  12 
6 2 2008  20  12 
7 3 2006  20  20 

İkinci vanilya seçenek olacaktır

new.data <- by(data = test.data, INDICES = test.data$case, FUN = function(x) { 
    x$level <- min(x$level) 
    x 
}) 

do.call("rbind", new.data) 

    case year level 
1.1 1 2006 10 
1.2 1 2007 10 
1.3 1 2008 10 
2.4 2 2007 12 
2.5 2 2006 12 
2.6 2 2008 12 
3  3 2006 20 
3

doBy

library(doBy) 
summaryBy(level ~ case, id=~ year, test.data, 
      full.dimension=TRUE, keep.names=TRUE, min) 

# case level year 
#1: 1 10 2006 
#2: 1 10 2006 
#3: 1 10 2006 
#4: 2 12 2007 
#5: 2 12 2007 
#6: 2 12 2007 
#7: 3 20 2006 

Veya daha kompakt olması

library(plyr) 
ddply(test.data, .(case), mutate, level = min(level)) 

# case year level 
#1 1 2006 10 
#2 1 2007 10 
#3 1 2008 10 
#4 2 2007 12 
#5 2 2006 12 
#6 2 2008 12 
#7 3 2006 20 

başka baz R yöntemi USI kullanarak alternatif ng lapply

do.call(rbind,lapply(split(test.data, test.data$case), 
       function(x){x$level = min(x$level); x})) 

# case year level 
#1: 1 2006 10 
#2: 1 2007 10 
#3: 1 2008 10 
#4: 2 2007 12 
#5: 2 2006 12 
#6: 2 2008 12 
#7: 3 2006 20