2016-02-10 12 views
8

मैं उन स्तंभों की संख्या गिनने की कोशिश कर रहा हूं जिनमें प्रत्येक पंक्ति के लिए NA शामिल नहीं है, और उस पंक्ति को उस पंक्ति के लिए एक नए कॉलम में रखें।आर: डेटा.table गिनती! NA प्रति पंक्ति

उदाहरण डेटा:

a b c num_obs 
1: 1 6 11  3 
2: 2 NA 12  2 
3: 3 8 NA  2 
4: 4 9 14  3 
5: NA 10 15  2 

मैं घंटों के लिए अभी पढ़ रहा है:

library(data.table) 

a = c(1,2,3,4,NA) 
b = c(6,NA,8,9,10) 
c = c(11,12,NA,14,15) 
d = data.table(a,b,c) 

> d 
    a b c 
1: 1 6 11 
2: 2 NA 12 
3: 3 8 NA 
4: 4 9 14 
5: NA 10 15 

मेरे वांछित आउटपुट एक नया स्तंभ num_obs जो गैर एनए प्रविष्टियों प्रति पंक्ति की संख्या में शामिल हैं को शामिल किया जाएगा और अब तक का सबसे अच्छा मैं पंक्तियों पर लूपिंग कर रहा हूं, जो मुझे पता है आर या डेटा.table में कभी सलाह नहीं दी जाती है। मुझे यकीन है कि ऐसा करने का एक बेहतर तरीका है, कृपया मुझे प्रबुद्ध करें।

मेरे भद्दा तरीका:

len = (1:NROW(d)) 
for (n in len) { 
    d[n, num_obs := length(which(!is.na(d[n])))] 
} 
+1

'डी [, num_obs: = sum (! Is.na (.SD)) की तरह, = 1: nrow (d)] []' या 'd [, num_obs: = rowSums (! Is.na (d))] [] '? (सुनिश्चित नहीं है कि कौन तेज़ होगा।) – A5C1D2H2I1M1N2O1R2T1

+0

हाँ! यह काम किया। क्या आप इसे समझा सकते हैं? मैंने सोचा था। अगर मैं '1 = 1: nrow (d)' का उपयोग करता हूं तो एसडी पूरे डेटासेट के बराबर होगा। यह कैसे है कि यह पंक्ति से करता है? संपादित करें: भी, खाली श्रृंखला '[] 'क्या जोड़ता है? – Reilstein

उत्तर

13

यह एक + कॉल एक साथ श्रृंखला के लिए Reduce उपयोग करके देखें:

d[, num_obs := Reduce(`+`, lapply(.SD,function(x) !is.na(x)))] 

तो गति महत्वपूर्ण है, तुम बाहर एक स्पर्श अधिक आनंद के सुझाव के साथ eek सकते स्तंभों की संख्या को हार्डकोड करने मूल्यांकन किया जा रहा:

d[, num_obs := 4 - Reduce("+", lapply(.SD, is.na))] 

बेंचमार्किंग का उपयोग कर आनंद के data.table d बड़ा ऊपर से:

fun1 <- function(indt) indt[, num_obs := rowSums(!is.na(indt))][] 
fun3 <- function(indt) indt[, num_obs := Reduce(`+`, lapply(.SD,function(x) !is.na(x)))][] 
fun4 <- function(indt) indt[, num_obs := 4 - Reduce("+", lapply(.SD, is.na))][] 

library(microbenchmark) 
microbenchmark(fun1(copy(d)), fun3(copy(d)), fun4(copy(d)), times=10L) 

#Unit: milliseconds 
#   expr  min  lq  mean median  uq  max neval 
# fun1(copy(d)) 3.565866 3.639361 3.912554 3.703091 4.023724 4.596130 10 
# fun3(copy(d)) 2.543878 2.611745 2.973861 2.664550 3.657239 4.011475 10 
# fun4(copy(d)) 2.265786 2.293927 2.798597 2.345242 3.385437 4.128339 10 
+0

अच्छा काम थाला :-) – A5C1D2H2I1M1N2O1R2T1

+0

अच्छा विकल्प। एक और। – akrun

+0

शायद यह ओपी के विवरण को देखते हुए कुछ और गति प्राप्त करेगा: 'indt [, num_obs: = 4 - कम करें ("+", लापरवाही (.SD, is.na))] [] '। पंक्ति से पुनर्मूल्यांकन से बचने के लिए मैंने "4" को हार्ड-कोड किया है। – A5C1D2H2I1M1N2O1R2T1

6

पास दो विकल्प है कि जल्दी से मन में आ रहे हैं:

d[, num_obs := sum(!is.na(.SD)), by = 1:nrow(d)][] 
d[, num_obs := rowSums(!is.na(d))][] 

प्रति समूह के लिए सिर्फ एक पंक्ति के एक "समूह" बनाने के द्वारा पहले काम करता है (1:nrow(d)) । इसके बिना, यह पूरी तालिका में NA मानों को जोड़ देगा।

दूसरा पहले से ही बहुत ही कुशल बेस आर फ़ंक्शन, rowSums का उपयोग करता है।

यहां पर अधिक डेटा पर एक बेंचमार्क है:

set.seed(1) 
nrow = 10000 
ncol = 15 
d <- as.data.table(matrix(sample(c(NA, -5:10), nrow*ncol, TRUE), nrow = nrow, ncol = ncol)) 

fun1 <- function(indt) indt[, num_obs := rowSums(!is.na(indt))][] 
fun2 <- function(indt) indt[, num_obs := sum(!is.na(.SD)), by = 1:nrow(indt)][] 

library(microbenchmark) 
microbenchmark(fun1(copy(d)), fun2(copy(d))) 
# Unit: milliseconds 
#   expr  min   lq  mean  median   uq  max neval 
# fun1(copy(d)) 3.727958 3.906458 5.507632 4.159704 4.475201 106.5708 100 
# fun2(copy(d)) 584.499120 655.634889 684.889614 681.054752 712.428684 861.1650 100 

वैसे, खाली [] बस है जिसके परिणामस्वरूप data.table मुद्रित करने के लिए। यह आवश्यक है जब आप "data.table" में set* फ़ंक्शंस से आउटपुट वापस करना चाहते हैं।

+0

यह बहुत अच्छा है, धन्यवाद @AnandaMahto! मैं थोड़ा उलझन में हूं कि आपने '1: nrow (d) 'का उपयोग करके एक पंक्ति के समूह को कैसे बनाया है। मेरा प्रारंभिक विचार यह था कि यह कथन पंक्ति 1 से फ़ाइल की अंतिम पंक्ति में एक समूह बना देगा। मैं स्पष्ट रूप से याद कर रहा हूं कि 'द्वारा' कथन कैसे काम करता है या कुछ। – Reilstein

+2

मेरे मानक सुझाव देते हैं कि यह फिर से तेज है: 'fun3 <- function (indt) indt [, num_obs: = घटाएं (\ '+ \', लापरवाही (.SD, फ़ंक्शन (x)! Is.na (x))]] [] ' – thelatemail

+0

हाँ मेरे बड़े डेटा सेट पर, लगभग 115 बनाम 0.06 एस, इसलिए एक बड़ा सुधार! इसे जोड़ने के लिए धन्यवाद! – Reilstein

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