ela*_*rry 6 r reshape melt reshape2
我是R的数据分析新手.我最近得到了一个预先格式化的环境观测模型数据集,其示例子集如下所示:
date site obs mod site obs mod
2000-09-01 00:00:00 campus NA 61.63 city centre 66 56.69
2000-09-01 01:00:00 campus 52 62.55 city centre NA 54.75
2000-09-01 02:00:00 campus 52 63.52 city centre 56 54.65
Run Code Online (Sandbox Code Playgroud)
基本上,数据包括每小时观察到的时间序列和在"重复列"中不同位置的污染物模型浓度,即站点 - 天然 - 模型(在示例中,我仅显示了总共75个站点中的2个).我将这个"宽"数据集作为数据框读取,并希望将其重塑为"较窄"格式,如下所示:
date site obs mod
2000-09-01 00:00:00 campus NA 61.63
2000-09-01 01:00:00 campus 52 62.55
2000-09-01 02:00:00 campus 52 63.52
2000-09-01 00:00:00 city centre 66 56.69
2000-09-01 01:00:00 city centre NA 54.75
2000-09-01 02:00:00 city centre 56 54.65
Run Code Online (Sandbox Code Playgroud)
我相信我应该使用"reshape2"包来做到这一点.首先,我尝试融化然后dcast数据集:
test.melt <- melt(test.data, id.vars = "date", measure.vars = c("site", "obs", "mod"))
Run Code Online (Sandbox Code Playgroud)
但是,它只返回了一半的数据,即第一个("校园")之后的网站("市中心")的记录全部被切断:
date variable value
2001-01-01 00:00:00 site campus
2001-01-01 01:00:00 site campus
2001-01-01 02:00:00 site campus
2001-01-01 00:00:00 obs NA
2001-01-01 01:00:00 obs 52
2001-01-01 02:00:00 obs 52
2001-01-01 00:00:00 mod 61.63
2001-01-01 01:00:00 mod 62.55
2001-01-01 02:00:00 mod 63.52
Run Code Online (Sandbox Code Playgroud)
然后我尝试重铸:
test.recast <- recast(test.data, date ~ site + obs + mod)
Run Code Online (Sandbox Code Playgroud)
但是,它返回错误消息:
Error in eval(expr, envir, enclos) : object 'site' not found
Run Code Online (Sandbox Code Playgroud)
我试图搜索以前的问题,但没有找到类似的情况(如果我错了,请纠正我).有人可以帮我这个吗?
提前谢谢了!
A5C*_*2T1 11
在进行一些变量名称清理后,最好使用基本R reshape.
这是你的数据.
test <- read.table(header = TRUE, stringsAsFactors=FALSE,
text = "date site obs mod site obs mod
'2000-09-01 00:00:00' campus NA 61.63 'city centre' 66 56.69
'2000-09-01 01:00:00' campus 52 62.55 'city centre' NA 54.75
'2000-09-01 02:00:00' campus 52 63.52 'city centre' 56 54.65")
test
# date site obs mod site.1 obs.1 mod.1
# 1 2000-09-01 00:00:00 campus NA 61.63 city centre 66 56.69
# 2 2000-09-01 01:00:00 campus 52 62.55 city centre NA 54.75
# 3 2000-09-01 02:00:00 campus 52 63.52 city centre 56 54.65
Run Code Online (Sandbox Code Playgroud)
如果你这样做的话,你应该得到我得到的名字:正如@chase 在他的回答中提到的那样,"反复出现的列名有点奇怪而且不是正常的R行为" - 所以我们必须解决这个问题.
注意:这两个选项都会生成一个"时间"变量,您可以继续前进和删除.您可能希望保留它,以防您想要重新变换为宽格式.
选项1:如果你有像我一样的名字(你应该有),解决方案很简单.对于第一个站点,只需在站点名称后加"0"并使用base R reshape:
names(test)[2:4] <- paste(names(test)[2:4], "0", sep=".")
test <- reshape(test, direction = "long",
idvar = "date", varying = 2:ncol(test))
rownames(test) <- NULL # reshape makes UGLY rownames
test
# date time site obs mod
# 1 2000-09-01 00:00:00 0 campus NA 61.63
# 2 2000-09-01 01:00:00 0 campus 52 62.55
# 3 2000-09-01 02:00:00 0 campus 52 63.52
# 4 2000-09-01 00:00:00 1 city centre 66 56.69
# 5 2000-09-01 01:00:00 1 city centre NA 54.75
# 6 2000-09-01 02:00:00 1 city centre 56 54.65
Run Code Online (Sandbox Code Playgroud)选项2:如果您确实拥有重复的列名称,则修复仍然很容易,并遵循相同的逻辑.首先,创建更好的列名称(易于使用rep()),然后reshape()如上所述使用.
names(test)[-1] <- paste(names(test)[-1],
rep(1:((ncol(test)-1)/3), each = 3), sep = ".")
test <- reshape(test, direction = "long",
idvar = "date", varying = 2:ncol(test))
rownames(test) <- NULL
### Or, more convenient:
# names(test) <- make.unique(names(test))
# names(test)[2:4] <- paste(names(test)[2:4], "0", sep=".")
# test <- reshape(test, direction = "long",
# idvar = "date", varying = 2:ncol(test))
# rownames(test) <- NULL
Run Code Online (Sandbox Code Playgroud)可选步骤:此表单中的数据仍然不完全"长".如果这是必需的,那么所需要的只是一步:
require(reshape2)
melt(test, id.vars = c("date", "site", "time"))
# date site time variable value
# 1 2000-09-01 00:00:00 campus 0 obs NA
# 2 2000-09-01 01:00:00 campus 0 obs 52.00
# 3 2000-09-01 02:00:00 campus 0 obs 52.00
# 4 2000-09-01 00:00:00 city centre 1 obs 66.00
# 5 2000-09-01 01:00:00 city centre 1 obs NA
# 6 2000-09-01 02:00:00 city centre 1 obs 56.00
# 7 2000-09-01 00:00:00 campus 0 mod 61.63
# 8 2000-09-01 01:00:00 campus 0 mod 62.55
# 9 2000-09-01 02:00:00 campus 0 mod 63.52
# 10 2000-09-01 00:00:00 city centre 1 mod 56.69
# 11 2000-09-01 01:00:00 city centre 1 mod 54.75
# 12 2000-09-01 02:00:00 city centre 1 mod 54.65
Run Code Online (Sandbox Code Playgroud)该reshape()文档是相当混乱.最好通过几个例子来了解它是如何工作的.具体来说,"时间"不必是指时间(问题中的"日期"),而是更多地用于面板数据,其中记录是在不同时间为相同ID收集的.在您的情况下,原始数据中唯一的"id"是"日期"列.另一个潜在的"id"是网站,但不是数据的组织方式.
想象一下,如果你的数据看起来像这样:
test1 <- structure(list(date = structure(1:3,
.Label = c("2000-09-01 00:00:00",
"2000-09-01 01:00:00", "2000-09-01 02:00:00"), class = "factor"),
obs.campus = c(NA, 52L, 52L), mod.campus = c(61.63, 62.55,
63.52), obs.cityCentre = c(66L, NA, 56L), mod.cityCentre = c(56.69,
54.75, 54.65)), .Names = c("date", "obs.campus", "mod.campus",
"obs.cityCentre", "mod.cityCentre"), class = "data.frame", row.names = c(NA,
-3L))
test1
# date obs.campus mod.campus obs.cityCentre mod.cityCentre
# 1 2000-09-01 00:00:00 NA 61.63 66 56.69
# 2 2000-09-01 01:00:00 52 62.55 NA 54.75
# 3 2000-09-01 02:00:00 52 63.52 56 54.65
Run Code Online (Sandbox Code Playgroud)
现在试试reshape(test1, direction = "long", idvar = "date", varying = 2:ncol(test1)).您将看到reshape()将站点名称视为"时间"(可以通过向命令添加" timevar = "site""来覆盖该站点名称reshape).
何时direction = "long",您必须指定哪些列随"时间"而变化.在你的情况下,这是除了第一列之外的所有列,因此我使用2:ncol(test)了" varying".
test2?哪里是?
@ Chase回答的问题:我认为你误解了melt()应该如何运作.基本上,它试图让你获得"最瘦的"数据形式.在这种情况下,最外面的形式将是上面描述的"可选步骤",因为date+ site将是构成唯一ID变量所需的最小值.(我会说" time"可以安全地丢弃.)
一旦您的数据采用"可选步骤"中描述的格式(我们假设输出已存储为" test.melt"),您可以随时轻松地以不同方式旋转表格.作为我的意思的演示,尝试以下内容,看看他们做了什么.
dcast(test.melt, date + site ~ variable)
dcast(test.melt, date ~ variable + site)
dcast(test.melt, variable + site ~ date)
dcast(test.melt, variable + date ~ site)
Run Code Online (Sandbox Code Playgroud)
如果您停在"选项1"或"选项2",那么拥有这种灵活性并不容易.
melt来自"data.table"现在可以以类似的方式"融化"多个列reshape.无论列名是否重复,它都应该有效.
您可以尝试以下方法:
measure <- c("site", "obs", "mod")
melt(as.data.table(test), measure.vars = patterns(measure), value.name = measure)
# date variable site obs mod
# 1: 2000-09-01 00:00:00 1 campus NA 61.63
# 2: 2000-09-01 01:00:00 1 campus 52 62.55
# 3: 2000-09-01 02:00:00 1 campus 52 63.52
# 4: 2000-09-01 00:00:00 2 city centre 66 56.69
# 5: 2000-09-01 01:00:00 2 city centre NA 54.75
# 6: 2000-09-01 02:00:00 2 city centre 56 54.65
Run Code Online (Sandbox Code Playgroud)
您有重复列名称的事实有点奇怪,并不是正常的R行为.大多数情况下,R强制您通过该make.names()功能获得有效名称.无论如何,我能够复制你的问题.注意我做了我自己的例子,因为你的例子不可复制,但逻辑是一样的.
#Do not force unique names
s <- data.frame(id = 1:3, x = runif(3), x = runif(3), check.names = FALSE)
#-----
id x x
1 1 0.6845270 0.5218344
2 2 0.7662200 0.6179444
3 3 0.4110043 0.1104774
#Now try to melt, note that 1/2 of your x-values are missing!
melt(s, id.vars = 1)
#-----
id variable value
1 1 x 0.6845270
2 2 x 0.7662200
3 3 x 0.4110043
Run Code Online (Sandbox Code Playgroud)
解决方案是使列名称唯一.正如我之前所说,在大多数情况下,R默认执行此操作.但是,您可以在事后通过make.unique()
names(s) <- make.unique(names(s))
#-----
[1] "id" "x" "x.1"
Run Code Online (Sandbox Code Playgroud)
请注意,x的第二列现在附加了1.现在melt()可以按照您的期望工作:
melt(s, id.vars = 1)
#-----
id variable value
1 1 x 0.6845270
2 2 x 0.7662200
3 3 x 0.4110043
4 1 x.1 0.5218344
5 2 x.1 0.6179444
6 3 x.1 0.1104774
Run Code Online (Sandbox Code Playgroud)
在这一点上,如果你想对待x和x.1作为相同的变量,我认为一点gsub()或其他正则表达式函数来摆脱有问题的字符.这是我经常使用的工作流程.