2013-07-24 3 views
8

हाल ही में, मैंने अपने वर्कस्पेस में factor=1 ऑब्जेक्ट बनाया है, यह नहीं जानते कि base पैकेज में factor कोई फ़ंक्शन है।समानांतर प्लीयर में अजीब पर्यावरण व्यवहार

मैं क्या करने का इरादा

library(plyr) 
library(foreach) 
library(doParallel) 

workers <- makeCluster(2) 
registerDoParallel(workers,cores=2) 

factor=1 

llply(
    as.list(1:2), 
    function(x) factor*x, 
    .parallel = TRUE, 
    .paropts=list(.export=c("factor")) 
    ) 

लेकिन यह एक त्रुटि में परिणाम है कि मुझे इतना समय लगा समझने के लिए एक समानांतर पाश के भीतर चर factor उपयोग करने के लिए किया गया था, उदाहरण के लिए,। जैसा कि लगता है, plyr अपने पर्यावरण exportEnv में ऑब्जेक्ट factor बनाता है, लेकिन उपयोगकर्ता द्वारा प्रदान की गई वस्तु के बजाय base::factor का उपयोग करता है। हम llply के उत्पादन का निरीक्षण तो निम्न उदाहरण

llply(
    as.list(1:2), 
    function(x) { 
    function_env=environment(); 
    global_env=parent.env(function_env); 
    export_env=parent.env(global_env); 
    list(
     function_env=function_env, 
     global_env=global_env, 
     export_env=export_env, 
     objects_in_exportenv=unlist(ls(envir=export_env)), 
     factor_found_in_envs=find("factor"), 
     factor_in_exportenv=get("factor",envir=export_env) 
    ) 
    }, 
    .parallel = TRUE, 
    .paropts=list(.export=c("factor")) 
) 

stopCluster(workers) 

देखो, हम देखते हैं कि लाइन factor_in_exportenv=get("factor",envir=export_env)1 (उपयोगकर्ता द्वारा प्रदान की वस्तु से सम्बंधित) लेकिन base::factor के समारोह परिभाषा वापस नहीं करता है।

प्रश्न 1) मैं इस व्यवहार को कैसे समझ सकता हूं? मुझे उम्मीद है कि आउटपुट 1 होगा।

प्रश्न 2) क्या R से चेतावनी प्राप्त करने का कोई तरीका है यदि मैं किसी ऑब्जेक्ट को नया मान निर्दिष्ट करता हूं जो पहले से ही किसी अन्य पैकेज में परिभाषित किया गया था (जैसे मेरे मामले factor)?

उत्तर

0

पहले, मैं नोट करना चाहिए कि त्रुटि दूर हो जाता है तो एक-दूसरे चर के नाम का base में नहीं किया जाता है का उपयोग करता है - उदाहरण के लिए, अगर हम factor के बजाय a का उपयोग करें। यह स्पष्ट रूप से इंगित करता है कि llplybase::factor (एक फ़ंक्शन) factor (मान 1 के साथ परिवर्तनीय) से पहले अपने खोज पथ के साथ पाता है। मैं, llply का एक सरलीकृत संस्करण है, अर्थात के साथ इस मुद्दे को दोहराने की कोशिश की है

library(plyr) 
library(foreach) 
library(doParallel) 

workers <- makeCluster(2) 
registerDoParallel(workers,cores=2) 

factor=1 

llply_simple=function(.x,.fun,.paropts) { 
    #give current environment a name 
    tmpEnv=environment() 
    attr(tmpEnv,"name")="llply_simple_body" 
    #print all enclosing envirs of llply_simple_body (see def of allEnv below) 
    print(allEnv(tmpEnv)) 
    cat("------\nResults:\n") 
    do.ply=function(i) { 
    .fun(i) 
    } 
    fe_call <- as.call(c(list(quote(foreach::foreach), i = .x), .paropts)) 
    fe <- eval(fe_call) 
    foreach::`%dopar%`(fe, do.ply(i)) 
} 

llply_simple एक पुनरावर्ती सहायक समारोह (allEnv) है कि सभी संलग्न वातावरण के माध्यम से लूप का उपयोग करता है। यह सब पर्यावरण नाम के साथ एक वेक्टर रिटर्न

allEnv=function(x) { 
    if (environmentName(x)=="R_EmptyEnv") { 
    return(environmentName(x)) 
    } else { 
    c(environmentName(x),allEnv(parent.env(x))) 
    } 
} 

यह दिलचस्प सरलीकृत समारोह वास्तव में काम करता है के रूप में उम्मीद

llply_simple(1:2,function(x) x*factor,list(.export="factor")) 
#[1] "llply_simple_body" "R_GlobalEnv"  "package:doParallel" "package:parallel" 
#[5] "package:iterators" "package:foreach" "package:plyr"  "tools:rstudio"  
#[9] "package:stats"  "package:graphics" "package:grDevices" "package:utils"  
#[13] "package:datasets" "package:methods" "Autoloads"   "base"    
#[17] "R_EmptyEnv" 
#-------- 
#Results:   
#[[1]] 
#[1] 1 
# 
#[[2]] 
#[1] 2 

(यानी, 1 और परिणाम के रूप में 2 देता है) कि तो साथ llply_simple का केवल महत्वपूर्ण अंतर पूर्ण plyr::llply फ़ंक्शन का सम्मान यह है कि उत्तरार्द्ध एक पैकेज से संबंधित है। आइए पैकेज में llply_simple स्थानांतरित करने का प्रयास करें।

package.skeleton(list=c("llply_simple","allEnv"),name="llplyTest") 
unlink("./llplyTest/DESCRIPTION") 
devtools::create_description("./llplyTest", 
          extra=list("devtools.desc.author"='"T <[email protected]>"')) 
tmp=readLines("./llplyTest/man/llply_simple.Rd") 
tmp[which(grepl("\\\\title",tmp))+1]="Test1" 
writeLines(tmp,"./llplyTest/man/llply_simple.Rd") 
tmp=readLines("./llplyTest/man/allEnv.Rd") 
tmp[which(grepl("\\\\title",tmp))+1]="Test2" 
writeLines(tmp,"./llplyTest/man/allEnv.Rd") 
devtools::install("./llplyTest") 

और अब हमारे नए पैकेज से llplyTest::llply_simple निष्पादित करने के लिए llplyTest

library(llplyTest) 
llplyTest::llply_simple(1:2,function(x) x*factor,list(.export="factor")) 
#[1] "llply_simple_body" "llplyTest"   "imports:llplyTest" "base"    
#[5] "R_GlobalEnv"  "package:doParallel" "package:parallel" "package:iterators" 
#[9] "package:foreach" "package:plyr"  "tools:rstudio"  "package:stats"  
#[13] "package:graphics" "package:grDevices" "package:utils"  "package:datasets" 
#[17] "package:methods" "Autoloads"   "base"    "R_EmptyEnv" 
#------ 
#Results: 
#Error in do.ply(i) : 
# task 1 failed - "non-numeric argument to binary operator" 

अचानक हम 2013 से अपने मूल प्रश्न में के रूप में ही त्रुटि मिलती है सब के सब तो इस मुद्दे को स्पष्ट रूप से बुला से जुड़ा है कोशिश एक पैकेज से समारोह। आइए allEnv के आउटपुट पर नज़र डालें: यह मूल रूप से उन वातावरणों का अनुक्रम देता है जो llpy_simple और llplyTest::llpy_simple निर्यात किए जाने वाले चरों को देखने के लिए उपयोग करते हैं। वास्तव में यह foreach कि निर्यात करता है और एक करता है, तो क्यों foreach वास्तव में पर्यावरण कि हम llply_simple_body नामित साथ शुरू होता है, foreach::%dopar%, foreach:::getDoPar और foreach:::.foreachGlobals$fun के स्रोत कोड को देखो और envir तर्क के मार्ग का अनुसरण करने के लिए दिलचस्पी है।

अब हम स्पष्ट रूप से देख सकते हैं कि गैर-पैकेज संस्करण में llplyTest::llpy_simple से भिन्न खोज अनुक्रम है और पैकेज-संस्करण base में factor मिलेगा!

1

लवली फ़ंक्शन हुड के नीचे "foreach" को कॉल करता है। पूर्वानुमान का मूल्यांकन करने के लिए Foreach "parant.frame()" का उपयोग करता है। Llply के मामले में parant.frame क्या है? यह लवली का कार्य वातावरण है, जिसमें कारक परिभाषित नहीं है।

llply का उपयोग करने के बजाय, सीधे foreach का उपयोग क्यों नहीं करें?

library(plyr) 
library(foreach) 
library(doParallel) 

workers <- makeCluster(2) 
registerDoParallel(workers,cores=2) 

factor=1 
foreach(x=1:2) %dopar% {factor*x} 

नोट, आपको .export पैरामीटर की भी आवश्यकता नहीं है, क्योंकि यह स्वचालित रूप से इस मामले में ऐसा करता है।

+0

आपके इनपुट के लिए धन्यवाद। यहां समस्या मूल्यांकन के पर्यावरण का इतना अधिक नहीं है, लेकिन निर्यात किए जाने वाले चर खोजने के लिए पर्यावरण 'foreach' किस प्रकार उपयोग करता है। समस्या दूर हो जाती है यदि कोई एक वैरिएबल नाम का उपयोग करता है जिसका उपयोग 'आधार' में नहीं किया जाता है, तो 'कारक' के बजाय 'a' कहें। मुझे पता है कि मैं सीधे 'foreach' का उपयोग कर सकता हूं (जैसे आपने किया और मैं आजकल ज्यादातर करता हूं) और यह कि त्रुटि तब खत्म हो जाती है। लेकिन 2013 में वापस मैं एक भारी 'प्लीयर' उपयोगकर्ता था और इस त्रुटि ने मुझे काफी परेशान किया। तो, मैं जिज्ञासा से इसे हल करना चाहता था। – cryo111

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