2013-04-22 12 views
5

Mam zestaw danych pomiarowych w szerokiej formie. W przypadku konkretnego pytania zestaw zmiennych został utworzony w surowych danych, aby przedstawić inny fakt, że pytanie ankiety zostało zadane w danym miesiącu.Wykonywanie operacji na podzbiorze za pomocą tabeli danych

Chcę utworzyć nowy zestaw zmiennych, które mają nazwy niezmienne od miesiąca; wartość tych zmiennych będzie odpowiadać wartości pytania miesięcznego dla obserwowanego miesiąca.

proszę zobaczyć przykładową/fikcyjne zestaw danych:

require(data.table) 

data <- data.table(month = rep(c('may', 'jun', 'jul'), each = 5), 
        may.q1 = rep(c('yes', 'no', 'yes'), each = 5), 
        jun.q1 = rep(c('breakfast', 'lunch', 'dinner'), each = 5), 
        jul.q1 = rep(c('oranges', 'apples', 'oranges'), each = 5), 
        may.q2 = rep(c('econ', 'math', 'science'), each = 5), 
        jun.q2 = rep(c('sunny', 'foggy', 'cloudy'), each = 5), 
        jul.q2 = rep(c('no rain', 'light mist', 'heavy rain'), each = 5)) 

W tym badaniu, istnieją naprawdę tylko dwa pytania: "Q1" i "Q2". Każde z tych pytań jest wielokrotnie zadawane przez kilka miesięcy. Jednak obserwacja zawiera poprawną odpowiedź tylko wtedy, gdy miesiąc obserwowany w danych jest zgodny z pytaniem ankiety w danym miesiącu.

Na przykład: "may.q1" jest obserwowane jako "tak" dla każdej obserwacji w "Maj". Chciałbym, aby nowa zmienna "Q1" reprezentowała "may.q1", "jun.q1" i "jul.q1". Wartość "Q1" przyjmie wartość "may.q1", gdy miesiąc jest "may", a wartość "Q1" przyjmie wartość "jun.q1", gdy miesiąc to "jun" .

Gdybym miał spróbować i zrobić to ręcznie za pomocą tabeli danych, chciałbym coś takiego:

mdata <- data[month == 'may', c('month', 'may.q1', 'may.q2'), with = F] 
setnames(mdata, names(mdata), gsub('may\\.', '', names(mdata))) 

Chciałbym żeby to powtórzył „za = miesiąc”.

Gdybym miał użyć pakietu „plyr” dla ramki danych, chciałbym rozwiązać stosując następujące podejście:

require(plyr) 
data <- data.frame(data) 

mdata <- ddply(data, .(month), function(dfmo) { 
    dfmo <- dfmo[, c(1, grep(dfmo$month[1], names(dfmo)))] 
    names(dfmo) <- gsub(paste0(dfmo$month[1], '\\.'), '', names(dfmo)) 
    return(dfmo) 
}) 

Każda pomoc stosując metodę data.table byłoby bardzo mile widziane, jako moich danych Są duże. Dziękuję Ci.

Odpowiedz

5

Innym sposobem, aby zilustrować:

data[, .SD[,paste0(month,c(".q1",".q2")), with=FALSE], by=month] 

    month may.q1  may.q2 
1: may  yes  econ 
2: may  yes  econ 
3: may  yes  econ 
4: may  yes  econ 
5: may  yes  econ 
6: jun lunch  foggy 
7: jun lunch  foggy 
8: jun lunch  foggy 
9: jun lunch  foggy 
10: jun lunch  foggy 
11: jul oranges heavy rain 
12: jul oranges heavy rain 
13: jul oranges heavy rain 
14: jul oranges heavy rain 
15: jul oranges heavy rain 

jednak pamiętać kolumnę nazwy pochodzą z pierwszej grupy (można przemianować potem używając setnames). I może nie być najskuteczniejsza, jeśli istnieje duża liczba kolumn, z których tylko kilka jest potrzebnych. W takim przypadku rozwiązanie Aruna topiącego się do długiego formatu powinno być szybsze.

+0

Oh wow .. I nie odczuwało myślę o tym! niesamowite. – Arun

+0

MatthewDowle, to * zdecydowanie * szybciej niż (my) stopić i rzucić. Wypróbowałem to na większych danych. Mój nie jest tak blisko ... Zajmuje 23 sekundy na 1e5 * 100 kolumnach, podczas gdy robi to w mniej niż sekundę! – Arun

3

Edytuj: Wydaje się bardzo nieefektywny w przypadku większych danych. Sprawdź odpowiedź @ MatthewDowle na naprawdę szybkie i schludne rozwiązanie.

Oto rozwiązanie z użyciem data.table.

dd <- melt.dt(data, id.var=c("month"))[month == gsub("\\..*$", "", ind)][, 
     ind := gsub("^.*\\.", "", ind)][, split(values, ind), by=list(month)] 

Funkcja melt.dt to mała funkcja (jeszcze ulepszenia być wykonane) Napisałem do meltdata.table podobna do funkcji melt w plyr (kopiuj/wklej tę funkcję pokazaną poniżej przed wypróbowanie kod powyżej).

melt.dt <- function(DT, id.var) { 
    stopifnot(inherits(DT, "data.table")) 
    measure.var <- setdiff(names(DT), id.var) 
    ind <- rep.int(measure.var, rep.int(nrow(DT), length(measure.var))) 
    m1 <- lapply(c("list", id.var), as.name) 
    m2 <- as.call(lapply(c("factor", "ind"), as.name)) 
    m3 <- as.call(lapply(c("c", measure.var), as.name))  
    quoted <- as.call(c(m1, ind = m2, values = m3)) 
    DT[, eval(quoted)] 
} 

Pomysł: Najpierw topi data.table z id.var = month kolumnę. Teraz wszystkie stopione nazwy kolumn mają postać month.question. Tak więc, usuwając ".question" z tej stopionej kolumny i utożsamiając z kolumną month, możemy usunąć wszystkie niepotrzebne wpisy. Kiedy to zrobiliśmy, nie potrzebujemy "miesiąca". w stopionej kolumnie "ind". Dlatego używamy gsub, aby usunąć "miesiąc". zachować tylko q1, q2 itd. Po tym musimy mieć reshape (lub cast) go. Odbywa się to przez grupowanie przez month i dzielenie kolumny przez ind (która ma albo q1 lub q2.Otrzymasz 2 kolumny za każdy miesiąc (który jest następnie łączony), aby uzyskać pożądany wynik.

1

Co o czymś takim

data <- data.table(
        may.q1 = rep(c('yes', 'no', 'yes'), each = 5), 
        jun.q1 = rep(c('breakfast', 'lunch', 'dinner'), each = 5), 
        jul.q1 = rep(c('oranges', 'apples', 'oranges'), each = 5), 
        may.q2 = rep(c('econ', 'math', 'science'), each = 5), 
        jun.q2 = rep(c('sunny', 'foggy', 'cloudy'), each = 5), 
        jul.q2 = rep(c('no rain', 'light mist', 'heavy rain'), each = 5) 
        ) 


tmp <- reshape(data, direction = "long", varying = 1:6, sep = ".", timevar = "question") 

str(tmp) 
## Classes ‘data.table’ and 'data.frame': 30 obs. of 5 variables: 
## $ question: chr "q1" "q1" "q1" "q1" ... 
## $ may  : chr "yes" "yes" "yes" "yes" ... 
## $ jun  : chr "breakfast" "breakfast" "breakfast" "breakfast" ... 
## $ jul  : chr "oranges" "oranges" "oranges" "oranges" ... 
## $ id  : int 1 2 3 4 5 6 7 8 9 10 ... 

Jeśli chcesz iść dalej i topienie te dane ponownie można użyć pakietu stopu

require(reshape2) 
## remove the id column if you want (id is the last col so ncol(tmp)) 
res <- melt(tmp[,-ncol(tmp), with = FALSE], measure.vars = c("may", "jun", "jul"), value.name = "response", variable.name = "month") 

str(res) 
## 'data.frame': 90 obs. of 3 variables: 
## $ question: chr "q1" "q1" "q1" "q1" ... 
## $ month : Factor w/ 3 levels "may","jun","jul": 1 1 1 1 1 1 1 1 1 1 ... 
## $ response: chr "yes" "yes" "yes" "yes" ... 
Powiązane problemy