在r中的数据表中按组累计识别新值
如何创建一个新列,该列通过在r中的数据表中按组累计识别新值,r,dataframe,dplyr,data.table,tidyverse,R,Dataframe,Dplyr,Data.table,Tidyverse,如何创建一个新列,该列通过年+月的一组独特梳子来累计标识字母列中的新值外观 数据样本 require(data.table) dt <- data.table(Letter = c(LETTERS[c(5, 1:2, 1:2, 1:4, 3:6)]), Year = 2018, Month = c(rep(5,5), rep(6,4), rep(7,4))) 我试图得到的结果是: Letter Year Mont
年
+月
的一组独特梳子来累计标识字母
列中的新值外观
数据样本
require(data.table)
dt <- data.table(Letter = c(LETTERS[c(5, 1:2, 1:2, 1:4, 3:6)]),
Year = 2018,
Month = c(rep(5,5), rep(6,4), rep(7,4)))
我试图得到的结果是:
Letter Year Month New
1: E 2018 5 TRUE
2: A 2018 5 TRUE
3: B 2018 5 TRUE
4: A 2018 5 TRUE
5: B 2018 5 TRUE
6: A 2018 6 FALSE
7: B 2018 6 FALSE
8: C 2018 6 TRUE
9: D 2018 6 TRUE
10: C 2018 7 FALSE
11: D 2018 7 FALSE
12: E 2018 7 FALSE
13: F 2018 7 TRUE
详细问题:
# dt[,new := ifelse(Letter %in% dt$Letter[dt$Month<Month],F,T), by="Month"][]
# Letter Year Month new
#1: E 2018 5 TRUE
#2: A 2018 5 TRUE
#3: B 2018 5 TRUE
#4: A 2018 5 TRUE
#5: B 2018 5 TRUE
#6: A 2018 6 FALSE
#7: B 2018 6 FALSE
#8: C 2018 6 TRUE
#9: D 2018 6 TRUE
#10: C 2018 7 FALSE
#11: D 2018 7 FALSE
#12: E 2018 7 FALSE
#13: F 2018 7 TRUE
#dt[,new:=ifelse(字母%in%dt$字母[dt$月另一种可能的方法:
dupes <- c()
dt[, New := {
x <- !Letter %chin% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
如果字母是字符:
microbenchmark(mtd0=dt0[, New := !(Letter %chin% dt0$Letter[dt0$Month<Month]), by=Month],
mtd1={
dt1[, v := FALSE]
dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
},
mtd2={
dupes <- c()
dt2[, New := {
x <- !Letter %chin% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
},
times=3L)
检查:
> identical(dt2$New, dt1$v)
[1] TRUE
> identical(dt0$New, dt1$v)
[1] FALSE
数据:
set.seed(0L)
nr初始化为FALSE;然后用每个字母连接到第一年的月份,并更新为TRUE:
dt[, v := FALSE]
dt[unique(dt, by="Letter"), on=.(Letter, Year, Month), v := TRUE][]
Letter Year Month v
1: E 2018 5 TRUE
2: A 2018 5 TRUE
3: B 2018 5 TRUE
4: A 2018 5 TRUE
5: B 2018 5 TRUE
6: A 2018 6 FALSE
7: B 2018 6 FALSE
8: C 2018 6 TRUE
9: D 2018 6 TRUE
10: C 2018 7 FALSE
11: D 2018 7 FALSE
12: E 2018 7 FALSE
13: F 2018 7 TRUE
@Andre这是一个简单而伟大的答案!谢谢你!@David谢谢你的添加。如果有多个年份,仅按月份分组和测试不平等性是不够的,对吗?你可以创建一个新的YearMonth:=粘贴(年,月)变量并使用它。我不知道不同年份的逻辑是什么。我宁愿按年份分割。使用我的代码和rbind。@Andre顺便说一句,用数据替换%
中的%in%
。表的本机%chin%
使它更加有效。仅供参考,您的DUPS对象在DT之外[…]没有被修改。这不是一个问题,但是一些可能感兴趣的替代方案:让它只存在于DT[…]中,比如DT[,New:={if(.GRP==1L)谢谢你,弗兰克。是的,如果需要unique
set,那么可以使用@chinsoon12谢谢!非常好的方法!特别是在字符串的效率方面。
Unit: milliseconds
expr min lq mean median uq max neval
mtd0 1293.3100 1318.775 1331.7129 1344.2398 1350.9143 1357.589 3
mtd1 377.1534 391.178 402.4423 405.2026 415.0868 424.971 3
mtd2 2015.2115 2020.926 2023.7209 2026.6400 2027.9756 2029.311 3
microbenchmark(mtd0=dt0[, New := !(Letter %chin% dt0$Letter[dt0$Month<Month]), by=Month],
mtd1={
dt1[, v := FALSE]
dt1[unique(dt1, by="Letter"), on=.(Letter, Year, Month), v := TRUE]
},
mtd2={
dupes <- c()
dt2[, New := {
x <- !Letter %chin% dupes
dupes <- c(dupes, unique(Letter[x]))
x
}, by=.(Year, Month)]
},
times=3L)
Unit: milliseconds
expr min lq mean median uq max neval
mtd0 1658.5806 1689.8941 1765.9329 1721.2076 1819.6090 1918.0105 3
mtd1 849.2361 851.1807 852.8632 853.1253 854.6768 856.2283 3
mtd2 420.1013 426.0941 433.9202 432.0869 440.8296 449.5723 3
> identical(dt2$New, dt1$v)
[1] TRUE
> identical(dt0$New, dt1$v)
[1] FALSE
set.seed(0L)
nr <- 1e7
dt <- unique(data.table(Letter=sample(nr/1e2, nr, replace=TRUE),
Year=sample(2014:2018, nr, replace=TRUE),
Month=sample(1:12, nr, replace=TRUE)))
setorder(dt, Year, Month)#[, Letter := as.character(Letter)]
dt0 <- copy(dt)
dt1 <- copy(dt)
dt2 <- copy(dt)
#for seed=0L, dt has about 4.8mio rows
dt[, v := FALSE]
dt[unique(dt, by="Letter"), on=.(Letter, Year, Month), v := TRUE][]
Letter Year Month v
1: E 2018 5 TRUE
2: A 2018 5 TRUE
3: B 2018 5 TRUE
4: A 2018 5 TRUE
5: B 2018 5 TRUE
6: A 2018 6 FALSE
7: B 2018 6 FALSE
8: C 2018 6 TRUE
9: D 2018 6 TRUE
10: C 2018 7 FALSE
11: D 2018 7 FALSE
12: E 2018 7 FALSE
13: F 2018 7 TRUE