2014-04-22 7 views
10

मेरा लक्ष्य data.table में उपसर्ग skill_ से शुरू होने वाले कॉलम में सभी मानों को जोड़ना है। मैं data.table का उपयोग कर समाधान पसंद करूंगा लेकिन मैं picky नहीं हूँ।सभी कॉलमों का योग करने का सबसे प्रभावी तरीका क्या है जिसका नाम पैटर्न के साथ शुरू होता है?

अब मेरे समाधान अप:

> require(data.table) 
> DT <- data.table(x=1:4, skill_a=c(0,1,0,0), skill_b=c(0,1,1,0), skill_c=c(0,1,1,1)) 
> DT[, row_idx := 1:nrow(DT)] 
> DT[, count_skills := 
      sapply(1:nrow(DT), 
       function(id) sum(DT[row_idx == id, 
            grepl("skill_", names(DT)), with=FALSE]))] 

> DT 
    x skill_a skill_b skill_c row_idx count_skills 
1: 1  0  0  0  1   0 
2: 2  1  1  1  2   3 
3: 3  0  1  1  3   2 
4: 4  0  0  1  4   1 

लेकिन यह बहुत धीमी गति से हो जाता है जब डीटी बहुत बड़ी है। क्या ऐसा करने का एक और अधिक प्रभावी तरीका है?

+0

कितना बड़ा_ और आप यहां कितने धीमे बात कर रहे हैं? – Thell

उत्तर

13

दक्षता और प्रदर्शन हमेशा मानक हकदार के बारे में एक सवाल ...

अपने डेटा का आकार महत्वपूर्ण है के रूप में विकास दर एक बनाता है विशाल अंतर ...

Relative Times सापेक्ष बेंचमार्क समय 2^4 और 2^24।
आकार के साथ 1 लाख पंक्तियों पर मानक के floor(2^logb(10^(seq(4, 24, .5)), 10))

अंश ...

## Unit: milliseconds 
##    expr min  lq median uq max neval 
## dplyr.sol(DT) 21.803 50.260 51.765 52.45 73.30 100 
## rowSums.sol(DT) 20.759 50.224 51.418 52.56 96.28 100 
## SDCols.sol(DT) 7.250 8.916 37.699 38.50 52.69 100 
##  eval.sol(DT) 6.883 7.007 7.916 9.45 50.91 100 

eval.sol एक जवाब है कि नीचे स्रोत में अभिव्यक्ति की data.table से निपटने का लाभ लेता है, है। ..

library(compiler) 
library(data.table) 
suppressMessages(library(dplyr)) 
library(microbenchmark) 

buildDT <- function(reps) { 
    data.table(x=seq_len(reps*4), 
       skill_a=rep(c(0,1,0,0),reps), 
       skill_b=rep(c(0,1,1,0),reps), 
       skill_c=rep(c(0,1,1,1),reps)) 
} 

OP.sol <- function(DT) { 
    DT[, row_idx := 1:nrow(DT)] 
    DT[, count_skills := 
      sapply(1:nrow(DT), 
       function(id) sum(DT[row_idx == id, 
            grepl("skill_", names(DT)), with=FALSE]))] 
} 

dplyr.sol <- function(DT) 
    DT %.% select(starts_with("skill_")) %.% rowSums() 

SDCols.sol <- function(DT) 
    DT[, Reduce(`+`, .SD), 
    .SDcols = grep("skill_", names(DT), value = T)] 

rowSums.sol <- function(DT) 
    rowSums(DT[,grep("skill_", names(DT)),with=FALSE]) 

eval.sol <- function(DT) { 
    cmd <- parse(text=paste(colnames(DT)[grepl("^skill_", colnames(DT))],collapse='+')) 
    DT[,eval(cmd)] 
} 

DT <- buildDT(1) 
identical(OP.sol(DT)$count_skills, dplyr.sol(DT)) 

## [1] TRUE 

identical(OP.sol(DT)$count_skills, rowSums.sol(DT)) 

## [1] TRUE 

identical(OP.sol(DT)$count_skills, SDCols.sol(DT)) 

## [1] TRUE 

identical(OP.sol(DT)$count_skills, eval.sol(DT)) 

## [1] TRUE 

DT<-buildDT(2500) 
nrow(DT) 

## [1] 10000 

microbenchmark(# OP.sol(DT), forget this method. 
       dplyr.sol(DT), 
       rowSums.sol(DT), 
       SDCols.sol(DT), 
       eval.sol(DT), 
       times=100) 

## Unit: microseconds 
##    expr min lq median uq max neval 
## dplyr.sol(DT) 760.1 809.0 848.2 951.5 2276 100 
## rowSums.sol(DT) 580.5 605.3 627.6 745.7 28481 100 
## SDCols.sol(DT) 559.8 610.5 638.8 694.0 2016 100 
##  eval.sol(DT) 636.4 677.7 692.4 740.5 2021 100 

DT<-buildDT(25000) 
nrow(DT) 

## [1] 100000 

microbenchmark(# OP.sol(DT), forget this method. 
       dplyr.sol(DT), 
       rowSums.sol(DT), 
       SDCols.sol(DT), 
       eval.sol(DT), 
       times=100) 

## Unit: milliseconds 
##    expr min lq median uq max neval 
## dplyr.sol(DT) 2.668 3.744 4.045 4.573 33.87 100 
## rowSums.sol(DT) 2.455 3.339 3.756 4.235 34.19 100 
## SDCols.sol(DT) 1.253 1.401 2.179 2.392 31.72 100 
##  eval.sol(DT) 1.294 1.427 2.116 2.484 32.02 100 

DT<-buildDT(250000) 
nrow(DT) 

## [1] 1000000 

microbenchmark(# OP.sol(DT), forget this method. 
       dplyr.sol(DT), 
       rowSums.sol(DT), 
       SDCols.sol(DT), 
       eval.sol(DT), 
       times=100) 

## Unit: milliseconds 
##    expr min  lq median uq max neval 
## dplyr.sol(DT) 21.803 50.260 51.765 52.45 73.30 100 
## rowSums.sol(DT) 20.759 50.224 51.418 52.56 96.28 100 
## SDCols.sol(DT) 7.250 8.916 37.699 38.50 52.69 100 
##  eval.sol(DT) 6.883 7.007 7.916 9.45 50.91 100 

identical(dplyr.sol(DT), rowSums.sol(DT)) 

## [1] TRUE 

identical(dplyr.sol(DT), SDCols.sol(DT)) 

## [1] TRUE 

identical(dplyr.sol(DT), eval.sol(DT)) 

## [1] TRUE 
+1

मुझे आपके बेंचमार्क – eddi

+0

@eddi में 'SDCols.sol' नहीं दिखाई देता है, मेरे खराब ... जोड़ा गया। बेंचमार्किंग के लिए – Thell

+1

धन्यवाद! तुलना 'SDCols.sol' के खिलाफ थोड़ा अनुचित है। यह परिवर्तनीय 'count_skills' जोड़ने पर कुछ समय खो रहा है जो अन्य समाधानों में नहीं किया जाता है। तो सही संस्करण 'डीटी [, घटाएं (' + ', एसएसडी), .SDcols = grep (" skill_ ", नाम (डीटी), मान = टी)]'। और यदि आप इसे केवल 10 बार चलाते हैं तो समय थोड़ा अस्थिर है। मैंने 'times = 100' के साथ अंतिम बेंचमार्क किया और' SDCols.sol' अपडेट किया और मुझे 35.2 ('SDCols.sol') और 32.4 (' eval.sol') जैसे औसत समय मिल गए। अंतर अब इतना बड़ा नहीं है। – djhurio

9

rowSums उपयोग करने के लिए क्यों नहीं, यह आम तौर पर कुशल है:

rowSums(DT[,grep("skill_", names(DT)),with=FALSE]) 
+0

धन्यवाद, जो मेरी समस्या हल करता है! मुझे यकीन नहीं है कि कोड पुन: उत्पन्न क्यों नहीं किया जाता है। एक आवश्यकता (डेटा.table) गुम है? मैं इसे जोड़ दूंगा। – Rodrigo

+0

@RogerBill क्षमा करें, कोड पुन: उत्पन्न किया गया था (मैंने आपके कोड से कोई लाइन नहीं बनाई) – agstudy

7

समाधान data.table और .SDcols का उपयोग कर।

require(data.table) 

DT <- data.table(x=1:4, skill_a=c(0,1,0,0), skill_b=c(0,1,1,0), 
       skill_c=c(0,1,1,1)) 

DT[, row_idx := 1:nrow(DT)] 

DT[, count_skills := Reduce(`+`, .SD), 
    .SDcols = grep("skill_", names(DT), value = T)] 
DT 
+0

धन्यवाद! इस तरह आपको row_idx जोड़ने की आवश्यकता नहीं है, कि मैं एक सहायक चर के रूप में उपयोग कर रहा था। – Rodrigo

8

यहाँ एक dplyr समाधान है:

library(dplyr) 

DT %>% mutate(count = DT %>% select(starts_with("skill_")) %>% rowSums()) 
संबंधित मुद्दे

 संबंधित मुद्दे