data.table:通过选择性地省略行

时间:2017-11-18 20:00:33

标签: r data.table

在一个包含数百万行信息的项目中,我们希望每个案例每年都有一行在研究中,我们发现了一个数据输入错误,因此有些情况会出现额外行的错误,而某些变量会有所不同。 (也就是说,uniqueduplicated无法解决这些问题。)在手动检查了其中的许多内容后,我们了解问题以及结果应该如何。但我需要你的帮助才能使data.table做正确的事。

我做了一个小测试用例。重现数据的代码如下。

> DT
    year case status
 1: 1980    a   born
 2: 1980    a  alive
 3: 1981    a  alive
 4: 1982    a  alive
 5: 1999    b  alive
 6: 1999    b  alive
 7: 2000    b  alive
 8: 2004    c  alive
 9: 2005    c  alive
10: 1977    d  alive
11: 1977    d   dead
12: 1983    e  alive
13: 1984    e   born
14: 1984    e  alive
15: 1985    e  alive
16: 1986    e  alive
17: 2000    f  alive
18: 2001    f  alive
19: 2002    f  alive
20: 2002    f   dead
21: 2003    f  alive
    year case status

修复问题

  1. 案例" a" 1980年有2行。因为那是第一个记录 对于那种情况,我们希望保留一个说出“#34; born"和 删除一个" alive"。案例" b" 1999年有2行,但是 我们没有"出生"在任何一个。我们想保持公正 一个"活着"行。

  2. 案例" e"有一个错误的"天生"在1984年。因为它是#34;活着" 1983年,1984年出生的#34;应该删除。

  3. 案例" f"有一个错误的"死了"在2002年。因为它显示 as" alive"在2003年,我们相信"死了"是一个错误。所以删除 一个说"死",但只是因为下一次有了 "活着"。

  4. 案例" d"在1977年有2行,但我们想保留两行

    我一直在寻找一种隔离行组的好方法。对于每种情况,我想标记第一年的行,然后计算要做什么。似乎用.GRP命名成长组会给出一些清晰度,但我仍然存在隔离每个案例的第一行组的问题。

    library(data.table)
    DT <- data.table(year = c(1980, 1980, 1981, 1982, 1999, 1999, 2000,
                              2004, 2005, 1977, 1977, 1983, 1984, 1984,
                              1985, 1986, 2000, 2001, 2002, 2002, 2003),
                     case = c("a", "a",  "a", "a",   "b",  "b", "b", "c",
                               "c", "d", "d", "e",  "e", "e", "e", "e",
                               "f", "f", "f", "f", "f"),
                     status = c("born", "alive", "alive", "alive", "alive",
                                "alive", "alive", "alive", "alive", "alive",
                                "dead", "alive", "born", "alive", "alive", "alive",
                                "alive", "alive", "alive", "dead", "alive"))
    
    ## re-order the rows, just in case
    DT <- DT[order(case, year, status)]
    ## A correct answer would be:
    DT[-c(1, 5, 14, 20)]
    
    ## Here is my effort to fix problem 1.
    setkey(DT, case, year)
    
    ## create a bunch of index variables, naive way to
    ## find first year with multiple rows
    DT[ , idx:=1:.N, by = list(case, year)]
    ## number of rows with case,year 
    DT[ , count := uniqueN(status), by = list(case, year)]
    DT[ , caseyr := 1:.N, by = list(case)]
    DT[ , casegrp := .GRP, by = list(case, year)]
    

    我认为这会隔离每个案例的第一个块,但是失败了。注意它拿起案例&#34; e&#34;

     > DT[count > 1 & 1 %in% idx & 1 %in% caseyr, .SD, by = list(case) ]
        case year status idx count caseyr casegrp
     1:    a 1980   born   1     2      1       1
     2:    a 1980  alive   2     2      2       1
     3:    b 1999  alive   1     2      1       4
     4:    b 1999  alive   2     2      2       4
     5:    d 1977  alive   1     2      1       8
     6:    d 1977   dead   2     2      2       8
     7:    e 1984   born   1     2      2      10
     8:    e 1984  alive   2     2      3      10
     9:    f 2002  alive   1     2      3      15
    10:    f 2002   dead   2     2      4      15
    

2 个答案:

答案 0 :(得分:1)

这是一个解决方案:

library(data.table)
DT <- data.table(year = c(1980, 1980, 1981, 1982, 1999, 1999, 2000,
                          2004, 2005, 1977, 1977, 1983, 1984, 1984,
                          1985, 1986, 2000, 2001, 2002, 2002, 2003),
                 case = c("a", "a",  "a", "a",   "b",  "b", "b", "c",
                          "c", "d", "d", "e",  "e", "e", "e", "e",
                          "f", "f", "f", "f", "f"),
                 status = c("born", "alive", "alive", "alive", "alive",
                            "alive", "alive", "alive", "alive", "alive",
                            "dead", "alive", "born", "alive", "alive", "alive",
                            "alive", "alive", "alive", "dead", "alive"))
#to check the ids removed are 1,5,14,20
setkey(DT,case, year, status)
DT[, id := 1:.N]
DT <- DT[order(case, year, status, -id)]

#remove duplicated alive (or other)
DT <- DT[!duplicated(DT[, list(case, year, status)])]

#compute year ordering
DT[, status_rank := rank(year), by = list(case)]

#remove late born
DT[, is_first := status_rank == min(status_rank), by = case]
DT <- DT[status != "born" | is_first]

#remove early dead
DT[, is_last := status_rank == max(status_rank), by = case]
DT <- DT[status != "dead" | is_last]

#remove redundant alive unless it's with dead
DT[, keep_alive := paste(sort(unique(status)), collapse = "") %in% c("alive", "alivedead") , by = list(case, year)]
DT <- DT[status != "alive" | keep_alive]
DT[, c("status_rank", "is_first", "is_last", "keep_alive") := NULL]
DT
    year case status id
 1: 1980    a   born  2
 2: 1981    a  alive  3
 3: 1982    a  alive  4
 4: 1999    b  alive  6
 5: 2000    b  alive  7
 6: 2004    c  alive  8
 7: 2005    c  alive  9
 8: 1977    d  alive 10
 9: 1977    d   dead 11
10: 1983    e  alive 12
11: 1984    e  alive 13
12: 1985    e  alive 15
13: 1986    e  alive 16
14: 2000    f  alive 17
15: 2001    f  alive 18
16: 2002    f  alive 19
17: 2003    f  alive 21

答案 1 :(得分:1)

这是另一种解决方案。基本上,我们专注于问题年份(每个案例的计数,年份> 1)并根据您的指定过滤。

## re-order the rows, just in case
DT <- DT[order(case, year, status)]
DT <- unique(DT) #fix case b 1999

#create indicator more than one data per year
DT[,count_born_alive:=sum(status=="born",status=="alive"),by=.(case,year)]
DT[,count_alive_dead:=sum(status=="alive",status=="dead"),by=.(case,year)]

#cumsum alive
DT[,alive_sum:=cumsum(status=="alive"),by=case]

#filter problem rows
DT <-DT[DT[, .I[!(count_born_alive>1&status=="alive"&alive_sum==1)], by = case]$V1] #Case "a" has 2 rows for 1980
DT <-DT[DT[, .I[!(count_born_alive>1&status=="born"&alive_sum>1)], by = case]$V1] #Case "f" has an erroneous "dead" in 2002. Because it shows as "alive" in 2003
DT <-DT[DT[, .I[!(count_alive_dead>1&status=="dead"&alive_sum<max(alive_sum))], by = case]$V1] #fix Case "f" has an erroneous "dead" in 2002

DT[,.(year,case,status)]
    year case status
 1: 1980    a   born
 2: 1981    a  alive
 3: 1982    a  alive
 4: 1999    b  alive
 5: 2000    b  alive
 6: 2004    c  alive
 7: 2005    c  alive
 8: 1977    d  alive
 9: 1977    d   dead
10: 1983    e  alive
11: 1984    e  alive
12: 1985    e  alive
13: 1986    e  alive
14: 2000    f  alive
15: 2001    f  alive
16: 2002    f  alive
17: 2003    f  alive