2015-06-29 20 views
5

Ich habe eine Frage, die hoffentlich nicht ein großes Hindernis für die erweiterte R Benutzer sein ...R: Einstellen von Werten für mehrere Vorkommen eines Falles

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

Wie Sie sehen vielleicht in der Lage, ich habe mehr Vorkommen für jeden Fall, unterschieden durch die Jahr. Die Werte von Level unterscheiden sich innerhalb eines Falles, und ich möchte das korrigieren, indem ich jeden Wert von Level auf das minimale Niveau eines gegebenen Falls einstelle. In diesem Beispiel wird jeder Wert von Ebene für case = 1 sollte 10 sein, und jeder Wert von Ebene für case = 2 sollte 12 Für jeden speziellen Fall sein ich folgendes tun könnte:

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

Aber da ich mehrere hundert Fälle habe, würde das ziemlich lange dauern. Daher würde ich gerne fragen, ob Sie eine schnellere Lösung haben.

Antwort

5

können Sie versuchen,

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 

Oder mit 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 

Oder 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 

mit oder eine Modifikation vorgeschlagen von @ G.Grothendieck mit nur 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 

Oder mit ist base R

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

hier eine klassische Funktionen Basis 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 

Zweite Vanille Option, Dinge zu tun wäre

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

Alternative mit 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 

Oder kompakter

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 

andere Basis R Methode usi zu sein 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 
Verwandte Themen