2015-10-20 98 views
2

我正在嘗試提高以下進程的計算效率。我創建了一個使用數據進行審查的玩具示例。第一種方法的運行時間是第二種方法的一半。改善循環的運行時間

如何改進第一種方法的運行時間?

library(sqldf) 
id = c(1,1,1,1,2,2,2,5,5,5,5,5,5) 
qn = c(0,0,1,1,0,1,0,0,0,1,0,1,0) 
d = data.frame(cbind(id,qn)) 
names(d) = c("id", "qn") 

un = unique(d$id) 
holder = matrix(0,length(un), 1) 
counter = 0 

x = proc.time() 

for (i in un) 
{ 
    z = head(which(d[d$id == i,]$qn==1),1) 
    counter = counter + 1 
    holder[counter,] = z 
} 

proc.time() - x 
f = sqldf("select id, count(qn) from d group by id", drv = 'SQLite') 
f = cbind(f,holder) 
################################# 
un = unique(d$id) 
holder = matrix(0,length(un), 1) 
counter = 0 

x = proc.time() 

for (i in 1:length(un)) 
{ 
    y = paste("select * from d where id = ", un[i]) 
    y = sqldf(y, drv = 'SQLite') 
    y = min(which(y$qn==1)) 
    counter = counter + 1 
    holder[counter,] = y 
} 

proc.time() - x 
f = sqldf("select id, count(qn) from d group by id", drv = 'SQLite') 
f = cbind(f,holder) 

我試圖計算每個ID的1

預期輸出的第一個實例:使用

# id first 
# 1: 1  3 
# 2: 2  2 
# 3: 5  3 
+1

最好是試着描述一下你正在嘗試做的,而不是隻顯示你如何」我已經做到了。什麼是最終目標? – MrFlick

+0

感謝您的快速回復!我試着爲每個ID計算一個1. –

回答

4

我們也可以使用data.table

library(data.table) 
setDT(d)[, list(first= which.max(qn)) , id] 
+1

謝謝!這樣可行。速度現在下降到0.01-0.02秒!這是贏家!我將用所有示例更新代碼。 –

+0

完成!由於報酬很小,我無法贊成,但在能夠做到的時候會做! –

4

你可以做到這一點沒有sqldfdplyr

library(dplyr) 
d %>% 
    group_by(id) %>% 
    summarize(first=first(which(qn==1))) 
+0

謝謝!這樣可行。速度從0.05秒降至0.03秒! %>%是什麼意思? –

+0

'%>%'代表'pipe'運算符,它的作用是將數據傳遞到下一個函數,請參閱http://stackoverflow.com/questions/24845028/understanding-operator/24845091#24845091和http: //stackoverflow.com/questions/24536154/what-does-mean-in-r – Alex

3

1) lapply內使用sqldf:

do.call(rbind, 
     lapply(split(d, id), function(i) 
      sqldf("SELECT id, min(rowid) AS first 
       FROM (SELECT rowid, * 
         FROM i) AS x 
       WHERE qn = 1")) 
     ) 

## id first 
## 1 1  3 
## 2 2  2 
## 5 5  3 

2)或用於純SQL溶液從第一ROWID減去第一行的ROWID每個組中具有QN = 1各組與添加1:

sqldf("select id, min_row1 - min_row + 1 first 
     from (select id, min(rowid) min_row 
      from d 
      group by id) 
     join (select id, min(rowid) min_row1 
      from d where qn = 1 
      group by id) using (id)") 


## id first 
## 1 1  3 
## 2 2  2 
## 3 5  3 

3)或一種替代純SQL溶液,C reate序列seq ID內內選擇,然後挑選出內有ID組QN = 1的第一個:

sqldf("select id, min(seq) first 
     from (select x.id, x.qn, count() seq 
      from d x 
      join d y on x.rowid >= y.rowid and x.id = y.id 
      group by x.rowid) 
     where qn = 1 
     group by id") 

## id first 
## 1 1  3 
## 2 2  2 
## 3 5  3 
+0

@ G.Grothendieck有沒有辦法在不使用'RPostgreSQL'的情況下獲得'row_number over(partition by id)'的功能?然後我們可以放下樂器。 – zx8754

+1

已在最後添加 –

+0

那麼神奇!我甚至不知道它可以用普通的SQL來完成。謝謝!我測試過它,但比我的方法1慢,但比我的方法快2。 –