2015-06-29 23 views
5

Mam pytanie mam nadzieję, że nie będzie się ogromnym utrudnieniem dla użytkowników zaawansowanych R ...R: ustawianie wartości dla wielu wystąpień przypadku

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)) 

Jak można być w stanie zobaczyć, mam wiele wystąpienia dla każdego przypadku , wyróżnione przez rok. Wartości poziomu różnią się w przypadku i chciałbym to poprawić, ustawiając każdą wartość poziomu na minimalny poziom danej sprawy. W tym przykładzie, każda wartość poziomie dla przypadku = 1 powinna wynosić 10, a każda wartość poziomie w przypadku = 2 powinien być 12. dla każdego konkretnego przypadku mogę wykonywać następujące czynności:

test.data$level[test.data$case==1] <- min(test.data$level[test.data$case==1]) 

Ale ponieważ mam kilkaset przypadków, zajmie to dość długo. Dlatego chciałbym zapytać, czy masz szybsze rozwiązanie.

Odpowiedz

5

Można spróbować

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 

lub używając 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 

lub używając 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 

Albo modyfikacją sugerowane przez @ G.Grothendieck używając tylko sqldf

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 

lub używając base R

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

Oto klasyczne użyciu funkcji baza R.

# 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 

Druga opcja wanilia robienia rzeczy byłoby

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

alternatywna użyciu 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 

albo być bardziej kompaktowy

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 

innej bazie R metoda USI 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