2011-07-12 11 views
84

मैं दिनांक वेक्टर में हेरफेर करने के लिए ifelse() फ़ंक्शन का उपयोग कर रहा हूं। मुझे उम्मीद है कि परिणाम Date वर्ग का होगा, और numeric वेक्टर प्राप्त करने के लिए आश्चर्यचकित था।ifelse() को तारीख वस्तुओं को संख्यात्मक वस्तुओं में बदलने से कैसे रोकें

dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05')) 
dates <- ifelse(dates == '2011-01-01', dates - 1, dates) 
str(dates) 

यह विशेष रूप से आश्चर्य की बात है क्योंकि पूरी सदिश भर में कार्रवाई करते एक Date ऑब्जेक्ट है: यहाँ एक उदाहरण है।

dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05')) 
dates <- dates - 1 
str(dates) 

मैं Date वैक्टर पर संचालित करने के लिए कुछ अन्य फ़ंक्शन का उपयोग किया जाना चाहिए? यदि हां, तो क्या कार्य? यदि नहीं, तो इनपुट के समान प्रकार के वेक्टर को वापस करने के लिए मैं ifelse को कैसे बल दूं?

ifelse के लिए सहायता पृष्ठ इंगित करता है कि यह एक सुविधा है, एक बग नहीं है, लेकिन मैं अभी भी आश्चर्यजनक व्यवहार के लिए एक स्पष्टीकरण खोजने के लिए संघर्ष कर रहा हूं।

+4

अब एक समारोह 'if_else()' dplyr पैकेज है कि 'ifelse' के लिए स्थानापन्न कर सकते हैं दिनांक वस्तुओं की सही वर्गों को बनाए रखते हुए में है - यह हालिया उत्तर के रूप में [नीचे पोस्ट किया गया है) (http://stackoverflow.com/a/38093096/4470365)। मैं यहां इस पर ध्यान दे रहा हूं क्योंकि यह एक समस्या प्रदान करके इस समस्या को हल करता है जो यूनिट-परीक्षण और एक सीआरएएन पैकेज में प्रलेखित है, कई अन्य उत्तरों के विपरीत (इस टिप्पणी के रूप में) इसके आगे रैंक किए गए थे। –

उत्तर

51

आप dplyr::if_else उपयोग कर सकते हैं।

dplyr 0.5.0 release notes से: "[if_else] सख्त अर्थ विज्ञान कि ifelse() है:। true और false तर्क एक ही प्रकार का होना चाहिए यह एक कम आश्चर्य की बात वापसी प्रकार देता है, और दिनांकों तरह S3 वैक्टर को बरकरार रखता है"।

library(dplyr) 
dates <- if_else(dates == '2011-01-01', dates - 1, dates) 
str(dates) 
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05" 
+1

निश्चित रूप से उपयोगी है भले ही यह मुझे एक चेकमार्क ढीला कर दे। सहायता पृष्ठ का वर्तमान संस्करण यह नहीं कहता कि कारक तर्कों से क्या अपेक्षा की जानी चाहिए। मेरा वोट एक कारक रिटर्न ऑब्जेक्ट के लिए होगा जिसमें ऐसे स्तर थे जो 'सत्य' और 'झूठे' स्तर के स्तर का संघ थे। –

+1

क्या 'if_else' के तर्कों में से एक है एनए?मैंने तार्किक 'NA_' विकल्पों का प्रयास किया है और कुछ भी चिपक रहा है और मुझे विश्वास नहीं है कि' NA_double_' – roarkz

+2

@Zak एक संभावना है 'एनए' में 'एनए' को लपेटना। – Henrik

55

यह ifelse के दस्तावेज मूल्य से संबंधित है:

एक ही लंबाई का एक वेक्टर और विशेषताएँ test के रूप में और डेटा मान yes या no के मूल्यों से (आयाम और "class" सहित)। yes से लिया गया कोई भी मान समायोजित करने के लिए उत्तर के मोड को तार्किक से जोड़ा जाएगा और फिर no से लिया गया कोई भी मान समायोजित किया जाएगा।

इसके प्रभावों पर उबला हुआ, ifelse कारकों को उनके स्तर खो देते हैं और तिथियां अपनी कक्षा खो देती हैं और केवल उनका मोड ("न्यूमेरिक") बहाल किया जाता है। ऐसा करें:

safe.ifelse <- function(cond, yes, no){ class.y <- class(yes) 
            X <- ifelse(cond, yes, no) 
            class(X) <- class.y; return(X)} 

safe.ifelse(dates == '2011-01-01', dates - 1, dates) 
# [1] "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05" 

बाद में एक नोट:

dates[dates == '2011-01-01'] <- dates[dates == '2011-01-01'] - 1 
str(dates) 
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05" 

आप एक safe.ifelse बना सकते हैं मुझे लगता है कि हैडली डेटा को आकार देने संकुल की magrittr/dplyr/tidyr परिसर में एक if_else का निर्माण किया है ।

+30

कुछ और अधिक सुरुचिपूर्ण संस्करण: 'safe.ifelse <- फ़ंक्शन (cond, yes, no) संरचना (ifelse (cond, yes, no), class = class (yes))' – hadley

+5

अच्छा। क्या आप कोई कारण देखते हैं कि यह डिफ़ॉल्ट व्यवहार क्यों नहीं है? –

+7

नहीं, मुझे समझ में नहीं आ रहा है कि ifelse जिस तरह से काम करता है। – hadley

12

डीडब्ल्यूएन की व्याख्या स्पॉट पर है। मैं fiddled और थोड़ी देर के लिए इस के साथ लड़ा से पहले मैंने महसूस किया मैं बस ifelse बयान के बाद वर्ग के लिए मजबूर कर सकता है:

dates <- as.Date(c('2011-01-01','2011-01-02','2011-01-03','2011-01-04','2011-01-05')) 
dates <- ifelse(dates=='2011-01-01',dates-1,dates) 
str(dates) 
class(dates)<- "Date" 
str(dates) 

पहले तो यह मेरे लिए थोड़ा "hackish" महसूस किया। लेकिन अब मैं इसे निष्पादन रिटर्न के लिए भुगतान करने के लिए एक छोटी सी कीमत के रूप में सोचता हूं जो मुझे ifelse() से मिलता है। इसके अलावा यह अभी भी एक लूप से बहुत अधिक संक्षिप्त है।

5

सुझाई गई विधि कारक कॉलम के साथ काम नहीं करती है।

safe.ifelse <- function(cond, yes, no) { 
    class.y <- class(yes) 
    if (class.y == "factor") { 
    levels.y = levels(yes) 
    } 
    X <- ifelse(cond,yes,no) 
    if (class.y == "factor") { 
    X = as.factor(X) 
    levels(X) = levels.y 
    } else { 
    class(X) <- class.y 
    } 
    return(X) 
} 

वैसे: ईद इस सुधार का सुझाव देना चाहते ifelse महान शक्ति के साथ बेकार है ... बड़ी जिम्मेदारी, 1x1 मैट्रिक्स और/या numerics [जब वे उदाहरण के लिए जोड़ा जाना चाहिए] है की यानी प्रकार रूपांतरण आता है मेरे लिए ठीक है लेकिन ifelse में इस प्रकार का रूपांतरण स्पष्ट रूप से अवांछित है।मैं अब बहुत ही ifelse कई बार 'बग' से टकरा गई और यह सिर्फ :-(

अपने समय चोरी परिवार कल्याण

रहती
+0

यह एकमात्र समाधान है जो कारकों के लिए मेरे लिए काम करता है। – bshor

+0

मैंने सोचा होगा कि लौटाए जाने वाले स्तर 'हां 'और' नहीं' के स्तर का संघ होंगे और आप पहले यह देखने के लिए जांच करेंगे कि वे दोनों कारक थे। आपको शायद चरित्र में परिवर्तित करने की आवश्यकता होगी और फिर "संघीय" -लेवल के साथ फिर से वापसी की आवश्यकता होगी। –

5

@ फैबियन-वर्नर द्वारा प्रदान की जवाब महान है, लेकिन वस्तुओं कई हो सकता है वर्गों, और "कारक" जरूरी class(yes) द्वारा लौटाए गए पहले एक नहीं हो सकता है, इसलिए मैं सभी वर्ग विशेषताओं की जांच करने के लिए इस छोटा सा संशोधन का सुझाव:

safe.ifelse <- function(cond, yes, no) { 
     class.y <- class(yes) 
     if ("factor" %in% class.y) { # Note the small condition change here 
     levels.y = levels(yes) 
     } 
     X <- ifelse(cond,yes,no) 
     if ("factor" %in% class.y) { # Note the small condition change here 
     X = as.factor(X) 
     levels(X) = levels.y 
     } else { 
     class(X) <- class.y 
     } 
     return(X) 
    } 

मैं भी एक जोड़ने के लिए आर विकास टीम के साथ एक अनुरोध भेज दिया है आधार :: ifelse() के लिए प्रलेखित विकल्प, उपयोगकर्ता चयन के आधार पर गुणों को संरक्षित करता है, जिनके गुणों को संरक्षित किया जाता है । अनुरोध यहां है: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=16609 - इस आधार पर इसे पहले से ही "WONTFIX" के रूप में फ़्लैग किया गया है कि यह हमेशा ऐसा ही रहा है, लेकिन मैंने एक अनुवर्ती तर्क प्रदान किया है कि क्यों एक साधारण जोड़ा बहुत से आर को बचा सकता है उपयोगकर्ता सिरदर्द। शायद उस बग थ्रेड में आपका "+1" आर कोर टीम को दूसरा रूप लेने के लिए प्रोत्साहित करेगा।

संपादित करें: यहां एक बेहतर संस्करण है जो उपयोगकर्ता को निर्दिष्ट करने के लिए अनुमति देता है कि कौन से गुण "cond" (डिफ़ॉल्ट ifelse() व्यवहार), "हां", ऊपर दिए गए कोड के अनुसार व्यवहार, या "नहीं" ऐसे मामलों में जहां "नहीं" मूल्य की विशेषताओं में बेहतर हैं के लिए:

safe_ifelse <- function(cond, yes, no, preserved_attributes = "yes") { 
    # Capture the user's choice for which attributes to preserve in return value 
    preserved   <- switch(EXPR = preserved_attributes, "cond" = cond, 
                   "yes" = yes, 
                   "no" = no); 
    # Preserve the desired values and check if object is a factor 
    preserved_class  <- class(preserved); 
    preserved_levels <- levels(preserved); 
    preserved_is_factor <- "factor" %in% preserved_class; 

    # We have to use base::ifelse() for its vectorized properties 
    # If we do our own if() {} else {}, then it will only work on first variable in a list 
    return_obj <- ifelse(cond, yes, no); 

    # If the object whose attributes we want to retain is a factor 
    # Typecast the return object as.factor() 
    # Set its levels() 
    # Then check to see if it's also one or more classes in addition to "factor" 
    # If so, set the classes, which will preserve "factor" too 
    if (preserved_is_factor) { 
     return_obj   <- as.factor(return_obj); 
     levels(return_obj) <- preserved_levels; 
     if (length(preserved_class) > 1) { 
      class(return_obj) <- preserved_class; 
     } 
    } 
    # In all cases we want to preserve the class of the chosen object, so set it here 
    else { 
     class(return_obj) <- preserved_class; 
    } 
    return(return_obj); 

} # End safe_ifelse function 
+1

'विरासत (वाई," कारक ")'% वर्ग में '" कारक "% से" अधिक सही "हो सकता है। –

+0

दरअसल। 'विरासत' सबसे अच्छा हो सकता है। –

4

कारण यह काम नहीं करेगा क्योंकि, ifelse() फ़ंक्शन मूल्यों को कारकों में परिवर्तित करता है। एक अच्छा कामकाज इसे मूल्यांकन करने से पहले इसे वर्णों में परिवर्तित करना होगा।

dates <- as.Date(c('2011-01-01','2011-01-02','2011-01-03','2011-01-04','2011-01-05')) 
dates_new <- dates - 1 
dates <- as.Date(ifelse(dates =='2011-01-01',as.character(dates_new),as.character(dates))) 

इस आधार आर से अलग किसी भी पुस्तकालय की आवश्यकता नहीं होगी

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