我有一个广泛的调查数据集。对于特定问题,在原始数据中创建了一组变量,以表示在特定月份询问调查问题的事实。
我希望创建一组具有月不变名称的新变量;这些变量的值将对应于所观察月份的月变量问题的值。
请参阅示例/虚构数据集:
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)))
我希望重复“by = month”。
如果我使用“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方法的任何帮助都将非常感激,因为我的数据很大。谢谢。
答案 0 :(得分: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的解决方案融化为长格式应该更快。
答案 1 :(得分: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.table
类似于melt
函数的plyr
1}}(在尝试上面的代码之前复制/粘贴下面显示的这个函数)。
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列每个月(然后拼接在一起)以获得所需的输出。
答案 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" ...