2013-04-22 62 views
5

Tôi có một bộ dữ liệu khảo sát ở dạng rộng. Đối với một câu hỏi cụ thể, một tập hợp các biến được tạo ra trong dữ liệu thô để đại diện cho sự thật là câu hỏi khảo sát được hỏi vào một tháng cụ thể.Thực hiện các thao tác trên một tập con bằng cách sử dụng bảng dữ liệu

Tôi muốn tạo một tập hợp các biến mới có tên bất biến tháng; giá trị của các biến này sẽ tương ứng với giá trị của câu hỏi biến thể tháng cho tháng được quan sát.

Hãy xem một ví dụ/hư cấu bộ dữ liệu:

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

Trong cuộc khảo sát này, có thực sự chỉ có hai câu hỏi: "q1" và "q2". Mỗi câu hỏi này được hỏi nhiều lần trong vài tháng. Tuy nhiên, quan sát chỉ chứa phản hồi hợp lệ khi tháng được quan sát trong dữ liệu khớp với câu hỏi khảo sát cho một tháng cụ thể.

Ví dụ: "may.q1" được quan sát là "có" cho bất kỳ quan sát nào trong "Có thể". Tôi muốn biến "Q1" mới đại diện cho "may.q1", "jun.q1" và "jul.q1". Giá trị của "Q1" sẽ tính theo giá trị "may.q1" khi tháng "có thể" và giá trị "Q1" sẽ tính theo giá trị "jun.q1" khi tháng là "jun" .

Nếu tôi là để thử và làm điều này bằng tay sử dụng bảng dữ liệu, tôi muốn một cái gì đó như:

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

Tôi muốn điều này lặp đi lặp lại "bởi = tháng".

Nếu tôi được sử dụng "plyr" trọn gói cho một khung dữ liệu, tôi sẽ giải quyết bằng cách sử dụng phương pháp sau đây:

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

Bất kỳ sự giúp đỡ sử dụng một phương pháp data.table sẽ được đánh giá rất nhiều, như dữ liệu của tôi lớn. Cảm ơn bạn.

Trả lời

5

Một cách khác nhau để minh họa:

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 

Nhưng lưu ý cột tên đến từ nhóm đầu tiên (có thể đổi tên sau đó sử dụng setnames). Và nó có thể không hiệu quả nhất nếu có một số lượng lớn các cột chỉ với một vài cột cần thiết. Trong trường hợp đó, giải pháp của Arun tan chảy theo định dạng dài sẽ nhanh hơn.

+0

Oh wow .. Tôi dint nghĩ về điều này! tuyệt vời. – Arun

+0

MatthewDowle, đây là * chắc chắn * nhanh hơn (của tôi) tan chảy + cast. Tôi đã thử nó trên một dữ liệu lớn hơn. Tôi không có nơi nào gần ... Phải mất 23 giây trên một cột 1e5 * 100 trong khi điều này thực hiện nó trong chưa đầy một giây! – Arun

3

Chỉnh sửa: Dường như rất không hiệu quả trên dữ liệu lớn hơn. Xem câu trả lời của @ MatthewDowle cho giải pháp thực sự nhanh chóng và gọn gàng.

Đây là giải pháp sử dụng data.table.

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

Chức năng melt.dt là một chức năng nhỏ (vẫn còn nhiều cải tiến được thực hiện) Tôi đã viết thư cho melt một data.table tương tự như của các melt chức năng trong plyr (sao chép/dán chức năng này được hiển thị dưới đây trước khi cố gắng ra mã ở trên).

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

Ý tưởng: Đầu tiên làm tan data.table với id.var = month cột. Bây giờ, tất cả các tên cột được làm nóng của bạn có dạng month.question. Vì vậy, bằng cách loại bỏ ".question" khỏi cột được làm nóng này và tương đương với cột month, chúng tôi có thể xóa tất cả các mục nhập không cần thiết. Khi chúng tôi đã làm điều này, chúng tôi không cần "tháng". trong cột tan chảy "ind" nữa. Vì vậy, chúng tôi sử dụng gsub để xóa "tháng". để giữ lại chỉ q1, q2 vv .. Sau này, chúng tôi phải reshape (hoặc cast) nó. Điều này được thực hiện bằng cách nhóm theo month và chia tách cột values theo số ind (trong đó có q1 hoặc q2.Vì vậy, bạn sẽ nhận được 2 cột cho mỗi tháng (sau đó được khâu lại với nhau) để có được sản lượng mong muốn của bạn.

1

gì về một cái gì đó như thế này

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

Nếu bạn muốn đi xa hơn và tan chảy dữ liệu này một lần nữa bạn có thể sử dụng làm tan gói

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" ... 
Các vấn đề liên quan