R 脚本中的 here() 问题

2023-11-27

R 脚本中的问题

我试图了解here()如何以可移植的方式工作。找到了:看看下面有什么工作最终答案 - TL;DR- 底线,here()运行 a 并不是真的那么有用script.R从命令行。

我在 JBGruber 的帮助下理解它的方式:here()查找项目的根目录(例如,RStudio 项目、Git 项目或使用 .here 文件定义的其他项目)从当前工作目录开始并向上移动,直到找到任何项目。如果没有找到任何内容,它将回退到使用完整的工作目录。如果由 cron 运行脚本,则默认为我的主目录。当然,可以通过 cron 命令将目录作为参数传递,但这相当麻烦。下面的答案提供了很好的解释,我在“最终答案部分”总结了我发现最直接有用的内容。但别误会,尼古拉的回答非常好,也很有帮助。

最初的目标- 编写一组R脚本,包括R-markdown.Rmd这样我就可以压缩目录,发送给其他人,然后它就可以在他们的计算机上运行。可能在非常低端的计算机上 - 例如 RaspberryPi 或运行 Linux 的旧硬件。

状况:

  • 可以通过命令行运行Rscript
  • 如上所述,但通过安排cron
  • 设置工作目录的主要方法是set_here()- 从控制台执行一次,然后该文件夹是可移植的,因为.here文件包含在压缩目录中。
  • 不需要Rstudio- 因此不想做 R 项目
  • can也可以交互地运行Rstudio(发展)
  • 可以从执行shiny(我认为只要满足上述条件就可以了)

我特别不想创建 Rstudio 项目,因为在我看来,它需要安装和使用 Rstudio,但我希望我的脚本尽可能可移植并在低资源、无头平台上运行。

示例代码:

让我们假设工作目录是myGoodScripts如下:

/Users/john/src/myGoodScripts/

当开始开发时,我会转到上面的目录setwd()并执行set_here()创造.here文件。然后有2个脚本dataFetcherMailer.R, dataFetcher.Rmd和一个子目录bkp:

dataFetcherMailer.R

library(here)
library(knitr)

basedir <- here()
# this is where here should give path to .here file

rmarkdown::render(paste0(basedir,"/dataFetcher.Rmd"))

# email the created report
# email_routine_with_gmailr(paste0(basedir,"dataFetcher.pdf"))
# now substituted with verification that a pdf report was created
file.exists(paste0(basedir,"/dataFetcher.pdf"))

数据获取器.Rmd

---
title: "Data collection control report"
author: "HAL"
date: "`r Sys.Date()`"
output: pdf_document
---

```{r setup, include=FALSE}
library(knitr)
library(here)

basedir <- here()

# in actual program this reads data from a changing online data source
df.main <- mtcars

# data backup
datestamp <- format(Sys.time(),format="%Y-%m-%d_%H-%M")
backupName <- paste0(basedir,"/bkp/dataBackup_",datestamp,"csv.gz")
write.csv(df.main, gzfile(backupName))
```

# This is data collection report

Yesterday's data total records: `r nrow(df.main)`. 

The basedir was `r basedir`

The current directory is `r getwd()`

The here path is `r here()`

我猜报告中的最后 3 行是匹配的。即使getwd()与其他两个不匹配,应该没关系,因为here()将确保绝对基本路径。

Errors

当然 - 上面的方法是行不通的。仅当我执行时才有效Rscript ./dataFetcherMailer.R来自同一个myGoodScripts/目录。

My aim是了解如何执行脚本,以便相对于脚本位置解析相对路径,并且可以独立于当前工作目录从命令行运行脚本。现在只有完成后我才能从 bash 运行它cd到包含脚本的目录。如果我安排cron要执行脚本,默认工作目录是/home/user并且脚本失败。我天真的做法是不管 shell 的当前工作目录如何basedir <- here()应该给出一个可以解析相对路径的文件系统点,但不起作用。

来自 Rstudio,无需事先setwd()

here() starts at /home/user
Error in abs_path(input) : 
The file '/home/user/dataFetcher.Rmd' does not exist.

从 bash 与Rscript如果 cwd 未设置为脚本目录。

$ cd /home/user/scrc
$ Rscript ./myGoodScripts/dataFetcherMailer.R 
here() starts at /home/user/src
Error in abs_path(input) : 
The file '/home/user/src/dataFetcher.Rmd' does not exist.
Calls: <Anonymous> -> setwd -> dirname -> abs_path

如果有人可以帮助我理解并解决这个问题,那就太好了。如果没有另一种可靠的方法来设置基本路径here()存在,我很想知道。最终执行脚本Rstudio比了解如何执行此类脚本要重要得多commandline/cron.

自 JBGruber 回答以来更新:

我稍微修改了该函数,以便它可以返回文件的文件名或目录。我目前正在尝试修改它,以便它可以在以下情况下工作.Rmd文件是由编织而成Rstudio并同样通过 R 文件运行。

here2 <- function(type = 'dir') {
  args <- commandArgs(trailingOnly = FALSE)
  if ("RStudio" %in% args) {
    filepath <- rstudioapi::getActiveDocumentContext()$path
  } else if ("interactive" %in% args) {
    file_arg <- "--file="
    filepath <- sub(file_arg, "", grep(file_arg, args, value = TRUE))
  } else if ("--slave" %in% args) {
    string <- args[6]
    mBtwSquotes <- "(?<=')[^']*[^']*(?=')"
    filepath <- regmatches(string,regexpr(mBtwSquotes,string,perl = T))
  } else if (pmatch("--file=" ,args)) {
    file_arg <- "--file="
    filepath <- sub(file_arg, "", grep(file_arg, args, value = TRUE))
  } else {
    if (type == 'dir') {
      filepath <- '.'
      return(filepath)
    } else {
      filepath <- "error"
      return(filepath)
    }
  }
  if (type == 'dir') {
    filepath <- dirname(filepath)
  }  
  return(filepath)
}

然而我发现commandArgs()继承自 R 脚本,即它们对于.Rmd编织时的文件script.R。因此只有basepath from script.R位置可以通用,而不是文件名。换句话说,这个函数当放置在.Rmd文件将指向调用script.R路径不是.Rmd文件路径。

最终答案(TL;DR)

因此,该函数的较短版本将更加有用:

here2 <- function() {
  args <- commandArgs(trailingOnly = FALSE)
  if ("RStudio" %in% args) {
    # R script called from Rstudio with "source file button"
    filepath <- rstudioapi::getActiveDocumentContext()$path
  } else if ("--slave" %in% args) {
    # Rmd file called from Rstudio with "knit button"  
    # (if we placed this function in a .Rmd file)
    file_arg <- "rmarkdown::render"
    string <- grep(file_arg, args, value = TRUE)
    mBtwQuotes <- "(?<=')[^']*[^']*(?=')"
    filepath <- regmatches(string,regexpr(mBtwQuotes,string,perl = T))
  } else if ((sum(grepl("--file=" ,args))) >0) {
    # called in some other way that passes --file= argument
    # R script called via cron or commandline using Rscript
    file_arg <- "--file="
    filepath <- sub(file_arg, "", grep(file_arg, args, value = TRUE))
  } else if (sum(grepl("rmarkdown::render" ,args)) >0 ) {
    # Rmd file called to render from commandline with 
    # Rscript -e 'rmarkdown::render("RmdFileName")'
    file_arg <- "rmarkdown::render"
    string <- grep(file_arg, args, value = TRUE)
    mBtwQuotes <- "(?<=\")[^\"]*[^\"]*(?=\")"
    filepath <- regmatches(string,regexpr(mBtwQuotes,string,perl = T))
  } else {
    # we do not know what is happening; taking a chance; could have  error later
    filepath <- normalizePath(".")
    return(filepath)
  }
  filepath <- dirname(filepath)
  return(filepath)
}

NB:从内部.Rmdfile 来获取文件的包含目录就足够了normalizePath(".")- 无论你调用哪个都有效.Rmd来自脚本、命令行或 Rstudio 的文件。


你要求什么

的行为here()我想这并不是你真正想要的。相反,您要寻找的是确定源文件的路径,即.R文件。我延长了here()命令一点以按照您期望的方式行事:

here2 <- function() {
  args <- commandArgs(trailingOnly = FALSE)
  if ("RStudio" %in% args) {
    dirname(rstudioapi::getActiveDocumentContext()$path)
  } else {
    file_arg <- "--file="
    filepath <- sub(file_arg, "", grep(file_arg, args, value = TRUE))
    dirname(filepath)
  }
}

当脚本不在 RStudio 中运行时的情况的想法来自这个答案。我通过将函数定义粘贴到您的开头来尝试此操作dataFetcherMailer.R文件。您还可以考虑将其放入主目录中的另一个文件中并使用以下命令调用它:source("here2.R")代替library(here)或者您可以为此目的编写一个小型 R 包。

r0berts 最终版本(op)

here2 <- function() {
  args <- commandArgs(trailingOnly = FALSE)
  if ("RStudio" %in% args) {
    # R script called from Rstudio with "source file button"
    filepath <- rstudioapi::getActiveDocumentContext()$path
  } else if ("--slave" %in% args) {
    # Rmd file called from Rstudio with "knit button"  
    # (if we placed this function in a .Rmd file)
    file_arg <- "rmarkdown::render"
    string <- grep(file_arg, args, value = TRUE)
    mBtwQuotes <- "(?<=')[^']*[^']*(?=')"
    filepath <- regmatches(string,regexpr(mBtwQuotes,string,perl = T))
  } else if ((sum(grepl("--file=" ,args))) >0) {
    # called in some other way that passes --file= argument
    # R script called via cron or commandline using Rscript
    file_arg <- "--file="
    filepath <- sub(file_arg, "", grep(file_arg, args, value = TRUE))
  } else if (sum(grepl("rmarkdown::render" ,args)) >0 ) {
    # Rmd file called to render from commandline with 
    # Rscript -e 'rmarkdown::render("RmdFileName")'
    file_arg <- "rmarkdown::render"
    string <- grep(file_arg, args, value = TRUE)
    mBtwQuotes <- "(?<=\")[^\"]*[^\"]*(?=\")"
    filepath <- regmatches(string,regexpr(mBtwQuotes,string,perl = T))
  } else {
    # we do not know what is happening; taking a chance; could have  error later
    filepath <- normalizePath(".")
    return(filepath)
  }
  filepath <- dirname(filepath)
  return(filepath)
}

我认为大多数人真正需要的

我不久前发现了这种方法,但后来实际上完全改变了我的工作流程,只使用 R Markdown 文件(和 RStudio 项目)。这样做的优点之一是 Rmd 文件的工作目录始终是该文件的位置。因此,您不必费心设置工作目录,只需在脚本中编写相对于 Rmd 文件位置的所有路径即可。

---
title: "Data collection control report"
author: "HAL"
date: "`r Sys.Date()`"
output: pdf_document
---

```{r setup, include=FALSE}
library(knitr)

# in actual program this reads data from a changing online data source
df.main <- mtcars

# data backup
datestamp <- format(Sys.time(),format="%Y-%m-%d_%H-%M")

# create bkp folder if it doesn't exist
if (!dir.exists(paste0("./bkp/"))) dir.create("./bkp/")

backupName <- paste0("./bkp/dataBackup_", datestamp, "csv.gz")
write.csv(df.main, gzfile(backupName))
```

# This is data collection report

Yesterday's data total records: `r nrow(df.main)`. 

The current directory is `r getwd()`

请注意,路径以./意思是在Rmd文件的文件夹中启动。../意味着你上升了一级。../../你上升两级,依此类推。因此,如果您的 Rmd 文件位于根文件夹中名为“scripts”的文件夹中,并且您希望将数据保存在根文件夹中名为“data”的文件夹中,则可以编写saveRDS(data, "../data/dat.RDS").

您可以从命令行/cron 运行 Rmd 文件Rscript -e 'rmarkdown::render("/home/johannes/Desktop/myGoodScripts/dataFetcher.Rmd")'.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

R 脚本中的 here() 问题 的相关文章

  • 为什么在 data.frame 中预先指定类型会比较慢?

    我预先分配了一个大 data frame 以便稍后填写 我通常这样做NA是这样的 n lt 1e6 a lt data frame c1 1 n c2 NA c3 NA 我想知道如果我预先指定数据类型是否会让事情变得更快 所以我测试了 f1
  • 如何从R中串扰的filter_select中删除(全部)?

    我遵循图 16 7 的示例https plotly r com client side linking html https plotly r com client side linking html并且无法弄清楚为什么有一个名为 全部 的
  • r:按多列分组并计数

    我有以下数据框 df LeftOrRight SpeedCategory NumThruLanes R 25to45 3 L 45to62 2 R Gt62 1 我想按速度类别对其进行分组 并循环遍历其他列以获取每个速度类别中每个唯一代码的
  • 在 R 中安全地计算算术表达式?

    Edit 好吧 由于似乎有很多混乱 我将稍微简化一下问题 您可以尝试回答下面的原始问题 或者您可以解决此版本并忽略该行下面的所有内容 我的目标是采用任意表达式并在极其受限的环境中对其进行评估 该环境将仅包含具有以下类型值的变量 数值向量 接
  • 配置 fix() 和 edit() 以从 R/RStudio 在 Notepad++ 中打开

    当我在 RStudio 或 RGUI 中执行此操作时 fix SomeFunction 或使用edit 我可以在记事本中看到该函数的代码 有什么方法可以更改此设置 以便代码预览在 Notepad 中打开 而不是在普通的旧记事本中打开 同样
  • 如何使用 ggplot2 对曲线下的区域进行着色

    我一直在尝试使用 ggplot2 生成类似于此 R 图形的绘图 xv lt seq 0 4 0 01 yv lt dnorm xv 2 0 5 plot xv yv type l polygon c xv xv lt 1 5 1 5 c y
  • 使用 roxygen2 导入两个同名函数

    我是 CRAN 包的维护者 在加载时收到以下消息 checking whether package qdap can be installed 10s 10s WARNING Found the following significant
  • R正则表达式获取第二个下划线之前的所有文本

    s lt 1 343 43Hello 2 323 14 fdh 99H 在 R 中 我想使用正则表达式来获取第二个下划线之前的子字符串 如何使用一个正则表达式来完成此操作 另一种方法是用 分割 然后粘贴前两个 一些东西 paste sapp
  • 使用神经网络包进行多项分类

    这个问题应该很简单 但文档没有帮助 我正在使用 R 我必须使用neuralnet多项式分类问题的包 所有示例均针对二项式或线性输出 我可以使用二项式输出进行一些一对一的实现 但我相信我应该能够通过使用 3 个单元作为输出层来做到这一点 其中
  • RMySQL fetch - 找不到继承的方法

    使用 RMySQL 我想将数据从数据库加载到 R 中的数据帧中 为此 我使用以下代码 R连接数据库 con lt dbConnect MySQL user root password password dbname prediction h
  • 如何将数据从长格式重塑为宽格式

    我在重新排列以下数据框时遇到问题 set seed 45 dat1 lt data frame name rep c firstName secondName each 4 numbers rep 1 4 2 value rnorm 8 d
  • 使用 R 下载压缩数据文件、提取并导入 .csv

    我正在尝试使用以下方法从网页下载并提取 csv 文件R 这个问题是重复的使用 R 下载压缩数据文件 提取和导入数据 https stackoverflow com questions 3053833 using r to download
  • R 中具有 p 值的相关矩阵

    假设我想要传导相关矩阵 library dplyr data iris iris gt select if is numeric gt cor y iris Petal Width method spearman gt round 2 现在
  • 使用 R Markdown 文档作为函数源

    我正在研究 R Markdown 来记录我经常使用的功能 我会将它们放入 R Markdown 文件中以记录它们 然后如果我几个月后回来查看它 就能够阅读我在函数背后的想法 我的问题是 如果我开始一个新的 R 项目 是否可以获取 r mar
  • 来自大型数据帧的共现

    我有一个数据框 其中包含有关每个用户访问过哪些城市的信息 df visited lt data frame user c john john claire claire doe doe city c Antananarivo Barcelo
  • 连接树状图和热图

    我有一个heatmap 一组样本的基因表达 set seed 10 mat lt matrix rnorm 24 10 mean 1 sd 2 nrow 24 ncol 10 dimnames list paste g 1 24 sep p
  • R中具有特定条件的多列变异

    我有这个数据 M1 M2 M3 UCL 1 2 3 1 5 我想在这种情况下创建新列 如果M1大于UCL MM1将为 UP 否则为 NULL 如果M2大于UCL MM2将为 UP 否则为 NULL 如果M3大于UCL MM3将为 UP 否则
  • 如果值大于或小于,则替换数据框中的值

    我在 R 中操作数据帧时遇到问题 这是 R 中的基本内容 但我找不到执行此类操作的最佳命令 虚拟示例 Var1 20 300 39 Var2 49 23 91 Var3 0 239 210 我怎样才能用10如果值小于 则在第 2 列中10
  • R ggplot2 分面保持比率但覆盖/定义输出图大小

    我目前正在使用 ggplot2 来比较不同组的统计数据 每个组属于不同的区域 这是通过运行 R 脚本的 Web 应用程序 tikiwiki CMS 插件 R 完成的 每个区域我可以有 2 到 30 个或更多组 相同的 R 脚本针对唯一网页中
  • ggplot2 + 使用比例 X 的日期结构

    我真的需要帮助 因为我已经迷路了 我正在尝试创建一个折线图 显示几个团队一年来的表现 我将一年分为几个季度 2012 年 1 月 1 日 2012 年 4 月 1 日 2012 年 8 月 1 日 12 1 12 并将 csv 数据帧加载到

随机推荐