2015-01-28 13 views
14

निम्न डेटा फ्रेम पर विचार के आधार पर:फ़िल्टर एक data.frame के प्रत्येक स्तंभ एक विशिष्ट मूल्य

df <- data.frame(replicate(5,sample(1:10,10,rep=TRUE))) 

# X1 X2 X3 X4 X5 
#1 7 9 8 4 10 
#2 2 4 9 4 9 
#3 2 7 8 8 6 
#4 8 9 6 6 4 
#5 5 2 1 4 6 
#6 8 2 2 1 7 
#7 3 8 6 1 6 
#8 3 8 5 9 8 
#9 6 2 3 10 7 
#10 2 7 4 2 9 

dplyr का उपयोग करते हुए, मैं कैसे प्रत्येक स्तंभ पर फ़िल्टर कर सकते हैं, (परोक्ष उनका नाम इस के बिना), सभी मानों के लिए एक से अधिक 2.

कोई चीज जो एक काल्पनिक filter_each(funs(. >= 2))

अभी नकल होगा मैं कर रहा हूँ:

df %>% filter(X1 >= 2, X2 >= 2, X3 >= 2, X4 >= 2, X5 >= 2) 

कौन सा के बराबर है:

df %>% filter(!rowSums(. < 2)) 

नोट: मुझे क्या करना होगा चलो कहते हैं कि मैं पहले 4 स्तंभ पर केवल फिल्टर करने के लिए करना चाहता था दो,:

df %>% filter(X1 >= 2, X2 >= 2, X3 >= 2, X4 >= 2) 

या

df %>% filter(!rowSums(.[-5] < 2)) 

चाहेंगे एक और अधिक कुशल विकल्प हो सकता है?

संपादित करें: उप सवाल

कैसे एक स्तंभ नाम निर्दिष्ट और एक hypothethical filter_each(funs(. >= 2), -X5) नकल करने के लिए?

बेंचमार्क उप सवाल

जब से मैं एक बड़े डेटासेट पर इस चलाने के लिए है, मैं सुझाव बेंचमार्क।

df <- data.frame(replicate(5,sample(1:10,10e6,rep=TRUE))) 

mbm <- microbenchmark(
Marat = df %>% filter(!rowSums(.[,!colnames(.) %in% "X5", drop = FALSE] < 2)), 
Richard = filter_(df, .dots = lapply(names(df)[names(df) != "X5"], function(x, y) { call(">=", as.name(x), y) }, 2)), 
Docendo = df %>% slice(which(!rowSums(select(., -matches("X5")) < 2L))), 
times = 50 
) 

यहाँ परिणाम हैं:

#Unit: milliseconds 
# expr  min  lq  mean median  uq  max neval 
# Marat 1209.1235 1320.3233 1358.7994 1362.0590 1390.342 1448.458 50 
# Richard 1151.7691 1196.3060 1222.9900 1216.3936 1256.191 1266.669 50 
# Docendo 874.0247 933.1399 983.5435 985.3697 1026.901 1053.407 50 

enter image description here

+2

क्या इसे dplyr का उपयोग करना है? – shecode

+1

स्टीवन, मुझे लगता है कि आपने इसे 'डीएफ%>% फ़िल्टर (! पंक्तिसमूह (। <2))' –

+0

@MaratTalipov अनुमान लगाया है, हां। लेकिन यह केवल कॉलम * नाम * निर्दिष्ट करने में सक्षम होना सुविधाजनक होगा जिसे आप फ़िल्टर नहीं करना चाहते हैं। एक hypothetical 'filter_each (मज़ेदार (।> = 2), -X5) की तरह कुछ ' –

उत्तर

4

slice के साथ एक और विकल्प है जिसका उपयोग इस मामले में filter के समान ही किया जा सकता है। मुख्य अंतर यह है कि आप slice पर एक पूर्णांक वेक्टर की आपूर्ति करते हैं जबकि filter लॉजिकल वेक्टर लेता है।

df %>% slice(which(!rowSums(select(., -matches("X5")) < 2L))) 

मैं इस दृष्टिकोण के बारे में क्या पसंद है कि क्योंकि हम rowSums अंदर select का उपयोग आप उस select आपूर्ति, उदाहरण के लिए matches की तरह सभी विशेष कार्य का उपयोग कर सकते है।


देखें कि यह कैसे अन्य उत्तर की तुलना करते हैं: टिप्पणी

df <- data.frame(replicate(5,sample(1:10,10e6,rep=TRUE))) 

mbm <- microbenchmark(
    Marat = df %>% filter(!rowSums(.[,!colnames(.) %in% "X5", drop = FALSE] < 2)), 
    Richard = filter_(df, .dots = lapply(names(df)[names(df) != "X5"], function(x, y) { call(">=", as.name(x), y) }, 2)), 
    dd_slice = df %>% slice(which(!rowSums(select(., -matches("X5")) < 2L))), 
    times = 50L, 
    unit = "relative" 
) 

#Unit: relative 
#  expr  min  lq median  uq  max neval 
# Marat 1.304216 1.290695 1.290127 1.288473 1.290609 50 
# Richard 1.139796 1.146942 1.124295 1.159715 1.160689 50 
# dd_slice 1.000000 1.000000 1.000000 1.000000 1.000000 50 

pic

संपादित करें: 50 repetitions (बार = 50L) के साथ और अधिक विश्वसनीय बेंचमार्क के साथ अद्यतन।


एक टिप्पणी है कि आधार आर slice दृष्टिकोण के रूप में एक ही गति के लिए होता है (क्या आधार आर दृष्टिकोण बिल्कुल मतलब है के विनिर्देश के बिना) के बाद, मैं आर लगभग का उपयोग कर के आधार के लिए एक तुलना के साथ मेरा उत्तर अद्यतन करने का फैसला किया मेरे जवाब में एक ही दृष्टिकोण। आधार आर के लिए मैं प्रयोग किया है:

base = df[!rowSums(df[-5L] < 2L), ], 
base_which = df[which(!rowSums(df[-5L] < 2L)), ] 

बेंचमार्क:

df <- data.frame(replicate(5,sample(1:10,10e6,rep=TRUE))) 

mbm <- microbenchmark(
    Marat = df %>% filter(!rowSums(.[,!colnames(.) %in% "X5", drop = FALSE] < 2)), 
    Richard = filter_(df, .dots = lapply(names(df)[names(df) != "X5"], function(x, y) { call(">=", as.name(x), y) }, 2)), 
    dd_slice = df %>% slice(which(!rowSums(select(., -matches("X5")) < 2L))), 
    base = df[!rowSums(df[-5L] < 2L), ], 
    base_which = df[which(!rowSums(df[-5L] < 2L)), ], 
    times = 50L, 
    unit = "relative" 
) 

#Unit: relative 
#  expr  min  lq median  uq  max neval 
#  Marat 1.265692 1.279057 1.298513 1.279167 1.203794 50 
# Richard 1.124045 1.160075 1.163240 1.169573 1.076267 50 
# dd_slice 1.000000 1.000000 1.000000 1.000000 1.000000 50 
#  base 2.784058 2.769062 2.710305 2.669699 2.576825 50 
# base_which 1.458339 1.477679 1.451617 1.419686 1.412090 50 

pic2

नहीं वास्तव में किसी भी अच्छा है या तुलनीय इन दोनों आधार आर दृष्टिकोण के साथ प्रदर्शन।

नोट संपादित करें # 2: आधार आर विकल्पों के साथ बेंचमार्क जोड़ा गया।

+1

यह अधिक प्राकृतिक, अधिक 'dplyr'-esque लगता है और वास्तव में अधिक कुशल है। ओपी में बेंचमार्क अपडेट करेंगे। –

+0

यह बहुत चालाक है। अच्छा जवाब –

+0

@ कोलोनेल बेउवेल, वास्तव में? मैंने बेस आर के साथ बेंचमार्क किया और यह धीमा था। –

6

यहाँ एक विचार यह काफी सरल नामों का चयन करने के बनाता है। आप filter_() के .dots तर्क को भेजने के लिए कॉल की एक सूची सेट अप कर सकते हैं। पहला ऐसा फ़ंक्शन जो एक अनियमित कॉल बनाता है।

Call <- function(x, value, fun = ">=") call(fun, as.name(x), value) 

अब हम filter_() उपयोग करते हैं, lapply() का उपयोग कर .dots बहस में कॉल की एक सूची से गुजर रहा, किसी भी नाम और मान चाहते हैं चुनने।

nm <- names(df) != "X5" 
filter_(df, .dots = lapply(names(df)[nm], Call, 2L)) 
# X1 X2 X3 X4 X5 
# 1 6 5 7 3 1 
# 2 8 10 3 6 5 
# 3 5 7 10 2 5 
# 4 3 4 2 9 9 
# 5 8 3 5 6 2 
# 6 9 3 4 10 9 
# 7 2 9 7 9 8 

यदि आप lapply() की X बहस में names() समायोजित

lapply(names(df)[4:5], Call, 2L) 
# [[1]] 
# X4 >= 2L 
# 
# [[2]] 
# X5 >= 2L 

तो साथ उदाहरण X4 और X5 के लिए Call() द्वारा बनाई unevaluated कॉल पर एक नज़र हो सकता है,,, आप होना चाहिए ठीक।

5

कॉलम नाम निर्दिष्ट करने और एक हाइपोथेथिकल filter_each (मज़ेदार (।> = 2), -X5) की नकल कैसे करें?

यह सबसे सुरुचिपूर्ण समाधान नहीं हो सकता है, लेकिन यह काम किया जाता है:

df %>% filter(!rowSums(.[,!colnames(.)%in%'X5',drop=F] < 2)) 

कई बाहर रखा कॉलम (जैसे X3, X5) के मामले में, एक का उपयोग कर सकते हैं:

df %>% filter(!rowSums(.[,!colnames(.)%in%c('X3','X5'),drop=F] < 2)) 
+2

'नाम' के बजाय 'नाम' का उपयोग करना तेज़ हो सकता है क्योंकि 'नाम' आदिम –

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