当数据散布在同一列中的组头时,如何对数据进行分组?

时间:2016-10-30 23:40:39

标签: r data.table

基本上,我的数据按天划分,其间的行数不一致:

16-Oct-16
Name1
Name2
Name3
17-Oct-16
Name1
Name2
Name3
Name4
Name5
19-Oct-16

我需要能够获取组数据并将其应用于子记录。 预期结果应如下所示:

Name1   16-Oct-16
Name2   16-Oct-16
Name3   16-Oct-16
Name1   17-Oct-16
Name2   17-Oct-16
Name3   17-Oct-16
Name4   17-Oct-16
Name5   17-Oct-16

我正在使用data.table,但目前除了循环之外我无法想到任何其他方式。

以下脚本生成我正在查看的数据集类型:

data.table(c('October 16, 2016', paste0('Name',1:4),
             'October 17, 2016', paste0('Name',1:12),
             'October 20, 2016', paste0('Name',1:2),
             'October 25, 2016', paste0('Name',1:6)))

我只想将相应的日期字段复制到每个名称行,最后得到一个整洁的数据集,其中每一行都有名称和日期。

2 个答案:

答案 0 :(得分:1)

我在类似情况下使用了data.table解决方案。 (我已使用data.table版本1.9.7进行了测试。但它也适用于CRAN版本1.9.6)

读取数据

library(data.table)

dt <- fread("16-Oct-16
            Name1
            Name2
            Name3
            17-Oct-16
            Name1
            Name2
            Name3
            Name4
            Name5
            19-Oct-16",
            header = FALSE)
print(dt)
           V1
 1: 16-Oct-16
 2:     Name1
 3:     Name2
 4:     Name3
 5: 17-Oct-16
 6:     Name1
 7:     Name2
 8:     Name3
 9:     Name4
10:     Name5
11: 19-Oct-16

最后的观察结果

组标题是日期。所以我使用了dmy包的lubridate函数来尽可能强制它们使用日期格式。对于未格式化为日期dmy创建NA的行。使用包na.locf中的zoo,可以继续进行最后一次非NA观察。两种操作都可以组合成一行:

dt[, day := zoo::na.locf(lubridate::dmy(V1))]
print(dt)
           V1        day
 1: 16-Oct-16 2016-10-16
 2:     Name1 2016-10-16
 3:     Name2 2016-10-16
 4:     Name3 2016-10-16
 5: 17-Oct-16 2016-10-17
 6:     Name1 2016-10-17
 7:     Name2 2016-10-17
 8:     Name3 2016-10-17
 9:     Name4 2016-10-17
10:     Name5 2016-10-17
11: 19-Oct-16 2016-10-19

(我想有一个更快的版本使用滚动连接而不是na.locf。)

删除组标题行

要删除组标题,我们需要保留一个临时列。

dt[, tmp := lubridate::dmy(V1)][, day := zoo::na.locf(tmp)]
print(dt)
           V1        tmp        day
 1: 16-Oct-16 2016-10-16 2016-10-16
 2:     Name1       <NA> 2016-10-16
 3:     Name2       <NA> 2016-10-16
 4:     Name3       <NA> 2016-10-16
 5: 17-Oct-16 2016-10-17 2016-10-17
 6:     Name1       <NA> 2016-10-17
 7:     Name2       <NA> 2016-10-17
 8:     Name3       <NA> 2016-10-17
 9:     Name4       <NA> 2016-10-17
10:     Name5       <NA> 2016-10-17
11: 19-Oct-16 2016-10-19 2016-10-19

dt <- dt[is.na(tmp)]
print(dt)
      V1  tmp        day
1: Name1 <NA> 2016-10-16
2: Name2 <NA> 2016-10-16
3: Name3 <NA> 2016-10-16
4: Name1 <NA> 2016-10-17
5: Name2 <NA> 2016-10-17
6: Name3 <NA> 2016-10-17
7: Name4 <NA> 2016-10-17
8: Name5 <NA> 2016-10-17

dt[, tmp := NULL]
print(dt)
      V1        day
1: Name1 2016-10-16
2: Name2 2016-10-16
3: Name3 2016-10-16
4: Name1 2016-10-17
5: Name2 2016-10-17
6: Name3 2016-10-17
7: Name4 2016-10-17
8: Name5 2016-10-17

答案 1 :(得分:1)

另一种选择是使用正则表达式模式。对于第一个示例数据集:

library(data.table)
library(zoo)
dt1[grep('([0-9]{1,2})-([A-Za-z]+)-(\\d{2})', V1), V2 := V1
    ][, V2 := na.locf(V2)][V1!=V2]

给出:

      V1        V2
1: Name1 16-Oct-16
2: Name2 16-Oct-16
3: Name3 16-Oct-16
4: Name1 17-Oct-16
5: Name2 17-Oct-16
6: Name3 17-Oct-16
7: Name4 17-Oct-16
8: Name5 17-Oct-16

对于第二个数据集,您可以使用:

dt2[grep('([A-Za-z]+ )([0-9]{1,2}[,] )(\\d{4})', V1), V2 := V1
    ][, V2 := na.locf(V2)][V1!=V2]

给出:

        V1               V2
 1:  Name1 October 16, 2016
 2:  Name2 October 16, 2016
 3:  Name3 October 16, 2016
 4:  Name4 October 16, 2016
 5:  Name1 October 17, 2016
 6:  Name2 October 17, 2016
 7:  Name3 October 17, 2016
 8:  Name4 October 17, 2016
 9:  Name5 October 17, 2016
10:  Name6 October 17, 2016
11:  Name7 October 17, 2016
12:  Name8 October 17, 2016
13:  Name9 October 17, 2016
14: Name10 October 17, 2016
15: Name11 October 17, 2016
16: Name12 October 17, 2016
17:  Name1 October 20, 2016
18:  Name2 October 20, 2016
19:  Name1 October 25, 2016
20:  Name2 October 25, 2016
21:  Name3 October 25, 2016
22:  Name4 October 25, 2016
23:  Name5 October 25, 2016
24:  Name6 October 25, 2016

使用过的数据:

dt1 <- fread("16-Oct-16
             Name1
             Name2
             Name3
             17-Oct-16
             Name1
             Name2
             Name3
             Name4
             Name5
             19-Oct-16", header = FALSE)

dt2 <- data.table(c('October 16, 2016', paste0('Name',1:4),
                    'October 17, 2016', paste0('Name',1:12),
                    'October 20, 2016', paste0('Name',1:2),
                    'October 25, 2016', paste0('Name',1:6)))