2013-04-22 47 views
5

我有一個廣泛的調查數據集。對於一個特定的問題,在原始數據中創建了一組變量來表示調查問題在特定月份被問到的不同事實。使用數據表對子集執行操作

我希望創建一個具有月份不變名稱的新變量集合;這些變量的值將對應於所觀察月份的月份變量問題的值。

請看一個例​​子/虛構數據集:

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

在此次調查中,有真的只有兩個問題: 「Q1」 和 「Q2」。這些問題中的每一個都被反覆詢問了幾個月。但是,只有在數據中觀察到的月份與特定月份的調查問題相匹配時,觀察結果才包含有效的答覆。

例如:對於「May」中的任何觀察,「may.q1」被觀察爲「是」。我想要一個新的「Q1」變量來表示「may.q1」,「jun.q1」和「jul.q1」。當月份爲「可」時,「Q1」的值將取「may.q1」的值,當月份爲「jun」時,「Q1」的值將取值「jun.q1」 。

如果我嘗試並使用數據表手工做到這一點,我想是這樣的:

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

我想這個重複「通過=月」。

如果我是使用「plyr」包用於數據幀,我會解決使用以下方法:

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

使用data.table方法任何幫助將不勝感激,如我的數據很大。謝謝。

回答

5

一種不同的方式來說明:

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 

但需要注意的列名來自第一組(可以重命名之後使用setnames)。如果只有少數需要的列數量很多,它可能不是最有效的。在這種情況下,Arun解決方案融化爲長格式應該更快。

+0

哇..我覺得憑着這個!真棒。 – Arun 2013-04-22 18:56:58

+0

MatthewDowle,這肯定比(我的)融合​​+演員快。我嘗試了一個更大的數據。我不是在哪裏接近...... 1e5 * 100列需要23秒,而這隻需要不到一秒鐘! – Arun 2013-04-22 19:56:38

3

編輯:似乎對更大的數據非常低效。查看@ MatthewDowle的答案,真的很快,整潔的解決方案。

下面是使用data.table的解決方案。

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

功能melt.dt是一個小功能(以進行進一步的改進),我寫信給melt一個data.tableplyr(副本類似於melt功能/粘貼嘗試代碼之前,如下所示此功能以上)。

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

的想法:首先熔化data.tableid.var = month柱。現在,所有已熔化的列名稱格式爲month.question。所以,通過從這個熔化的列中移除「.question」並等同於month列,我們可以刪除所有不必要的條目。一旦我們這樣做了,我們不需要「月」。在熔化的列「ind」了。所以,我們使用gsub來刪除「月」。保留只是q1, q2等。此後,我們要reshape(或cast)它。這是通過將month分組並且將values列拆分ind(其具有q1q2。所以,你會得到每個月2列(然後拼接在一起),以獲得您想要的輸出。

1

什麼像這樣

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

如果你想更進一步,融化這個數據再次可以使用熔融包裹

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