R 如何使用“重新塑造数据帧”;再次发生;柱?

R 如何使用“重新塑造数据帧”;再次发生;柱?,r,reshape,melt,reshape2,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 cit

我不熟悉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
基本上,数据包括“重现柱”中不同地点每小时观察和模拟污染物浓度的时间序列,即地点-obs-mod(在示例中,我仅显示了总共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
我认为我应该使用包“重塑2”来实现这一点。首先,我尝试熔化数据集,然后dcast数据集:

test.melt <- melt(test.data, id.vars = "date", measure.vars = c("site", "obs", "mod"))
然后我试着重铸:

test.recast <- recast(test.data, date ~ site + obs + mod)
我试图搜索以前的问题,但没有发现类似的情况(如果我错了,请纠正我)。有人能帮我吗


非常感谢

您经常使用列名这一事实有点奇怪,而且不是正常的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
请注意,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

此时,如果您想将
x
x.1
视为同一个变量,我认为可以使用一点
gsub()
或其他正则表达式函数来消除不符合规则的字符。这是一个我经常使用的工作流。

在完成一些变量名清理后,您最好使用base R restrape

这是你的数据

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
  • 可选步骤:此表单中的数据仍然不是完全“长”。如果需要,只需多做一步:

    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
    
  • 更新(尝试解决评论中的一些问题)
  • reformate()
    文档非常混乱。最好通过几个例子来了解它是如何工作的。具体来说,“时间”不一定指时间(“问题中的日期”),而是更多地指面板数据,即在不同时间为同一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
    
    如果您停留在“选项1”或“选项2”上,就不容易获得这种灵活性


  • 更新(几年后) “data.table”中的
    melt
    现在可以以类似于
    重塑
    的方式“熔化”多个列。无论列名是否重复,它都应该起作用

    您可以尝试以下操作:

    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
    

    measure这是我最初的想法,但我认为两者的比较并不完全相同。我认为在修复重复的列名之后,这里实际上需要一个简单的
    重塑()
    (base R)。(.)感谢您指出,在这种情况下,列名不应相同(或重复出现)。抱歉,我没有解释清楚-原始列是按顺序命名的,但我将名称更改为此形式,认为这可能有助于对同一变量的所有值进行分组。。。还有一个问题:在您的示例中,测量的变量都是“独立的”(每列1个),但在我的示例中,每个记录由3列组成(站点obs mod)。考虑到列名可能不同,是否有可能直接将数据从原始数据重塑为我想要的形式?谢谢@elarry,我试着回答这个问题以及你在我的最新答案中提出的其他问题。我希望这能有所帮助。您实际希望输出的格式是什么?您给出的第一个示例输出显示了半宽格式。在
    重塑2
    语言中,它不是完全“融化”的。请参阅我更新的两个选项的答案。非常感谢您提供的详细解释和解决方案-我尝试了
    选项1
    ,它确实产生了我想要的输出格式!我可以再问两个问题吗?1.我参考了
    reformate()
    的帮助文件,但被参数
    idvar
    timevar
    的定义弄糊涂了。您能解释一下为什么在选项1中指定了它们吗?2.我认为在
    test2
    中没有名为
    “site”
    的专栏,但
    restrape()
    确实有效。为什么?非常感谢您花了这么大的力气为我解释清楚-这比官方的
    reforme()
    文档帮助我理解它的用法要好得多。忘了
    test2
    ——我想这是我在没有刷新页面的情况下看到的您之前的一个回复
    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
    
    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
    
    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
    
    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
    
    dcast(test.melt, date + site ~ variable)
    dcast(test.melt, date ~ variable + site)
    dcast(test.melt, variable + site ~ date)
    dcast(test.melt, variable + date ~ site)
    
    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