2014-11-06 29 views
3

亞組考慮由分組變量(這裏id)的數據集和有序變量(這裏date使用`data.table`獲得第一基於可變

(df <- data.frame(
    id = rep(1:2,2), 
    date = 4:1 
)) 
# id date 
# 1 1 4 
# 2 2 3 
# 3 1 2 
# 4 2 1 

我想知道什麼最簡單的方法是在data.table做這個dplyr代碼相當於:

library(dplyr) 
df %>% 
    group_by(id) %>% 
    filter(min_rank(date)==1) 
# Source: local data frame [2 x 2] 
# Groups: id 
# 
# id date 
# 1 1 2 
# 2 2 1 

即每個id根據date拿到第一。

基於類似計算器的問題(Create an "index" for each element of a group with data.table),我想出了這個

library(data.table) 
dt <- data.table(df) 
setkey(dt, id, date) 
for(k in unique(dt$id)){ 
    dt[id==k, index := 1:.N] 
} 
dt[index==1,] 

但似乎應該有一個班輪這一點。不熟悉data.table我以爲像這樣

dt[,,mult="first", by=id] 

應該工作,但唉!代碼的最後一點似乎應該按id,然後採取先(其內id將由date來決定,因爲我已經這樣設置的加密密鑰。)


編輯

由於阿難Mahto,這一個班輪現在在我data.table劇目

dt[,.SD[1], by=id] 
# id date 
# 1: 1 2 
# 2: 2 1 
+0

會這樣的工作適合你:'setkey(as.data.table(df),id,date)[,.SD [1],by = id]'? – A5C1D2H2I1M1N2O1R2T1 2014-11-06 10:46:43

+0

@AnandaMahto是的!謝謝。 – 2014-11-06 10:51:42

+1

@DavidArenburg,毫秒正在慢慢地殺死我:-) – A5C1D2H2I1M1N2O1R2T1 2014-11-06 11:11:40

回答

4

直接與你的源data.frame工作,你可以嘗試:

setkey(as.data.table(df), id, date)[, .SD[1], by = id] 
# id date 
# 1: 1 2 
# 2: 2 1 

擴展您最初的想法,你可以這樣做:

dt <- data.table(df) 
setkey(dt, id, date) 
dt[, index := sequence(.N), by = id][index == 1] 
# id date index 
# 1: 1 2  1 
# 2: 2 1  1 

這可能是在一定的規模,大衛是正確的約head VS [1],但我不知道會是什麼規模。

set.seed(1) 
nrow <- 10000 
ncol <- 20 

df <- data.frame(matrix(sample(10, nrow * ncol, TRUE), nrow = nrow, ncol = ncol)) 

fun1 <- function() setkey(as.data.table(df), X1, X2)[, head(.SD, 1), by = X1] 
fun2 <- function() setkey(as.data.table(df), X1, X2)[, .SD[1], by = X1] 

library(microbenchmark) 
microbenchmark(fun1(), fun2()) 
# Unit: milliseconds 
# expr  min  lq  mean median  uq  max neval 
# fun1() 12.178189 12.496777 13.400905 12.808523 13.483545 30.28425 100 
# fun2() 4.474345 4.554527 4.948255 4.620596 4.965912 8.17852 100 
+0

爲什麼您使用'.SD'而不是'date'?你爲什麼不使用'setDT'? – Roland 2014-11-06 10:54:41

+0

@羅蘭,我做這些事情是強制性的嗎?如果除「日期」之外還有更多列,該怎麼辦?如果我不想將輸入轉換爲'data.table'會怎麼樣? – A5C1D2H2I1M1N2O1R2T1 2014-11-06 10:56:35

+0

不,當然不是。這個問題是針對一列的。你爲什麼不呢? – Roland 2014-11-06 10:58:26

2

下面是使用data.table小號二進制搜索

setkey(dt[, indx := seq_len(.N), by = id], indx)[J(1)] 
# id date indx 
# 1: 1 2 1 
# 2: 2 1 1 

一些性能測試的另一種選擇: 似乎所有的方法執行或多或少相同,但在龐大的數據集(1e+06*1e+2)二進制搜索獲勝

set.seed(1) 
nrow <- 1e6 
ncol <- 1e2 

df <- data.frame(matrix(sample(10, nrow * ncol, TRUE), nrow = nrow, ncol = ncol)) 
library(data.table) 

funAM1 <- function() setkey(as.data.table(df), X1, X2)[, .SD[1], by = X1] 
funAM2 <- function() setkey(as.data.table(df), X1, X2)[, index := sequence(.N), by = X1][index == 1] 
funDA1 <- function() setkey(as.data.table(df), X1, X2)[, head(.SD, 1), by = X1] 
funDA2 <- function() setkey(as.data.table(df)[, indx := seq_len(.N), by = X1], X1)[J(1)] 

library(microbenchmark) 
Res <- microbenchmark(funAM1(), funAM2(), funDA1(), funDA2()) 
Res 
# Unit: milliseconds 
#  expr  min  lq median  uq  max neval 
# funAM1() 737.5690 758.3015 771.9344 794.1417 910.1019 100 
# funAM2() 631.7822 693.8286 704.6912 729.6960 806.5556 100 
# funDA1() 757.0327 772.4353 784.3107 810.0759 938.6344 100 
# funDA2() 564.7291 578.1089 587.6470 611.7269 740.4077 100 
boxplot(Res) 

enter image description here