2017-02-21 5 views
13

मुझे एक टेम्पलेट फ़ाइल test.txt पढ़ने की आवश्यकता है, सामग्री को संशोधित करें और फिर डिस्क पर लिखें foo`i`.in (i एक पुनरावृत्ति संख्या के साथ एक संशोधित प्रति)। चूंकि मुझे इस ऑपरेशन को बड़ी संख्या में करने की आवश्यकता है (दस लाख बार असामान्य नहीं होगा), कुशल समाधानों को प्राथमिकता दी जाएगी। टेम्पलेट फ़ाइल इस तरह है:कुछ संशोधनों के बाद एक टेम्पलेट फ़ाइल पढ़ना और इसे डिस्क पर लिखना

1 
bar.out 
     70.000000000000000 
     2.000000000000000 
     14.850000000000000 
    8000.000000000000000 
     120.000000000000000 
     60.000000000000000 
     0.197500000000000 
     0.197500000000000 
     2.310000000000000 
     0.200000000000000 
     0.000000000000000 
     1.000000000000000 
     0.001187700000000 
     22.000000000000000 
     1.400000000000000 
     1.000000000000000 
     0.010000000000000 
100 
     0.058600000000000 
     -0.217000000000000 
     0.078500000000000 
     -0.110100000000000 
30 
     500.000000000000000 
T 

मुझे बस कुछ पंक्तियों को संशोधित करने की आवश्यकता नहीं है। विशेष रूप से, मुझे bar.out को bar`i`.out संशोधित करने की आवश्यकता है जहां i एक पुनरावृत्ति सूचकांक है। मैं भी निम्न मान के साथ कुछ संख्यात्मक लाइनों संशोधित करने की आवश्यकता:

parameters <- data.frame(index = c(1:10, 13:16, 21:22), variable = c("P1", 
         "P2", "T1", "s", "D", "L", "C1", "C2", "VA", 
         "pw", "m", "mw", "Cp", "Z", "ff_N", "ff_M"), 
         value = c(65, 4, 16.85, 7900, 110, 60, 0.1975, .1875, 2.31, 
           0.2, 0.0011877, 22.0, 1.4, 1.0, 0.0785, -0.1101)) 

सभी अन्य लाइनों, एक ही रहना चाहिए अंतिम पंक्ति T भी शामिल है।

: इस प्रकार, यह मानते हुए मैंने पहली बार यात्रा पर हूँ, उम्मीद उत्पादन सामग्री (सही संख्या स्वरूप है महत्वपूर्ण नहीं है, जब तक parameters$value में सभी महत्वपूर्ण अंक foo1.in में शामिल किए गए हैं) होने foo1.in नामक एक पाठ फ़ाइल है
1 
bar1.out 
     65.000000000000000 
     4.000000000000000 
     16.850000000000000 
    7900.000000000000000 
     110.000000000000000 
     60.000000000000000 
     0.197500000000000 
     0.187500000000000 
     2.310000000000000 
     0.200000000000000 
     0.000000000000000 
     1.000000000000000 
     0.001187700000000 
     22.000000000000000 
     1.400000000000000 
     1.000000000000000 
     0.010000000000000 
100 
     0.058600000000000 
     -0.217000000000000 
     0.078500000000000 
     -0.110100000000000 
30 
     500.000000000000000 
T 

foo.in और bar.out संशोधित करना आसान है:

template <- "test.txt" 
infile <- "foo.in" 
string1 <- "bar.out" 
iteration <- 1 

# build string1 
elements <- strsplit(string1, "\\.")[[1]] 
elements[1] <- paste0(elements[1], iteration) 
string1 <- paste(elements, collapse = ".") 

# build infile name 
elements <- strsplit(infile, "\\.")[[1]] 
elements[1] <- paste0(elements[1], iteration) 
infile<- paste(elements, collapse = ".") 

अब, मैं टेम्पलेट फ़ाइल पढ़ सकते हैं और इरादा लाइनों केवल संशोधित करना चाहते हैं। मुझे पहली समस्या का सामना करना पड़ता है कि read.table केवल डेटा फ्रेम आउटपुट करता है। चूंकि मेरी टेम्पलेट फ़ाइल में एक ही कॉलम में संख्याएं और स्ट्रिंग हैं, अगर मैं read.table के साथ सभी फाइलें पढ़ता हूं तो मुझे एक वर्ण कॉलम (मुझे लगता है) प्राप्त होगा। मैं केवल सांख्यिक मानों मैं में दिलचस्पी रखता हूँ पढ़कर समस्या को दरकिनार:

# read template file 
    temp <- read.table(template, stringsAsFactors = FALSE, skip = 2, nrows = 23)$V1 
    lines_to_read <- temp[length(temp)] 

    # modify numerical parameter values 
    temp[parameters$index] <- parameters$value 

हालांकि, अब मैं foo1.in लिखने के लिए कैसे पता नहीं है। अगर मैं write.table का उपयोग करता हूं, तो मैं केवल डिस्क पर मैट्रिक्स या डेटाफ्रेम लिख सकता हूं, इसलिए मैं एक फ़ाइल नहीं लिख सकता जिसमें एक ही कॉलम में संख्याएं और स्ट्रिंग शामिल हैं। इसे कैसे हल किया जा सकता है?

संपादित करें मैं इस समस्या पर थोड़ी सी पृष्ठभूमि प्रदान करता हूं, यह बताने के लिए कि मुझे इस फ़ाइल को इतनी बार क्यों लिखना है। तो, विचार कंप्यूटर कोड (एक निष्पादन योग्य) के अंशांकन मानकों के लिए Bayesian अनुमान प्रदर्शन करना है। मूल विचार सरल है: आपके पास एक ब्लैक बॉक्स (वाणिज्यिक) कंप्यूटर कोड है, जो एक शारीरिक समस्या को अनुकरण करता है, उदाहरण के लिए एक फेम कोड। चलो इस कोड जो कहते हैं। एक इनपुट फ़ाइल को देखते हुए, जो भौतिक प्रणाली की प्रतिक्रिया के लिए भविष्यवाणी करता है। अब, मेरे पास इस प्रणाली की प्रतिक्रिया के लिए वास्तविक प्रयोगात्मक माप भी हैं। मैं जो के इनपुट के मूल्यों को ढूंढना चाहता हूं जैसे कि जो के आउटपुट और वास्तविक माप के बीच का अंतर कम हो गया है (वास्तव में चीजें काफी अलग हैं, लेकिन यह सिर्फ एक विचार देने के लिए है)। अभ्यास में, इसका मतलब है कि मुझे विभिन्न इनपुट फ़ाइलों के साथ कई बार जो चलाने की ज़रूरत है, और इसे इनपुट मानों को तुरंत ढूंढें जो जो की भविष्यवाणी और प्रयोगात्मक परिणामों के बीच "विसंगति" को कम करते हैं। संक्षेप में:

  1. मैं इनपुट फ़ाइलों की सामग्री को कई इनपुट (पाठ) उत्पन्न पहले से
  2. मैं नहीं जानता कि फाइल की जरूरत है। संख्यात्मक पैरामीटर को पुनरावृत्ति के दौरान एक पुनरावृत्ति के दौरान संशोधित किया जाता है।
  3. मुझे प्रत्येक इनपुट के लिए जो के आउटपुट को पढ़ने की भी आवश्यकता है। यह वास्तव में एक और समस्या है और मैं शायद इस बिंदु पर एक विशिष्ट प्रश्न लिखूंगा।

तो, जबकि जो एक वाणिज्यिक कोड है जिसके लिए मैं केवल निष्पादन योग्य (कोई स्रोत) है, बायेसियन अनुमान आर में किया जाता है, क्योंकि आर (और, यह महत्वपूर्ण कार्यों के लिए अजगर) के लिए उत्कृष्ट उपकरण है इस तरह के अध्ययन करते हैं।

+2

प्रत्येक पुनरावृत्ति पर डिस्क पर एक सादे पाठ फ़ाइल को पढ़ने और लिखना आर वस्तु में चीजों को संग्रहित करने की तुलना में अक्षम होगा। आपका अनुमान वेक्टर छोटा है, इसलिए मुझे नहीं लगता कि डिस्क पर डालने से सीमित रैम के बारे में चिंताओं को उचित ठहराया जाएगा। आप अनुकूलन करने के लिए कुछ गैर-आर चीज का उपयोग कर रहे हैं लेकिन आर में पुनरावृत्ति भाग को संभालने? ब्याज के लिए – Frank

+0

@ फ्रैंक धन्यवाद। यह थोड़ा जटिल है: मैं पृष्ठभूमि प्रदान करने के लिए सवाल संपादित करूंगा, उम्मीद है कि यह और स्पष्ट हो जाएगा। – DeltaIV

+2

क्या सभी इनपुट फ़ाइलों के लिए 'पैरामीटर' वैरिएबल समान है, या यह इनपुट फ़ाइल (या अन्यत्र) में किसी चीज़ के आधार पर बदलता है? प्रत्येक इनपुट फ़ाइल के लिए – r2evans

उत्तर

4

यह शायद Mustache जैसे टेम्पलेट भाषा का उपयोग करके सबसे आसान हल किया गया है, जिसे whisker पैकेज में आर में कार्यान्वित किया गया है।

नीचे एक उदाहरण दिखाया गया है कि यह आपके मामले में कैसे किया जा सकता है। उदाहरण के तौर पर, मैंने केवल पहले तीन चर और bar1.out को लागू किया। शेष चर लागू करना सरल होना चाहिए।

library(whisker) 


# You could also read the template in using readLines 
# template <- readLines("template.txt") 
# but to keep example selfsufficient, I included it in the code 
template <- "1 
bar{{run}}.out 
     {{P1}} 
     {{P2}} 
     {{T1}} 
    8000.000000000000000 
     120.000000000000000 
     60.000000000000000 
     0.197500000000000 
     0.197500000000000 
     2.310000000000000 
     0.200000000000000 
     0.000000000000000 
     1.000000000000000 
     0.001187700000000 
     22.000000000000000 
     1.400000000000000 
     1.000000000000000 
     0.010000000000000 
100 
     0.058600000000000 
     -0.217000000000000 
     0.078500000000000 
     -0.110100000000000 
30 
     500.000000000000000 
T" 


# Store parameters in a list 
parameters <- list(
    run = 1, 
    P1 = 65, 
    P2 = 4, 
    T1 = 16.85) 

for (i in seq_len(10)) { 
    # New set of parameters 
    parameters$run <- i 
    parameters$P1 <- sample(1:100, 1) 

    # Generate new script by rendering the template using paramers 
    current_script <- whisker.render(template, parameters) 
    writeLines(current_script, paste0("foo", i, ".in")) 

    # Run script 
    # system(...) 
} 

क्या मूंछें करता है (इस मामले में, और अधिक जटिल templating संभव है; जैसे सशर्त तत्वों) parameters सूची में संबंधित मान के साथ सभी {{<variable>}} की जगह है।

+0

यह बहुत आसान लग रहा है! @ R2evans पर मेरी टिप्पणियों में बताए गए कारणों के लिए, मैं स्ट्रिंग '" bar.out "को हार्ड-कोड नहीं करना चाहता हूं। मुझे लगता है कि मैं केवल दो चर, '{{outfile_prefix}} 'और' {{outfile_suffix}} 'जोड़कर अपना उदाहरण अनुकूलित कर सकता हूं। सही? – DeltaIV

+0

@ डेल्टाइव आप सही हैं, या आपके पास एक फ़ील्ड '{{outfile}}' हो सकती है और आर में फ़ाइल नाम का निर्माण हो सकता है। –

2

कुछ चालें मदद करनी चाहिए। आइए न्यूनतम कार्य उदाहरण का पालन करें जो - मुझे लगता है - आपकी समस्या की सभी सुविधाएं हैं।

1 
bar.out 
21 
31 
T 

आमतौर पर हम बल्कि वैक्टर से सूचियों के साथ काम जब आर विषम डेटा है: यहाँ फ़ाइल की सामग्री को संशोधित करने मैं कर रहा हूँ, tmp.txt हैं। लेकिन यहां मुझे एक चरित्र वेक्टर के साथ काम करना आसान लगता है। एक चरित्र वेक्टर में एक पाठ कनेक्शन से फ़ाइल पढ़ें:

a <- readLines("tmp.txt") 

जब से तुम प्रतिस्थापन मान हैं, उन्हें बदलना करते हैं जैसे आप तार की तरह। चूंकि ऐसा लगता है कि आपके पास तारों के नियंत्रण में प्रतिस्थापन है, चलिए उन नंबरों को बदल दें। हम आपके पास एक वेक्टर वेक्टर के न्यूमेरिक वेक्टर को कन्वर्ट करना चाहते हैं।

value <- c(21, 31) 
value <- as.character(value) 
a[3:4] <- value 

अब पुरानी फाइल को बदलने के लिए लिखें:

writeLines(a, "tmp.txt") 

अब फ्रैंक की टिप्पणी क्योंकि फ़ाइल मैं/हे यहाँ एक गंभीर अड़चन हो जाएगा प्रासंगिक है। रैम में यह सब करने के लिए यह बहुत तेज़ होगा।

time for i in {1..1000}; do ./run.R; done 

real 0m44.988s 
user 0m33.270s 
sys 0m5.170s 

समय रैखिक रूप से बढ़ने लग रहा था, इसलिए मुझे उम्मीद है कि दस लाख पुनरावृत्तियों में लगभग 16 घंटे लगेंगे। उस समय अधिकांश फ़ाइल पढ़ने और लिखना है। आप इसे गति देने का प्रयास कर सकते हैं, लेकिन मुझे नहीं लगता कि आप इसे तब तक बढ़ाने में सक्षम होंगे जब तक कि आप अपनी एमसीएमसी बाइनरी को राडाटा बाइनरी (या पंख फाइल) थूकने के लिए प्राप्त नहीं कर सकते।

+0

यदि आप आर के भीतर लूपिंग करते हैं तो यह कैसा प्रदर्शन करता है? मुझे लगता है कि आप उस समय अनुमान में आर स्टार्टअप को उलझन में डाल रहे हैं। – r2evans

+0

मुझे लगता है कि @ r2evans सही है - आप प्रत्येक पुनरावृत्ति के लिए एक आर स्क्रिप्ट लॉन्च कर रहे हैं। मुझे यकीन नहीं है, क्योंकि मुझे आर आंतरिक कार्यकलापों के बारे में पर्याप्त जानकारी नहीं है, लेकिन अगर मैं सिर्फ उस कोड को एक फ़ंक्शन के अंदर रखता हूं और प्रत्येक पुनरावृत्ति पर फ़ंक्शन कहलाता हूं, तो शायद यह तेज़ होगा। – DeltaIV

3

लगता है जैसे आपको कस्टम पढ़ने/लिखने के कार्यों की आवश्यकता है; आदर्श नहीं है, लेकिन जब आपके पास हाइब्रिड कॉलम जैसी चीज है, तो आप पहले से ही "साफ डेटा" से अलग हो जाते हैं (भले ही यह साफ है या नहीं)।

तीन कार्यों को सरल बनाने वाली मैं क्या लगता है कि आप की जरूरत है:

read_myfile <- function(x) { 
    # mostly during dev 
    if (file.exists(x)) x <- readLines(x) 
    if (length(x) == 1) x <- strsplit(rawfile, "\n")[[1]] 
    # find all left-aligned NAMED rows 
    hdrs <- grep("[A-Za-z]", x) 
    hdrs <- c(1, hdrs) # ensure the first "1" is preserved 
    dat <- mapply(function(a,b,x) if (b >= a) as.numeric(x[seq(a, b)]), 
       hdrs + 1, c(hdrs[-1] - 1, length(x)), list(x), 
       SIMPLIFY = FALSE) 
    names(dat) <- trimws(x[hdrs]) 
    dat 
} 

mod_myfile <- function(x, i, params) { 
    # sanity checks 
    stopifnot(
    is.list(x), 
    is.numeric(i), 
    is.data.frame(params), 
    all(c("index", "value") %in% colnames(params)) 
) 
    isbarout <- which(names(x) == "bar.out") 
    stopifnot(
    length(isbarout) == 1 
) 
    x$bar.out[ params$index ] <- params$value 
    names(x)[isbarout] <- sprintf("bar%i.out", i) 
    x 
} 

write_myfile <- function(x, ...) { 
    newdat <- unlist(unname(
    mapply(function(hdr, dat) c(hdr, sprintf("%25.15f ", dat)), 
      names(x), x, SIMPLIFY = TRUE) 
)) 
    writeLines(newdat, ...) 
} 

उपयोग सीधी-सपाट है। मैं एक ही चरित्र स्ट्रिंग इनपुट टेम्पलेट का अनुकरण करने के साथ शुरू करेंगे (पढ़ने समारोह एक चरित्र तार के साथ समान रूप से अच्छी तरह से काम करता है के रूप में यह एक फ़ाइल नाम के साथ करता है):

rawfile <- "1 
bar.out 
     70.000000000000000 
     2.000000000000000 
     14.850000000000000 
    8000.000000000000000 
     120.000000000000000 
     60.000000000000000 
     0.197500000000000 
     0.197500000000000 
     2.310000000000000 
     0.200000000000000 
     0.000000000000000 
     1.000000000000000 
     0.001187700000000 
     22.000000000000000 
     1.400000000000000 
     1.000000000000000 
     0.010000000000000 
100 
     0.058600000000000 
     -0.217000000000000 
     0.078500000000000 
     -0.110100000000000 
30 
     500.000000000000000 
T 
" 

, शुरू करने के लिए सिर्फ डेटा को पढ़ने:

dat <- read_myfile(rawfile) 
# dat <- read_myfile("file.in") 
str(dat) 
# List of 3 
# $ 1  : NULL 
# $ bar.out: num [1:24] 70 2 14.8 8000 120 ... 
# $ T  : NULL 

आप किसी भी तरह से निर्धारित करेंगे कि पैरामीटर बदलना चाहिए। मैं अपने पिछले डेटा का उपयोग करेंगे:

parameters <- data.frame(
    index = c(1:10, 13:16, 21:22), 
    variable = c("P1", "P2", "T1", "s", "D", "L", "C1", "C2", 
       "VA", "pw", "m", "mw", "Cp", "Z", "ff_N", "ff_M"), 
    value = c(65, 4, 16.85, 7900, 110, 60, 0.1975, .1875, 2.31, 
      0.2, 0.0011877, 22.0, 1.4, 1.0, 0.0785, -0.1101) 
) 

पहले पैरामीटर read_myfile से उत्पादन है, दूसरा वह इटरेटर है जिसे आप bar.out में बढ़ाना चाहते हैं; तीसरा यह parameters डेटा है।फ्रेम:

newdat <- mod_myfile(dat, 32, parameters) 
str(newdat) 
# List of 3 
# $ 1  : NULL 
# $ bar32.out: num [1:24] 65 4 16.9 7900 110 ... 
# $ T  : NULL 

और अब इसे लिखें।

write_myfile(newdat, sprintf("foo%d.in", 32)) 

मैं जब एक आर सत्र में चलाने के लिए कैसे @ GiovanniRighi के प्रदर्शन की तुलना करेंगे पता नहीं है, लेकिन इन फ़ाइलों के 1000 अपने कंप्यूटर पर कम से कम 7 सेकंड लेता है।

+0

वाह! जो कुछ भी मैं बाहर आ सकता था उससे कहीं अधिक उन्नत है :) हालांकि, मुझे आपके कोड को समझने में कुछ कठिनाइयों का सामना करना पड़ रहा है। 'Read_myfile' में: ए) 'अगर (लंबाई (x) == 1) का उद्देश्य क्या है ...'? बी) क्या आप समझा सकते हैं कि 'मैप्ली' क्या कर रहा है? 'Mod_myfile' में मैं 'bar.out" को कड़ी-कोडित नहीं करना चाहता हूं। मैं इसे सिर्फ एक डमी तर्क के रूप में जोड़ सकता हूं, है ना? यानी, 'mod_myfile <- फ़ंक्शन (x, i, पैरा, output_filename) {... '। 'Write_myfile' में: मुझे लगता है कि 'मैप्ली' का लक्ष्य सभी मानकों पर एक निश्चित प्रारूप को लागू करना है, है ना? – DeltaIV

+0

'read_myfile' में कोड की पहली दो पंक्तियां पूरी तरह कच्चे स्ट्रिंग के साथ-साथ फ़ाइल नाम स्वीकार करने में सुविधा के लिए हैं; यह परीक्षण में सहायक है, लेकिन उत्पादन में अप्रयुक्त है। 'Read' से पहले दो पंक्तियों (दोनों 'if') को हटाने के लिए स्वतंत्र महसूस करें।'Mod' के लिए: यह func फ़ाइल आउटपुट नहीं करता है, यह सिर्फ संरचना को संशोधित करता है। 'बार% d.out' में परिवर्तन फ़ाइल की दूसरी पंक्ति को प्रभावित करता है, फ़ाइल नाम नहीं। मैं आपके "अपेक्षित आउटपुट" का पालन कर रहा था। 'मैप्ली' लाइनें सूची में नामों के रूप में "सहेजे गए" अपरिवर्तनीय पुन: विलय करने की अनुमति दे रही हैं (उदा।, '1',' bar.out', और 'T')। – r2evans

+0

इसके अलावा, कोई कारण नहीं है कि आप * mod_' और 'write_myfile' को एक ही फ़ंक्शन में जोड़ नहीं सकते हैं; हेक, नए मानकों को निर्धारित करने के तरीके के आधार पर, आप सभी तीनों को एक ही फ़ंक्शन में जोड़ सकते हैं। मैंने उन्हें स्पष्टता और प्रदर्शन के लिए अलग कर दिया। ऐसा कहकर, रखरखाव और पठनीयता के लिए, यह अक्सर एक-उद्देश्य और ऑर्थोगोनल कार्यों को रखने के लिए बेहतर (लंबे समय तक) होता है: एक (छोटी) चीज़ करें, इसे अच्छी तरह से करें, और कुछ भी नहीं करें। – r2evans

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