在一个包含数百万行信息的项目中,我们希望每个案例每年都有一行在研究中,我们发现了一个数据输入错误,因此有些情况会出现额外行的错误,而某些变量会有所不同。 (也就是说,unique
或duplicated
无法解决这些问题。)在手动检查了其中的许多内容后,我们了解问题以及结果应该如何。但我需要你的帮助才能使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
修复问题
案例" a" 1980年有2行。因为那是第一个记录 对于那种情况,我们希望保留一个说出“#34; born"和 删除一个" alive"。案例" b" 1999年有2行,但是 我们没有"出生"在任何一个。我们想保持公正 一个"活着"行。
案例" e"有一个错误的"天生"在1984年。因为它是#34;活着" 1983年,1984年出生的#34;应该删除。
案例" f"有一个错误的"死了"在2002年。因为它显示 as" alive"在2003年,我们相信"死了"是一个错误。所以删除 一个说"死",但只是因为下一次有了 "活着"。
案例" 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
答案 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