本文介绍了读取一个模板文件并在修改后将其写入磁盘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我需要读取一个模板文件 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 $ b $ 100 0.058600000000000 -0.217000000000000 0.078500000000000 - 0.110100000000000 30 500.000000000000000 T 我不需要修改所有行,只是其中的一部分。具体来说,我需要修改 bar.out 到 bar`i`.out 其中 i 是一个迭代索引。我还需要用下面的值修改一些数字行: 参数< - data.frame(index = c(1 :10,13:16,21:22),变量= 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 。因此,假设我在第一次迭代中,预期输出是一个名为 foo1.in 的文本文件,其内容(确切数字格式只要参数$ value 中的所有有效位都包含在 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 $ 0.058600000000000 -0.217000000000000 0.078500000000000 -0.110100000000000 30 500.000000000000000 T 修改 foo.in 和 bar.out 很简单: template infile< - foo.in string1< - bar.out iteration< 1 $ b $#build string1 元素< - strsplit(string1,\\\。)[[1]] elements [1]< - paste0(元素[1],迭代) string1< - paste(elements,collapse =。) #构建infile名称元素< - strsplit(infile, (元素[1],迭代) infile< - paste(elements,collapse =。)$ { elements [1] b $ b 现在,我想读取模板文件并只修改预定的行。我面对的第一个问题是 read.table 只输出一个数据帧。由于我的模板文件包含数字和字符串在同一列,如果我阅读所有文件与 read.table 我会得到一个字符列(我猜)。我只是通过阅读我感兴趣的数值来避免这个问题: $ p $ #读取模板文件 temp< ; - read.table(template,stringsAsFactors = FALSE,skip = 2,nrows = 23)$ V1 lines_to_read< - temp [length(temp)] #修改数字参数值 temp [parameters $ index]< - parameters $ value 但是,不知道如何写 foo1.in 。如果我使用 write.table ,我只能写矩阵或数据框到磁盘,所以我不能在同一列写一个包含数字和字符串的文件。我该如何解决这个问题? 编辑我在这个问题上提供了一些背景知识,解释了为什么我需要这么多次写这个文件。所以,这个想法是对计算机代码(可执行文件)的校准参数进行贝叶斯推断。基本思想很简单:你有一个黑盒(商业)计算机代码,它模拟一个物理问题,例如一个FEM代码。我们称这个代码为Joe。给定一个输入文件,Joe输出一个预测物理系统的响应。现在,我也有实际的实验测量这个系统的响应。我想找到乔的输入值,使得乔的输出和实际测量之间的差异最小化(事实上情况完全不同,但这只是一个想法)。实际上,这意味着我需要使用不同的输入文件多次运行Joe,并且迭代地找到可以减少Joe的预测和实验结果之间差异的输入值。简而言之: 我需要生成许多输入(文本)文件 提前知道输入文件的内容。在优化过程中,数值参数会以迭代方式被修改。 我还需要读取每个输入的Joe输出。这实际上是另一个问题,我可能会写一个关于这一点的具体问题。 所以,虽然乔是商业代码我只有可执行文件(没有源代码),贝叶斯推理是在R中执行的,因为R(以及它对于什么很重要,Python)有很好的工具来执行这种研究。 >小胡子,在R的 whisker 包中实现。 下面是一个例子,展示了如何在你的情况下完成这项工作。作为一个例子,我只实现了前三个变量和 bar1.out 。实施其余的变量应该是直截了当的。 library(whisker) #也可以使用readLine #template< - readLines(template.txt)#但为了保持示例自足,我将它包含在代码 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 #存储参数rs 参数< - list( run = 1, P1 = 65, P2 = 4, T1 = 16.85) for(i in seq_len(10)){#新的一组参数参数$ run< - 参数$ P1< - sample(1:100, 1) #通过使用参数渲染模板来生成新脚本 current_script< - whisker.render(template,parameters) writeLines(current_script,paste0(foo, i,.in)) #运行脚本#system(...)} 什么胡须(在这种情况下,更复杂的模板是可能的;例如条件元素)将 {{< variable>}} 替换为参数列表中的相应值。 I need to read a template file test.txt, modify the contents and then write to disk a modified copy with name foo`i`.in (i is an iteration number). Since I need to perform this operation a large number of times (a million times wouldn't be uncommon), efficient solutions would be preferred. The template file is like this: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 I don't need to modify all lines, just some of them. Specifically, I need to modify bar.out to bar`i`.out where i is an iteration index. I also need to modify some numeric lines with the following values: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))All the other lines must remain the same, including the last line T. Thus, assuming I'm at the first iteration, the expected output is a text file named foo1.in having the content (the exact number format is not important, as long as all the significant digits in parameters$value are included 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 Modifying foo.in and bar.out is easy:template <- "test.txt"infile <- "foo.in"string1 <- "bar.out"iteration <- 1# build string1elements <- strsplit(string1, "\\.")[[1]]elements[1] <- paste0(elements[1], iteration)string1 <- paste(elements, collapse = ".")# build infile nameelements <- strsplit(infile, "\\.")[[1]]elements[1] <- paste0(elements[1], iteration)infile<- paste(elements, collapse = ".")Now, I would like to read the template file and modify only the intended lines. The first problem I face is that read.table only outputs a data frame. Since my template file contains numbers and strings in the same column, if I read all the file with read.table I would obtain a character column (I guess). I circumvent the problem by reading only the numeric values I'm interested in: # 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$valueHowever, now I don't know how to write foo1.in. If I use write.table, I can only write matrices or dataframes to disk, so I can't write a file which contains numbers and strings in the same column. How can I solve this? EDIT I provide a bit of background on this problem, to explain why I need to write this file so many times. So, the idea is to perform Bayesian inference for the calibration parameters of a computer code (an executable). The basic idea is simple: you have a black box (commercial) computer code, which simulates a physical problem, for example a FEM code. Let's call this code Joe. Given an input file, Joe outputs a prediction for the response of a physical system. Now, I also have actual experimental measurements for the response of this system. I would like to find values of Joe's inputs such that the difference between Joe's outputs and the real measurements is minimized (actually things are quite different, but this is just to give an idea). In practice, this means that I need to run Joe many times with different input files, and iteratively find the input values which reduce the "discrepancy" between Joe's prediction and experimental results. In short:I need to generate many input (text) filesI don't know in advance the contents of the input files. The numerical parameters are modified during the optimization in an iterative way.I also need to read Joe's output for each input. This is actually another problem and I'll probably write a specific question on this point.So, while Joe is a commercial code for which I only have the executable (no source), the Bayesian inference is performed in R, because R (and, for what it matters, Python) have excellent tools to perform this kind of study. 解决方案 This is probably easiest solved using a template language, such as Mustache, which is implemented in R in the whisker package.Below is an example showing how this can be done in your case. As an example, I only implemented the first three variables and the bar1.out. Implementing the remaining variables should be straightforward. 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 codetemplate <- "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 listparameters <- 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(...)}What mustache does (in this case; more complex templating is possible; e.g. conditional elements) is replace all {{<variable>}} with the corresponding value in the parameters list. 这篇关于读取一个模板文件并在修改后将其写入磁盘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 09-17 18:00