在R中与dplyr,tidyr,reshape2复合熔融

时间:2016-08-14 21:50:05

标签: r dplyr reshape2 tidyr

我想了解"融化"适用于复杂情况。我在很简单的情况下看过很多关于使用这些软件包的帖子和博客 - 但不是更困难的。例如:

假设我在数据框中有以下数据:

  CA UNIT      SCP    DATE1    TIME1   DESC1 ENTRIES1  EXITS1  
1 A002 R051 02-00-00 07-27-13 00:00:00 REGULAR  4209603 1443585
2 A002 R051 02-00-00 07-28-13 08:00:00 REGULAR  4210490 1443821
3 A002 R051 02-00-00 07-29-13 16:00:00 REGULAR  4211586 1444302
4 A002 R051 02-00-00 07-30-13 14:01:46   LOGON  4213192 1444700
5 A002 R051 02-00-00 07-30-13 16:00:00 REGULAR  4213333 1444737
6 A002 R051 02-00-00 08-01-13 00:00:00 REGULAR  4215894 1445274`

并继续向右列(抱歉,我无法在代码块中正确格式化):

     `DATE2    TIME2     DESC2 ENTRIES2  EXITS2
1   07-27-13 08:00:00   REGULAR  4209663 1443616 
2   07-28-13 16:00:00   REGULAR  4210775 1443921 
3   07-30-13 00:00:00   REGULAR  4212845 1444369 
4   07-30-13 14:02:18 DOOR OPEN  4213192 1444700 
5   07-31-13 00:00:00   REGULAR  4214345 1444823 
6   08-01-13 08:00:00   REGULAR  4215977 1445362`

我希望将其融入具有以下格式的数据框中:

  CA UNIT      SCP    DATE    TIME        DESC    ENTRIES  EXITS  
1 A002 R051 02-00-00 07-27-13 00:00:00   REGULAR  4209603 1443585
2 A002 R051 02-00-00 07-28-13 08:00:00   REGULAR  4210490 1443821
3 A002 R051 02-00-00 07-29-13 16:00:00   REGULAR  4211586 1444302
4 A002 R051 02-00-00 07-30-13 14:01:46     LOGON  4213192 1444700
5 A002 R051 02-00-00 07-30-13 16:00:00   REGULAR  4213333 1444737
6 A002 R051 02-00-00 08-01-13 00:00:00   REGULAR  4215894 1445274
7 A002 R051 02-00-00 07-27-13 08:00:00   REGULAR  4209663 1443616
8 A002 R051 02-00-00 07-28-13 16:00:00   REGULAR  4210775 1443921 
9 A002 R051 02-00-00 07-30-13 00:00:00   REGULAR  4212845 1444369
10A002 R051 02-00-00 07-30-13 14:02:18 DOOR OPEN  4213192 1444700
11A002 R051 02-00-00 07-31-13 00:00:00   REGULAR  4214345 1444823
12A002 R051 02-00-00 08-01-13 08:00:00   REGULAR  4215977 1445362

这里面临的挑战是我想要的专栏"融化"有不同的数据类型。我读到的所有帖子都非常简单,并且假设所有熔化的列都具有相同的数据类型,并且将属于漂亮的键/值对。这显然不是这种情况。

我找到了另一篇帖子,表明可以使用'替换'来完成重组。来自统计数据。我明白了。但是如果dplyr,reshape2和tidyr无法用于更复杂的真实场景,那么它的实际用途是什么?

请说明如何使用tidyr,dplyr或reshape2执行此操作。

提前谢谢!

4 个答案:

答案 0 :(得分:6)

如果您查看reshape默认分隔符为?reshape,并且.指定为{{1>,则来自R的sep选项然后它将使用正则表达式来分割适合您的情况的""列名称。如果您不需要,可以删除[A-Za-z][0-9]time变量:

id
reshape(df, varying = 4:13, dir = "long", sep = "")

答案 1 :(得分:3)

可能有一个很好的tidyr和/或data.table解决方案,但你也可以在基数R中执行以下操作来堆叠两个五列组:

names(dat) = gsub("1|2", "", names(dat))
rbind(dat[,1:8], dat[,c(1:3,9:13)])
     CA UNIT      SCP     DATE     TIME      DESC ENTRIES   EXITS
1  A002 R051 02-00-00 07-27-13 00:00:00   REGULAR 4209603 1443585
2  A002 R051 02-00-00 07-28-13 08:00:00   REGULAR 4210490 1443821
3  A002 R051 02-00-00 07-29-13 16:00:00   REGULAR 4211586 1444302
4  A002 R051 02-00-00 07-30-13 14:01:46     LOGON 4213192 1444700
5  A002 R051 02-00-00 07-30-13 16:00:00   REGULAR 4213333 1444737
6  A002 R051 02-00-00 08-01-13 00:00:00   REGULAR 4215894 1445274
7  A002 R051 02-00-00 07-27-13 08:00:00   REGULAR 4209663 1443616
8  A002 R051 02-00-00 07-28-13 16:00:00   REGULAR 4210775 1443921
9  A002 R051 02-00-00 07-30-13 00:00:00   REGULAR 4212845 1444369
10 A002 R051 02-00-00 07-30-13 14:02:18 DOOR_OPEN 4213192 1444700
11 A002 R051 02-00-00 07-31-13 00:00:00   REGULAR 4214345 1444823
12 A002 R051 02-00-00 08-01-13 08:00:00   REGULAR 4215977 1445362

在您的示例中,您只有两个需要堆叠的五列集。如果你有更多这样的群体,你可以做这样的事情,以避免大量的硬编码:

dat = lapply(seq(4,ncol(dat),5), function(i) {
  tmp = dat[, c(1:3, i:(i+4))]
  names(tmp) = gsub("[0-9]", "", names(tmp))
  tmp
})

dat = do.call(rbind, dat)

答案 2 :(得分:2)

我们可以使用melt中的data.table轻松完成此操作,因为它可能需要多个measure patterns

library(data.table)
melt(setDT(df), measure = patterns(c("DATE", "TIME", "DESC", "ENTRIES", 
       "EXITS")), value.name = c('DATE', 'TIME', 'DESC', 'ENTRIES', 
       'EXITS'))[, variable := NULL][]
#       CA UNIT      SCP     DATE     TIME      DESC ENTRIES   EXITS
#1: A002 R051 02-00-00 07-27-13 00:00:00   REGULAR 4209603 1443585
#2: A002 R051 02-00-00 07-28-13 08:00:00   REGULAR 4210490 1443821
#3: A002 R051 02-00-00 07-29-13 16:00:00   REGULAR 4211586 1444302
#4: A002 R051 02-00-00 07-30-13 14:01:46     LOGON 4213192 1444700
#5: A002 R051 02-00-00 07-30-13 16:00:00   REGULAR 4213333 1444737
#6: A002 R051 02-00-00 08-01-13 00:00:00   REGULAR 4215894 1445274
#7: A002 R051 02-00-00 07-27-13 08:00:00   REGULAR 4209663 1443616
#8: A002 R051 02-00-00 07-28-13 16:00:00   REGULAR 4210775 1443921
#9: A002 R051 02-00-00 07-30-13 00:00:00   REGULAR 4212845 1444369
#10:A002 R051 02-00-00 07-30-13 14:02:18 DOOR OPEN 4213192 1444700
#11:A002 R051 02-00-00 07-31-13 00:00:00   REGULAR 4214345 1444823
#12:A002 R051 02-00-00 08-01-13 08:00:00   REGULAR 4215977 1445362

答案 3 :(得分:1)

tidyr中,您需要gather加长,修改列名称,然后spread返回广泛。由于spread对索引非常挑剔,因此您需要添加一个唯一的ID列,dplyr::add_rownames可以很好地执行此操作:

library(tidyr)
library(dplyr)

df %>% add_rownames() %>% 
    # gather to long form
    gather(var, val, DATE1:EXITS2) %>% 
    # separate ID suffix from variable name by position
    separate(var, c('var', 'id'), sep = -2) %>% 
    # spread back to wide form
    spread(var, val, convert = TRUE) %>% 
    # clean up extra columns
    select(-rowname, -id)

## # A tibble: 12 x 8
##        CA   UNIT      SCP     DATE      DESC ENTRIES   EXITS     TIME
## *  <fctr> <fctr>   <fctr>    <chr>     <chr>   <int>   <int>    <chr>
## 1    A002   R051 02-00-00 07-27-13   REGULAR 4209603 1443585 00:00:00
## 2    A002   R051 02-00-00 07-27-13   REGULAR 4209663 1443616 08:00:00
## 3    A002   R051 02-00-00 07-28-13   REGULAR 4210490 1443821 08:00:00
## 4    A002   R051 02-00-00 07-28-13   REGULAR 4210775 1443921 16:00:00
## 5    A002   R051 02-00-00 07-29-13   REGULAR 4211586 1444302 16:00:00
## 6    A002   R051 02-00-00 07-30-13   REGULAR 4212845 1444369 00:00:00
## 7    A002   R051 02-00-00 07-30-13     LOGON 4213192 1444700 14:01:46
## 8    A002   R051 02-00-00 07-30-13 DOOR OPEN 4213192 1444700 14:02:18
## 9    A002   R051 02-00-00 07-30-13   REGULAR 4213333 1444737 16:00:00
## 10   A002   R051 02-00-00 07-31-13   REGULAR 4214345 1444823 00:00:00
## 11   A002   R051 02-00-00 08-01-13   REGULAR 4215894 1445274 00:00:00
## 12   A002   R051 02-00-00 08-01-13   REGULAR 4215977 1445362 08:00:00