2011-01-20 7 views
68

के सभी तत्वों के बीच समानता के लिए परीक्षण मैं परीक्षण करने की कोशिश कर रहा हूं कि वेक्टर के सभी तत्व एक-दूसरे के बराबर हैं या नहीं। जिन समाधानों के साथ मैं आया हूं, वे कुछ हद तक चौराहे लगते हैं, जिनमें length() की जांच शामिल है।एक वेक्टर

x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE 
y <- rep(2, times = 7)  # TRUE 

unique() के साथ:

length(unique(x)) == 1 
length(unique(y)) == 1 

rle() के साथ:

length(rle(x)$values) == 1 
length(rle(y)$values) == 1 

एक समाधान है कि मुझे तत्वों के बीच 'समानता' का आकलन करने के लिए एक सहिष्णुता मूल्य शामिल FAQ 7.31 से बचने के लिए आदर्श होगा दिया जाएगा मुद्दे।

क्या परीक्षण के प्रकार के लिए एक अंतर्निहित फ़ंक्शन है जिसे मैंने पूरी तरह अनदेखा कर दिया है? identical() और all.equal() दो आर वस्तुओं की तुलना करें, इसलिए वे यहां काम नहीं करेंगे।

संपादित करें 1

यहाँ कुछ बेंच मार्किंग परिणाम हैं। परिणाम के साथ

library(rbenchmark) 

John <- function() all(abs(x - mean(x)) < .Machine$double.eps^0.5) 
DWin <- function() {diff(range(x)) < .Machine$double.eps^0.5} 
zero_range <- function() { 
    if (length(x) == 1) return(TRUE) 
    x <- range(x)/mean(x) 
    isTRUE(all.equal(x[1], x[2], tolerance = .Machine$double.eps^0.5)) 
} 

x <- runif(500000); 

benchmark(John(), DWin(), zero_range(), 
    columns=c("test", "replications", "elapsed", "relative"), 
    order="relative", replications = 10000) 

: कोड का उपयोग करना

  test replications elapsed relative 
2  DWin()  10000 109.415 1.000000 
3 zero_range()  10000 126.912 1.159914 
1  John()  10000 208.463 1.905251 

तो यह लग रहा है diff(range(x)) < .Machine$double.eps^0.5 की तरह सबसे तेज है।

R> compare <- function(v) all(sapply(as.list(v[-1]), 
+       FUN=function(z) {identical(z, v[1])})) 
R> compare(x) 
[1] FALSE 
R> compare(y) 
[1] TRUE 
R> 

इस तरह आप के रूप में की जरूरत के लिए किसी भी identical() एप्सिलॉन जोड़ सकते हैं:

उत्तर

25

मैं इस विधि है, जो न्यूनतम और अधिकतम तुलना मतलब से विभाजित करने के बाद, का उपयोग करें:

# Determine if range of vector is FP 0. 
zero_range <- function(x, tol = .Machine$double.eps^0.5) { 
    if (length(x) == 1) return(TRUE) 
    x <- range(x)/mean(x) 
    isTRUE(all.equal(x[1], x[2], tolerance = tol)) 
} 

यदि आप उपयोग कर रहे थे यह अधिक गंभीरता से, आप सीमा और माध्य की गणना करने से पहले लापता मूल्यों को हटाना चाहते हैं।

+0

मैंने इसे डिर्क की तुलना में तेज़ होने के लिए चुना है। मेरे पास लाखों तत्व नहीं हैं, लेकिन यह मेरे लिए थोड़ा तेज चलना चाहिए। – kmm

+0

@ केविन: जॉन के समाधान के बारे में क्या? यह हैडली की तुलना में ~ 10x तेज है और आपको सहनशीलता सेट करने की अनुमति देता है। क्या यह किसी अन्य तरीके से कमी है? –

+0

कृपया कुछ बेंचमार्किंग प्रदान करें - मैंने अभी जांच की है कि मेरा एक लाख वर्दी के वेक्टर के लिए समान है। – hadley

11

आप सभी दूसरों के लिए पहला तत्व की तुलना, प्रभावी रूप से भर में तुलना व्यापक द्वारा identical() और all.equal() उपयोग कर सकते हैं।

+1

हालांकि अक्षम रूप से अक्षम है ... (मेरे कंप्यूटर पर यह दस लाख संख्याओं के लिए लगभग 10 सेकंड लेता है) – hadley

+1

इसमें कोई संदेह नहीं है। ओपी हालांकि पूछताछ कर रहा था कि यह * सभी * किया जा सकता है। इसे अच्छी तरह से करना एक दूसरा कदम है। और आप जानते हैं कि मैं लूप के साथ कहां खड़ा हूं ... ;-) –

+7

वह लूप भयानक हैं? ;) – hadley

18
> isTRUE(all.equal(max(y) ,min(y))) 
[1] TRUE 
> isTRUE(all.equal(max(x) ,min(x))) 
[1] FALSE 
उसी तर्ज पर एक और

:

> diff(range(x)) < .Machine$double.eps^0.5 
[1] FALSE 
> diff(range(y)) < .Machine$double.eps^0.5 
[1] TRUE 
+0

पर बहुत तेज़ लगता है मुझे नहीं लगता कि यह बहुत छोटी संख्याओं के लिए बहुत अच्छा काम करता है: 'x <- seq (1, 10)/1e10' – hadley

+1

@ हैडली: ओपी ने एक समाधान के लिए कहा जो एक के विनिर्देश की अनुमति देगा सहिष्णुता, संभवतः क्योंकि वह बहुत छोटे अंतरों की परवाह नहीं करता था। all.equal का उपयोग अन्य सहनशीलता के साथ किया जा सकता है और ओपी इसे समझने लगता है। –

+1

मैंने स्वयं को स्पष्ट रूप से व्यक्त नहीं किया - मेरे उदाहरण में सबसे बड़ी और छोटी संख्याओं के बीच दस गुना सापेक्ष अंतर है। शायद यह कुछ है जिसे आप नोटिस करना चाहते हैं! मुझे लगता है कि डेटा की सीमा के सापेक्ष संख्यात्मक सहिष्णुता की गणना की जानी चाहिए - मैंने पहले यह नहीं किया है और इससे समस्याएं हुई हैं। – hadley

29

वे तो सभी संख्यात्मक मान रहे हैं, तो सहने अपने सहिष्णुता फिर ...

all(abs(y - mean(y)) < tol) 

आपकी समस्या का हल है।

संपादित करें:

इस पर देख रहे हैं, और अन्य उत्तर, और कुछ बातें निम्नलिखित DWin जवाब के रूप में दो बार के रूप में तेजी से बाहर के ऊपर आता है बेंचमार्किंग के बाद।

abs(max(x) - min(x)) < tol 

इसमें कुछ समय में आश्चर्यजनक रूप से तेजी से diff(range(x))diff के बाद से बहुत अलग हो - से और दो नंबर के साथ abs नहीं मानना ​​चाहिए। सीमा का अनुरोध करना न्यूनतम और अधिकतम प्राप्त करने के अनुकूल होना चाहिए। diff और range दोनों प्राचीन कार्य हैं। लेकिन समय झूठ नहीं बोलता है।

+0

क्या आप इसके द्वारा विभाजित करने की तुलना में माध्य को घटाने के सापेक्ष गुणों पर टिप्पणी कर सकते हैं? – hadley

+0

यह कम्प्यूटेशनल रूप से सरल है। सिस्टम के आधार पर, और कैसे आर संकलित और वेक्टरकृत किया जाता है, यह कम बिजली की खपत के साथ तेजी से पूरा किया जाएगा। साथ ही, जब आप इसका मतलब बताते हैं कि आपका परीक्षण परिणाम 1 के सापेक्ष है, तो घटाव के साथ यह 0 है, जो मुझे अच्छा लगता है। इसके अलावा, सहिष्णुता की एक और सीधी व्याख्या है। – John

+1

लेकिन यह इतना भी नहीं है कि विभाजन जटिल है क्योंकि श्रेणी को निकालने के लिए आवश्यक खोज और सॉर्ट एक सरल घटाव से अधिक कम्प्यूटेशनल रूप से महंगा है। मैंने इसका परीक्षण किया और उपर्युक्त कोड zero_range फ़ंक्शन हैडली से लगभग 10x तेज है (और आपका यहां सबसे तेज़ सही उत्तर है)। Dirk की तुलनात्मक कार्य क्रूरता से धीमा है। यह यहां सबसे तेज़ उत्तर है। – John

9

जब से मैं अधिक से अधिक इस सवाल सेवाएं लेने आते हैं, यहाँ एक Rcpp समाधान है कि आम तौर पर बहुत ज्यादा R समाधान के किसी भी तुलना में तेजी से हो सकता है अगर इस सवाल का जवाब वास्तव में FALSE है (क्योंकि यह पल बंद हो जाएगा यह एक बेमेल का सामना करना पड़ता) और यदि उत्तर TRUE है तो सबसे तेज़ आर समाधान के समान गति होगी। उदाहरण के लिए ओपी बेंचमार्क के लिए, system.time इस फ़ंक्शन का उपयोग करके बिल्कुल 0 पर घड़ियों।

library(inline) 
library(Rcpp) 

fast_equal = cxxfunction(signature(x = 'numeric', y = 'numeric'), ' 
    NumericVector var(x); 
    double precision = as<double>(y); 

    for (int i = 0, size = var.size(); i < size; ++i) { 
    if (var[i] - var[0] > precision || var[0] - var[i] > precision) 
     return Rcpp::wrap(false); 
    } 

    return Rcpp::wrap(true); 
', plugin = 'Rcpp') 

fast_equal(c(1,2,3), 0.1) 
#[1] FALSE 
fast_equal(c(1,2,3), 2) 
#[2] TRUE 
+1

यह अच्छा है और गति के लिए +1 है, लेकिन मुझे विश्वास नहीं है कि सभी तत्वों को पहले तत्व में तुलना करना काफी सही है। एक वेक्टर इस परीक्षण को पारित कर सकता है, फिर भी अधिकतम (x) और न्यूनतम (x) के बीच का अंतर परिशुद्धता से अधिक हो सकता है। उदाहरण के लिए 'fast_equal (c (2,1,3), 1.5) ' – dww

+0

@dww आप जो इंगित कर रहे हैं वह यह है कि जब आपके पास सटीक समस्याएं होती हैं तो तुलनात्मक नहीं होती है - यानी' a == b', 'b == यदि आप फ़्लोटिंग पॉइंट तुलना कर रहे हैं तो सी 'जरूरी नहीं है' == सी'। आप या तो इस समस्या से बचने के लिए तत्वों की संख्या से अपने परिशुद्धता को विभाजित कर सकते हैं, या 'min' और 'max' की गणना करने के लिए एल्गोरिदम को संशोधित कर सकते हैं और इसे रोकने की स्थिति के रूप में उपयोग कर सकते हैं। – eddi

2

आपको वास्तव में न्यूनतम, माध्य या अधिकतम उपयोग करने की आवश्यकता नहीं है। जॉन जवाब के आधार पर:

all(abs(x - x[[1]]) < tolerance) 
6

मैं इसके लिए विशेष रूप से एक समारोह में लिखा था, एक सदिश में न केवल तत्वों की जांच कर सकते हैं, लेकिन पता चल सके कि एक सूची के सभी तत्वों समान हैं की भी सक्षम। बेशक यह चरित्र वैक्टर और अन्य सभी प्रकार के वेक्टर अच्छी तरह से संभालता है। इसमें उचित त्रुटि प्रबंधन भी है।

all_identical <- function(x) { 
    if (length(x) == 1L) { 
    warning("'x' has a length of only 1") 
    return(TRUE) 
    } else if (length(x) == 0L) { 
    warning("'x' has a length of 0") 
    return(logical(0)) 
    } else { 
    TF <- vapply(1:(length(x)-1), 
       function(n) identical(x[[n]], x[[n+1]]), 
       logical(1)) 
    if (all(TF)) TRUE else FALSE 
    } 
} 

अब कुछ उदाहरणों को आजमाएं।

x <- c(1, 1, 1, NA, 1, 1, 1) 
all_identical(x)  ## Return FALSE 
all_identical(x[-4]) ## Return TRUE 
y <- list(fac1 = factor(c("A", "B")), 
      fac2 = factor(c("A", "B"), levels = c("B", "A")) 
     ) 
all_identical(y)  ## Return FALSE as fac1 and fac2 have different level order 
2

यहां न्यूनतम, अधिकतम चाल का उपयोग करने वाला एक विकल्प है लेकिन डेटा फ्रेम के लिए। उदाहरण में मैं कॉलम की तुलना कर रहा हूं लेकिन apply से मार्जिन पैरामीटर पंक्तियों के लिए 1 में बदला जा सकता है।

valid = sum(!apply(your_dataframe, 2, function(x) diff(c(min(x), max(x)))) == 0) 

valid == 0 तो सभी तत्वों को कर रहे हैं एक ही

18

क्यों बस विचरण का उपयोग नहीं:

var(x) == 0 

सभी x के तत्वों के बराबर हैं, तो आप 0 के विचरण मिल जाएगा ।

+3

'लंबाई (अद्वितीय (एक्स)) = 1' तेजी से दोगुनी हो जाती है, लेकिन 'var' terse है जो अच्छा है। – AdamO