[英]R dplyr to data table - Group and Filter
我试图将我的数据操作代码从dplyr
data.table
为dplyr
以data.table
速度。 我几乎在那里,但错过了最后一步。
我有一些示例数据来复制我的问题。
c_dt = data.table(u_id=rep(c("u1", "u2"),each=5),
p_id=c("p1", "p1", "p1", "p2","p2", "p1", "p2", "p2", "p2", "p2" ),
c_dt=c("2015-12-01", "2015-12-02", "2015-12-03", "2015-12-02",
"2015-12-05", "2015-12-02", "2015-12-03", "2015-12-04",
"2015-12-05", "2015-12-06"))
我想识别u_id
和p_id
重复的行; 并且只保留具有最小c_dt
的行(基本上保留第一个实例)。 我使用以下dplyr
代码:
c_df <- as.data.frame(c_dt)
cdedup_df <- c_df %>% group_by(p_id, u_id) %>% filter(c_dt == min(c_dt))
其中给出了以下输出
> cdedup_df
Source: local data frame [4 x 3]
Groups: p_id, u_id
u_id p_id c_dt
1 u1 p1 2015-12-01
2 u1 p2 2015-12-02
3 u2 p1 2015-12-02
4 u2 p2 2015-12-03
我有以下data.table
代码,正确识别所需的行,但我无法弄清楚如何只是过滤和行原样。
cdedup_dt <- c_dt[,c_dt == min(c_dt),by = list(u_id, p_id)]
cdedup_dt
u_id p_id V1
1: u1 p1 TRUE
2: u1 p1 FALSE
3: u1 p1 FALSE
4: u1 p2 TRUE
5: u1 p2 FALSE
6: u2 p1 TRUE
7: u2 p2 TRUE
8: u2 p2 FALSE
9: u2 p2 FALSE
10: u2 p2 FALSE
像这样的东西应该做的伎俩:
c_dt[, list(c_dt=min(c_dt)), by=list(u_id, p_id)]
## u_id p_id c_dt
## 1: u1 p1 2015-12-01
## 2: u1 p2 2015-12-02
## 3: u2 p1 2015-12-02
## 4: u2 p2 2015-12-03
在我的方法下面。 我希望它可以更好地扩展到大数据集,因为没有min
by group
,只有单一排序data.table非常有效,然后首先按组子集。
setorderv(c_dt, "c_dt")[, .SD[1L], .(u_id, p_id)]
# in data.table 1.9.7+ you can also use `head`
setorderv(c_dt, "c_dt")[, head(.SD, 1L), .(u_id, p_id)]
下面的代码包括当前其他答案的验证。
如果OP将提供大数据集,我可以添加基准。
library(data.table)
c_dt = data.table(u_id=rep(c("u1", "u2"),each=5), p_id=c("p1", "p1", "p1", "p2","p2", "p1", "p2", "p2", "p2", "p2" ), c_dt=c("2015-12-01", "2015-12-02", "2015-12-03", "2015-12-02", "2015-12-05", "2015-12-02", "2015-12-03", "2015-12-04", "2015-12-05", "2015-12-06"))
zero = c_dt[, list(c_dt=min(c_dt)), by=list(u_id, p_id)]
ananda = c_dt[, list(c_dt = c_dt[c_dt == min(c_dt)]), by = .(u_id, p_id)]
tal = c_dt[, .SD[rank(c_dt, ties.method = c("first")) == 1],by = .(u_id, p_id)]
all.equal(zero, ananda)
#[1] TRUE
all.equal(ananda, tal)
#[1] TRUE
jan = setorderv(c_dt, "c_dt")[, .SD[1L], .(u_id, p_id)]
all.equal(tal, jan)
#[1] TRUE
所以你确实很亲密。 你所缺少的就是在j栏中传递.SD
。 让我们看看它是如何工作的:
library(data.table)
c_dt = data.table(u_id=rep(c("u1", "u2"),each=5),
p_id=c("p1", "p1", "p1", "p2","p2", "p1", "p2", "p2", "p2", "p2" ),
c_dt=c("2015-12-01", "2015-12-02",
"2015-12-03", "2015-12-02", "2015-12-05",
"2015-12-02", "2015-12-03", "2015-12-04",
"2015-12-05", "2015-12-06"))
c_dt
u_id p_id c_dt
1: u1 p1 2015-12-01
2: u1 p1 2015-12-02
3: u1 p1 2015-12-03
4: u1 p2 2015-12-02
5: u1 p2 2015-12-05
6: u2 p1 2015-12-02
7: u2 p2 2015-12-03
8: u2 p2 2015-12-04
9: u2 p2 2015-12-05
10: u2 p2 2015-12-06
现在我们将按u_id和p_id进行分组, 并按 c_df的最小值进行过滤 :
cdedup_dt <- c_dt[ , .SD[c_dt == min(c_dt)], by = .(u_id, p_id)]
cdedup_dt
u_id p_id c_dt
1: u1 p1 2015-12-01
2: u1 p2 2015-12-02
3: u2 p1 2015-12-02
4: u2 p2 2015-12-03
请注意.(u_id, p_id)
等于list(u_id, p_id)
而.SD
是指每个组的Data.table的子集。 你所缺少的就是.SD
。
正如@ zero323 min所提到的,将保留重复(这基本上意味着我们的示例中有一些重复的行)。 如果您只希望为每个组保留一条记录,则更安全的选择是使用排名功能:
cdedup_dt <- c_dt[, .SD[rank(c_dt, ties.method = c("first")) == 1],by = .(u_id, p_id)]
cdedup_dt
u_id p_id c_dt
1: u1 p1 2015-12-01
2: u1 p2 2015-12-02
3: u2 p1 2015-12-02
4: u2 p2 2015-12-03
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.