2013-04-22 3 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.q1» наблюдается как «да» для любого наблюдения в «мае». Я бы хотел, чтобы новая переменная «Q1» представляла «may.q1», «jun.q1» и «jul.q1». Значение «Q1» будет принимать значение «may.q1», если месяц «может», а значение «Q1» примет значение «jun.q1», когда месяц «jun», ,

Если бы я, чтобы попытаться сделать это вручную, используя данные таблицы, я хотел бы что-то вроде:

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). И это может быть не самым эффективным, если имеется большое количество столбцов с несколькими нужными. В таком случае раствор Аруна, плавящийся в длинный формат, должен быть быстрее.

+0

Ого .. я вмятину думать об этом! здорово. – Arun

+0

MatthewDowle, это * определенно * быстрее, чем (мой) расплав + литье. Я попробовал его по более крупным данным. Мина не там, где близко ... Это займет 23 секунды на столбцах 1e5 * 100, тогда как это происходит менее чем за секунду! – Arun

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 небольшая функция (еще больше улучшений, которые будут сделаны) я писал meltdata.table аналогична функции melt в plyr (копировать/вставить эту функцию, показанную ниже, прежде чем попробовать код выше).

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.table с id.var = month колонкой с. Теперь все ваши имена расплавленных столбцов имеют форму month.question. Таким образом, удалив «.question» из этого расплавленного столбца и приравнивая столбец month, мы можем удалить все ненужные записи. Как только мы это сделали, нам не нужен «месяц». в расплавленной колонке «ind». Итак, мы используем gsub для удаления «месяца». чтобы сохранить только q1, q2 и т. д. После этого у нас есть reshape (или cast). Это делается путем группировки на month и расщепления колонки values на ind (который имеет либо q1, либо q2.Таким образом, вы получите 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" ... 
Смежные вопросы